Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

667 lines
23KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE 6 technical preview.
  4. Copyright (c) 2020 - Raw Material Software Limited
  5. You may use this code under the terms of the GPL v3
  6. (see www.gnu.org/licenses).
  7. For this technical preview, this file is not subject to commercial licensing.
  8. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  9. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  10. DISCLAIMED.
  11. ==============================================================================
  12. */
  13. namespace juce
  14. {
  15. #if (defined (MAC_OS_X_VERSION_10_11) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11) \
  16. || (defined (__IPHONE_8_0) && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_8_0)
  17. #define JUCE_USE_WKWEBVIEW 1
  18. #if (defined (MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12)
  19. #define WKWEBVIEW_OPENPANEL_SUPPORTED 1
  20. #endif
  21. #endif
  22. NSMutableURLRequest* getRequestForURL (const String& url, const StringArray* headers, const MemoryBlock* postData)
  23. {
  24. NSString* urlString = juceStringToNS (url);
  25. #if (JUCE_MAC && (defined (MAC_OS_X_VERSION_10_9) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9)) \
  26. || (JUCE_IOS && (defined (__IPHONE_7_0) && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_7_0))
  27. urlString = [urlString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
  28. #else
  29. urlString = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
  30. #endif
  31. if (NSURL* nsURL = [NSURL URLWithString: urlString])
  32. {
  33. NSMutableURLRequest* r
  34. = [NSMutableURLRequest requestWithURL: nsURL
  35. cachePolicy: NSURLRequestUseProtocolCachePolicy
  36. timeoutInterval: 30.0];
  37. if (postData != nullptr && postData->getSize() > 0)
  38. {
  39. [r setHTTPMethod: nsStringLiteral ("POST")];
  40. [r setHTTPBody: [NSData dataWithBytes: postData->getData()
  41. length: postData->getSize()]];
  42. }
  43. if (headers != nullptr)
  44. {
  45. for (int i = 0; i < headers->size(); ++i)
  46. {
  47. auto headerName = (*headers)[i].upToFirstOccurrenceOf (":", false, false).trim();
  48. auto headerValue = (*headers)[i].fromFirstOccurrenceOf (":", false, false).trim();
  49. [r setValue: juceStringToNS (headerValue)
  50. forHTTPHeaderField: juceStringToNS (headerName)];
  51. }
  52. }
  53. return r;
  54. }
  55. return nullptr;
  56. }
  57. #if JUCE_USE_WKWEBVIEW
  58. struct WebViewDelegateClass : public ObjCClass<NSObject>
  59. {
  60. WebViewDelegateClass() : ObjCClass<NSObject> ("JUCEWebViewDelegate_")
  61. {
  62. addIvar<WebBrowserComponent*> ("owner");
  63. addMethod (@selector (webView:decidePolicyForNavigationAction:decisionHandler:), decidePolicyForNavigationAction, "v@:@@@");
  64. addMethod (@selector (webView:didFinishNavigation:), didFinishNavigation, "v@:@@");
  65. addMethod (@selector (webView:didFailNavigation:withError:), didFailNavigation, "v@:@@@");
  66. addMethod (@selector (webView:didFailProvisionalNavigation:withError:), didFailProvisionalNavigation, "v@:@@@");
  67. addMethod (@selector (webView:webViewDidClose:), webViewDidClose, "v@:@");
  68. addMethod (@selector (webView:createWebViewWithConfiguration:forNavigationAction:
  69. windowFeatures:), createWebView, "@@:@@@@");
  70. #if WKWEBVIEW_OPENPANEL_SUPPORTED
  71. addMethod (@selector (webView:runOpenPanelWithParameters:
  72. initiatedByFrame:completionHandler:), runOpenPanel, "v@:@@@@");
  73. #endif
  74. registerClass();
  75. }
  76. static void setOwner (id self, WebBrowserComponent* owner) { object_setInstanceVariable (self, "owner", owner); }
  77. static WebBrowserComponent* getOwner (id self) { return getIvar<WebBrowserComponent*> (self, "owner"); }
  78. private:
  79. static void decidePolicyForNavigationAction (id self, SEL, WKWebView*, WKNavigationAction* navigationAction,
  80. void (^decisionHandler)(WKNavigationActionPolicy))
  81. {
  82. if (getOwner (self)->pageAboutToLoad (nsStringToJuce ([[[navigationAction request] URL] absoluteString])))
  83. decisionHandler (WKNavigationActionPolicyAllow);
  84. else
  85. decisionHandler (WKNavigationActionPolicyCancel);
  86. }
  87. static void didFinishNavigation (id self, SEL, WKWebView* webview, WKNavigation*)
  88. {
  89. getOwner (self)->pageFinishedLoading (nsStringToJuce ([[webview URL] absoluteString]));
  90. }
  91. static void displayError (WebBrowserComponent* owner, NSError* error)
  92. {
  93. if ([error code] != NSURLErrorCancelled)
  94. {
  95. auto errorString = nsStringToJuce ([error localizedDescription]);
  96. bool proceedToErrorPage = owner->pageLoadHadNetworkError (errorString);
  97. // WKWebView doesn't have an internal error page, so make a really simple one ourselves
  98. if (proceedToErrorPage)
  99. owner->goToURL ("data:text/plain;charset=UTF-8," + errorString);
  100. }
  101. }
  102. static void didFailNavigation (id self, SEL, WKWebView*, WKNavigation*, NSError* error)
  103. {
  104. displayError (getOwner (self), error);
  105. }
  106. static void didFailProvisionalNavigation (id self, SEL, WKWebView*, WKNavigation*, NSError* error)
  107. {
  108. displayError (getOwner (self), error);
  109. }
  110. static void webViewDidClose (id self, SEL, WKWebView*)
  111. {
  112. getOwner (self)->windowCloseRequest();
  113. }
  114. static WKWebView* createWebView (id self, SEL, WKWebView*, WKWebViewConfiguration*,
  115. WKNavigationAction* navigationAction, WKWindowFeatures*)
  116. {
  117. getOwner (self)->newWindowAttemptingToLoad (nsStringToJuce ([[[navigationAction request] URL] absoluteString]));
  118. return nil;
  119. }
  120. #if WKWEBVIEW_OPENPANEL_SUPPORTED
  121. static void runOpenPanel (id, SEL, WKWebView*, WKOpenPanelParameters* parameters, WKFrameInfo*,
  122. void (^completionHandler)(NSArray<NSURL*>*))
  123. {
  124. #if JUCE_MODAL_LOOPS_PERMITTED
  125. FileChooser chooser (TRANS("Select the file you want to upload..."),
  126. File::getSpecialLocation (File::userHomeDirectory), "*");
  127. auto flags = FileBrowserComponent::openMode | FileBrowserComponent::canSelectFiles
  128. | ([parameters allowsMultipleSelection] ? FileBrowserComponent::canSelectMultipleItems : 0);
  129. #if (defined (MAC_OS_X_VERSION_10_14) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_14)
  130. if ([parameters allowsDirectories])
  131. flags |= FileBrowserComponent::canSelectDirectories;
  132. #endif
  133. if (chooser.showDialog (flags, nullptr))
  134. {
  135. auto results = chooser.getResults();
  136. auto urls = [NSMutableArray arrayWithCapacity: (NSUInteger) results.size()];
  137. for (auto& f : results)
  138. [urls addObject: [NSURL fileURLWithPath: juceStringToNS (f.getFullPathName())]];
  139. completionHandler (urls);
  140. }
  141. else
  142. {
  143. completionHandler (nil);
  144. }
  145. #else
  146. ignoreUnused (parameters, completionHandler);
  147. jassertfalse; // Can't use this without modal loops being enabled!
  148. #endif
  149. }
  150. #endif
  151. };
  152. //==============================================================================
  153. class WebBrowserComponent::Pimpl
  154. #if JUCE_MAC
  155. : public NSViewComponent
  156. #else
  157. : public UIViewComponent
  158. #endif
  159. {
  160. public:
  161. Pimpl (WebBrowserComponent* owner)
  162. {
  163. ignoreUnused (owner);
  164. WKWebViewConfiguration* config = [[WKWebViewConfiguration alloc] init];
  165. #if JUCE_MAC
  166. auto frame = NSMakeRect (0, 0, 100.0f, 100.0f);
  167. #else
  168. auto frame = CGRectMake (0, 0, 100.0f, 100.0f);
  169. #endif
  170. webView = [[WKWebView alloc] initWithFrame: frame
  171. configuration: config];
  172. static WebViewDelegateClass cls;
  173. webViewDelegate = [cls.createInstance() init];
  174. WebViewDelegateClass::setOwner (webViewDelegate, owner);
  175. [webView setNavigationDelegate: webViewDelegate];
  176. [webView setUIDelegate: webViewDelegate];
  177. setView (webView);
  178. }
  179. ~Pimpl()
  180. {
  181. [webView setNavigationDelegate: nil];
  182. [webView setUIDelegate: nil];
  183. [webViewDelegate release];
  184. setView (nil);
  185. }
  186. void goToURL (const String& url,
  187. const StringArray* headers,
  188. const MemoryBlock* postData)
  189. {
  190. stop();
  191. if (url.trimStart().startsWithIgnoreCase ("javascript:"))
  192. {
  193. [webView evaluateJavaScript: juceStringToNS (url.fromFirstOccurrenceOf (":", false, false))
  194. completionHandler: nil];
  195. }
  196. else if (NSMutableURLRequest* request = getRequestForURL (url, headers, postData))
  197. {
  198. [webView loadRequest: request];
  199. }
  200. }
  201. void goBack() { [webView goBack]; }
  202. void goForward() { [webView goForward]; }
  203. void stop() { [webView stopLoading]; }
  204. void refresh() { [webView reload]; }
  205. private:
  206. WKWebView* webView = nil;
  207. id webViewDelegate;
  208. };
  209. #else
  210. #if JUCE_MAC
  211. struct WebViewKeyEquivalentResponder : public ObjCClass<WebView>
  212. {
  213. WebViewKeyEquivalentResponder() : ObjCClass<WebView> ("WebViewKeyEquivalentResponder_")
  214. {
  215. addMethod (@selector (performKeyEquivalent:), performKeyEquivalent, @encode (BOOL), "@:@");
  216. registerClass();
  217. }
  218. private:
  219. static BOOL performKeyEquivalent (id self, SEL selector, NSEvent* event)
  220. {
  221. NSResponder* first = [[self window] firstResponder];
  222. if (([event modifierFlags] & NSDeviceIndependentModifierFlagsMask) == NSCommandKeyMask)
  223. {
  224. if ([[event charactersIgnoringModifiers] isEqualToString:@"x"]) return [NSApp sendAction:@selector(cut:) to:first from:self];
  225. if ([[event charactersIgnoringModifiers] isEqualToString:@"c"]) return [NSApp sendAction:@selector(copy:) to:first from:self];
  226. if ([[event charactersIgnoringModifiers] isEqualToString:@"v"]) return [NSApp sendAction:@selector(paste:) to:first from:self];
  227. if ([[event charactersIgnoringModifiers] isEqualToString:@"a"]) return [NSApp sendAction:@selector(selectAll:) to:first from:self];
  228. }
  229. objc_super s = { self, [WebView class] };
  230. return ObjCMsgSendSuper<BOOL, NSEvent*> (&s, selector, event);
  231. }
  232. };
  233. struct DownloadClickDetectorClass : public ObjCClass<NSObject>
  234. {
  235. DownloadClickDetectorClass() : ObjCClass<NSObject> ("JUCEWebClickDetector_")
  236. {
  237. addIvar<WebBrowserComponent*> ("owner");
  238. addMethod (@selector (webView:decidePolicyForNavigationAction:request:frame:decisionListener:),
  239. decidePolicyForNavigationAction, "v@:@@@@@");
  240. addMethod (@selector (webView:decidePolicyForNewWindowAction:request:newFrameName:decisionListener:),
  241. decidePolicyForNewWindowAction, "v@:@@@@@");
  242. addMethod (@selector (webView:didFinishLoadForFrame:), didFinishLoadForFrame, "v@:@@");
  243. addMethod (@selector (webView:didFailLoadWithError:forFrame:), didFailLoadWithError, "v@:@@@");
  244. addMethod (@selector (webView:didFailProvisionalLoadWithError:forFrame:), didFailLoadWithError, "v@:@@@");
  245. addMethod (@selector (webView:willCloseFrame:), willCloseFrame, "v@:@@");
  246. addMethod (@selector (webView:runOpenPanelForFileButtonWithResultListener:allowMultipleFiles:), runOpenPanel, "v@:@@", @encode (BOOL));
  247. registerClass();
  248. }
  249. static void setOwner (id self, WebBrowserComponent* owner) { object_setInstanceVariable (self, "owner", owner); }
  250. static WebBrowserComponent* getOwner (id self) { return getIvar<WebBrowserComponent*> (self, "owner"); }
  251. private:
  252. static String getOriginalURL (NSDictionary* actionInformation)
  253. {
  254. if (NSURL* url = [actionInformation valueForKey: nsStringLiteral ("WebActionOriginalURLKey")])
  255. return nsStringToJuce ([url absoluteString]);
  256. return {};
  257. }
  258. static void decidePolicyForNavigationAction (id self, SEL, WebView*, NSDictionary* actionInformation,
  259. NSURLRequest*, WebFrame*, id<WebPolicyDecisionListener> listener)
  260. {
  261. if (getOwner (self)->pageAboutToLoad (getOriginalURL (actionInformation)))
  262. [listener use];
  263. else
  264. [listener ignore];
  265. }
  266. static void decidePolicyForNewWindowAction (id self, SEL, WebView*, NSDictionary* actionInformation,
  267. NSURLRequest*, NSString*, id<WebPolicyDecisionListener> listener)
  268. {
  269. getOwner (self)->newWindowAttemptingToLoad (getOriginalURL (actionInformation));
  270. [listener ignore];
  271. }
  272. static void didFinishLoadForFrame (id self, SEL, WebView* sender, WebFrame* frame)
  273. {
  274. if ([frame isEqual: [sender mainFrame]])
  275. {
  276. NSURL* url = [[[frame dataSource] request] URL];
  277. getOwner (self)->pageFinishedLoading (nsStringToJuce ([url absoluteString]));
  278. }
  279. }
  280. static void didFailLoadWithError (id self, SEL, WebView* sender, NSError* error, WebFrame* frame)
  281. {
  282. if ([frame isEqual: [sender mainFrame]] && error != nullptr && [error code] != NSURLErrorCancelled)
  283. {
  284. auto errorString = nsStringToJuce ([error localizedDescription]);
  285. bool proceedToErrorPage = getOwner (self)->pageLoadHadNetworkError (errorString);
  286. // WebKit doesn't have an internal error page, so make a really simple one ourselves
  287. if (proceedToErrorPage)
  288. getOwner (self)->goToURL ("data:text/plain;charset=UTF-8," + errorString);
  289. }
  290. }
  291. static void willCloseFrame (id self, SEL, WebView*, WebFrame*)
  292. {
  293. getOwner (self)->windowCloseRequest();
  294. }
  295. static void runOpenPanel (id, SEL, WebView*, id<WebOpenPanelResultListener> resultListener, BOOL allowMultipleFiles)
  296. {
  297. #if JUCE_MODAL_LOOPS_PERMITTED
  298. FileChooser chooser (TRANS("Select the file you want to upload..."),
  299. File::getSpecialLocation (File::userHomeDirectory), "*");
  300. if (allowMultipleFiles ? chooser.browseForMultipleFilesToOpen()
  301. : chooser.browseForFileToOpen())
  302. {
  303. for (auto& f : chooser.getResults())
  304. [resultListener chooseFilename: juceStringToNS (f.getFullPathName())];
  305. }
  306. #else
  307. ignoreUnused (resultListener, allowMultipleFiles);
  308. jassertfalse; // Can't use this without modal loops being enabled!
  309. #endif
  310. }
  311. };
  312. #else
  313. struct WebViewDelegateClass : public ObjCClass<NSObject>
  314. {
  315. WebViewDelegateClass() : ObjCClass<NSObject> ("JUCEWebViewDelegate_")
  316. {
  317. addIvar<WebBrowserComponent*> ("owner");
  318. addMethod (@selector (gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:),
  319. shouldRecognizeSimultaneouslyWithGestureRecognizer, "c@:@@");
  320. addMethod (@selector (webView:shouldStartLoadWithRequest:navigationType:), shouldStartLoadWithRequest, "c@:@@@");
  321. addMethod (@selector (webViewDidFinishLoad:), webViewDidFinishLoad, "v@:@");
  322. registerClass();
  323. }
  324. static void setOwner (id self, WebBrowserComponent* owner) { object_setInstanceVariable (self, "owner", owner); }
  325. static WebBrowserComponent* getOwner (id self) { return getIvar<WebBrowserComponent*> (self, "owner"); }
  326. private:
  327. static BOOL shouldRecognizeSimultaneouslyWithGestureRecognizer (id, SEL, UIGestureRecognizer*, UIGestureRecognizer*)
  328. {
  329. return YES;
  330. }
  331. static BOOL shouldStartLoadWithRequest (id self, SEL, UIWebView*, NSURLRequest* request, UIWebViewNavigationType)
  332. {
  333. return getOwner (self)->pageAboutToLoad (nsStringToJuce ([[request URL] absoluteString]));
  334. }
  335. static void webViewDidFinishLoad (id self, SEL, UIWebView* webView)
  336. {
  337. getOwner (self)->pageFinishedLoading (nsStringToJuce ([[[webView request] URL] absoluteString]));
  338. }
  339. };
  340. #endif
  341. //==============================================================================
  342. class WebBrowserComponent::Pimpl
  343. #if JUCE_MAC
  344. : public NSViewComponent
  345. #else
  346. : public UIViewComponent
  347. #endif
  348. {
  349. public:
  350. Pimpl (WebBrowserComponent* owner)
  351. {
  352. #if JUCE_MAC
  353. static WebViewKeyEquivalentResponder webviewClass;
  354. webView = (WebView*) webviewClass.createInstance();
  355. webView = [webView initWithFrame: NSMakeRect (0, 0, 100.0f, 100.0f)
  356. frameName: nsEmptyString()
  357. groupName: nsEmptyString()];
  358. static DownloadClickDetectorClass cls;
  359. clickListener = [cls.createInstance() init];
  360. DownloadClickDetectorClass::setOwner (clickListener, owner);
  361. [webView setPolicyDelegate: clickListener];
  362. [webView setFrameLoadDelegate: clickListener];
  363. [webView setUIDelegate: clickListener];
  364. #else
  365. webView = [[UIWebView alloc] initWithFrame: CGRectMake (0, 0, 1.0f, 1.0f)];
  366. static WebViewDelegateClass cls;
  367. webViewDelegate = [cls.createInstance() init];
  368. WebViewDelegateClass::setOwner (webViewDelegate, owner);
  369. [webView setDelegate: webViewDelegate];
  370. #endif
  371. setView (webView);
  372. }
  373. ~Pimpl()
  374. {
  375. #if JUCE_MAC
  376. [webView setPolicyDelegate: nil];
  377. [webView setFrameLoadDelegate: nil];
  378. [webView setUIDelegate: nil];
  379. [clickListener release];
  380. #else
  381. [webView setDelegate: nil];
  382. [webViewDelegate release];
  383. #endif
  384. setView (nil);
  385. }
  386. void goToURL (const String& url,
  387. const StringArray* headers,
  388. const MemoryBlock* postData)
  389. {
  390. stop();
  391. if (url.trimStart().startsWithIgnoreCase ("javascript:"))
  392. {
  393. [webView stringByEvaluatingJavaScriptFromString:
  394. juceStringToNS (url.fromFirstOccurrenceOf (":", false, false))];
  395. }
  396. else if (NSMutableURLRequest* request = getRequestForURL (url, headers, postData))
  397. {
  398. #if JUCE_MAC
  399. [[webView mainFrame] loadRequest: request];
  400. #else
  401. [webView loadRequest: request];
  402. #endif
  403. #if JUCE_IOS
  404. [webView setScalesPageToFit: YES];
  405. #endif
  406. }
  407. }
  408. void goBack() { [webView goBack]; }
  409. void goForward() { [webView goForward]; }
  410. #if JUCE_MAC
  411. void stop() { [webView stopLoading: nil]; }
  412. void refresh() { [webView reload: nil]; }
  413. #else
  414. void stop() { [webView stopLoading]; }
  415. void refresh() { [webView reload]; }
  416. #endif
  417. void mouseMove (const MouseEvent&)
  418. {
  419. // WebKit doesn't capture mouse-moves itself, so it seems the only way to make
  420. // them work is to push them via this non-public method..
  421. if ([webView respondsToSelector: @selector (_updateMouseoverWithFakeEvent)])
  422. [webView performSelector: @selector (_updateMouseoverWithFakeEvent)];
  423. }
  424. private:
  425. #if JUCE_MAC
  426. WebView* webView = nil;
  427. id clickListener;
  428. #else
  429. UIWebView* webView = nil;
  430. id webViewDelegate;
  431. #endif
  432. };
  433. #endif
  434. //==============================================================================
  435. WebBrowserComponent::WebBrowserComponent (bool unloadWhenHidden)
  436. : unloadPageWhenBrowserIsHidden (unloadWhenHidden)
  437. {
  438. setOpaque (true);
  439. browser.reset (new Pimpl (this));
  440. addAndMakeVisible (browser.get());
  441. }
  442. WebBrowserComponent::~WebBrowserComponent()
  443. {
  444. }
  445. //==============================================================================
  446. void WebBrowserComponent::goToURL (const String& url,
  447. const StringArray* headers,
  448. const MemoryBlock* postData)
  449. {
  450. lastURL = url;
  451. if (headers != nullptr)
  452. lastHeaders = *headers;
  453. else
  454. lastHeaders.clear();
  455. if (postData != nullptr)
  456. lastPostData = *postData;
  457. else
  458. lastPostData.reset();
  459. blankPageShown = false;
  460. browser->goToURL (url, headers, postData);
  461. }
  462. void WebBrowserComponent::stop()
  463. {
  464. browser->stop();
  465. }
  466. void WebBrowserComponent::goBack()
  467. {
  468. lastURL.clear();
  469. blankPageShown = false;
  470. browser->goBack();
  471. }
  472. void WebBrowserComponent::goForward()
  473. {
  474. lastURL.clear();
  475. browser->goForward();
  476. }
  477. void WebBrowserComponent::refresh()
  478. {
  479. browser->refresh();
  480. }
  481. //==============================================================================
  482. void WebBrowserComponent::paint (Graphics&)
  483. {
  484. }
  485. void WebBrowserComponent::checkWindowAssociation()
  486. {
  487. if (isShowing())
  488. {
  489. reloadLastURL();
  490. if (blankPageShown)
  491. goBack();
  492. }
  493. else
  494. {
  495. if (unloadPageWhenBrowserIsHidden && ! blankPageShown)
  496. {
  497. // when the component becomes invisible, some stuff like flash
  498. // carries on playing audio, so we need to force it onto a blank
  499. // page to avoid this, (and send it back when it's made visible again).
  500. blankPageShown = true;
  501. browser->goToURL ("about:blank", nullptr, nullptr);
  502. }
  503. }
  504. }
  505. void WebBrowserComponent::reloadLastURL()
  506. {
  507. if (lastURL.isNotEmpty())
  508. {
  509. goToURL (lastURL, &lastHeaders, &lastPostData);
  510. lastURL.clear();
  511. }
  512. }
  513. void WebBrowserComponent::parentHierarchyChanged()
  514. {
  515. checkWindowAssociation();
  516. }
  517. void WebBrowserComponent::resized()
  518. {
  519. browser->setSize (getWidth(), getHeight());
  520. }
  521. void WebBrowserComponent::visibilityChanged()
  522. {
  523. checkWindowAssociation();
  524. }
  525. void WebBrowserComponent::focusGained (FocusChangeType)
  526. {
  527. }
  528. void WebBrowserComponent::clearCookies()
  529. {
  530. NSHTTPCookieStorage* storage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
  531. if (NSArray* cookies = [storage cookies])
  532. {
  533. const NSUInteger n = [cookies count];
  534. for (NSUInteger i = 0; i < n; ++i)
  535. [storage deleteCookie: [cookies objectAtIndex: i]];
  536. }
  537. [[NSUserDefaults standardUserDefaults] synchronize];
  538. }
  539. } // namespace juce