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.

681 lines
24KB

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