WebChromeClient.mm 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952
  1. /*
  2. * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
  3. * Copyright (C) 2008, 2010 Nokia Corporation and/or its subsidiary(-ies)
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. *
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
  15. * its contributors may be used to endorse or promote products derived
  16. * from this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
  19. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  20. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  21. * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
  22. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  23. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  24. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  25. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  27. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. */
  29. #import "WebChromeClient.h"
  30. #import "DOMElementInternal.h"
  31. #import "DOMNodeInternal.h"
  32. #import "PopupMenuMac.h"
  33. #import "SearchPopupMenuMac.h"
  34. #import "WebBasePluginPackage.h"
  35. #import "WebDefaultUIDelegate.h"
  36. #import "WebDelegateImplementationCaching.h"
  37. #import "WebElementDictionary.h"
  38. #import "WebFrameInternal.h"
  39. #import "WebFrameView.h"
  40. #import "WebHTMLViewInternal.h"
  41. #import "WebHistoryInternal.h"
  42. #import "WebKitFullScreenListener.h"
  43. #import "WebKitPrefix.h"
  44. #import "WebKitSystemInterface.h"
  45. #import "WebNSURLRequestExtras.h"
  46. #import "WebOpenPanelResultListener.h"
  47. #import "WebPlugin.h"
  48. #import "WebQuotaManager.h"
  49. #import "WebSecurityOriginInternal.h"
  50. #import "WebUIDelegatePrivate.h"
  51. #import "WebView.h"
  52. #import "WebViewInternal.h"
  53. #import <Foundation/Foundation.h>
  54. #import <WebCore/BlockExceptions.h>
  55. #import <WebCore/Console.h>
  56. #import <WebCore/ContextMenu.h>
  57. #import <WebCore/ContextMenuController.h>
  58. #import <WebCore/Cursor.h>
  59. #import <WebCore/Element.h>
  60. #import <WebCore/FileChooser.h>
  61. #import <WebCore/FileIconLoader.h>
  62. #import <WebCore/FloatRect.h>
  63. #import <WebCore/Frame.h>
  64. #import <WebCore/FrameLoadRequest.h>
  65. #import <WebCore/FrameView.h>
  66. #import <WebCore/HTMLInputElement.h>
  67. #import <WebCore/HTMLNames.h>
  68. #import <WebCore/HTMLPlugInImageElement.h>
  69. #import <WebCore/HitTestResult.h>
  70. #import <WebCore/Icon.h>
  71. #import <WebCore/IntPoint.h>
  72. #import <WebCore/IntRect.h>
  73. #import <WebCore/NavigationAction.h>
  74. #import <WebCore/NotImplemented.h>
  75. #import <WebCore/Page.h>
  76. #import <WebCore/PlatformScreen.h>
  77. #import <WebCore/ResourceRequest.h>
  78. #import <WebCore/Widget.h>
  79. #import <WebCore/WindowFeatures.h>
  80. #import <wtf/PassRefPtr.h>
  81. #import <wtf/Vector.h>
  82. #import <wtf/text/WTFString.h>
  83. #if USE(ACCELERATED_COMPOSITING)
  84. #import <WebCore/GraphicsLayer.h>
  85. #endif
  86. #if USE(PLUGIN_HOST_PROCESS) && ENABLE(NETSCAPE_PLUGIN_API)
  87. #import "NetscapePluginHostManager.h"
  88. #endif
  89. NSString *WebConsoleMessageXMLMessageSource = @"XMLMessageSource";
  90. NSString *WebConsoleMessageJSMessageSource = @"JSMessageSource";
  91. NSString *WebConsoleMessageNetworkMessageSource = @"NetworkMessageSource";
  92. NSString *WebConsoleMessageConsoleAPIMessageSource = @"ConsoleAPIMessageSource";
  93. NSString *WebConsoleMessageStorageMessageSource = @"StorageMessageSource";
  94. NSString *WebConsoleMessageAppCacheMessageSource = @"AppCacheMessageSource";
  95. NSString *WebConsoleMessageRenderingMessageSource = @"RenderingMessageSource";
  96. NSString *WebConsoleMessageCSSMessageSource = @"CSSMessageSource";
  97. NSString *WebConsoleMessageSecurityMessageSource = @"SecurityMessageSource";
  98. NSString *WebConsoleMessageOtherMessageSource = @"OtherMessageSource";
  99. NSString *WebConsoleMessageDebugMessageLevel = @"DebugMessageLevel";
  100. NSString *WebConsoleMessageLogMessageLevel = @"LogMessageLevel";
  101. NSString *WebConsoleMessageWarningMessageLevel = @"WarningMessageLevel";
  102. NSString *WebConsoleMessageErrorMessageLevel = @"ErrorMessageLevel";
  103. @interface NSApplication (WebNSApplicationDetails)
  104. - (NSCursor *)_cursorRectCursor;
  105. @end
  106. @interface NSView (WebNSViewDetails)
  107. - (NSView *)_findLastViewInKeyViewLoop;
  108. @end
  109. // For compatibility with old SPI.
  110. @interface NSView (WebOldWebKitPlugInDetails)
  111. - (void)setIsSelected:(BOOL)isSelected;
  112. @end
  113. @interface NSWindow (AppKitSecretsIKnowAbout)
  114. - (NSRect)_growBoxRect;
  115. @end
  116. using namespace WebCore;
  117. using namespace HTMLNames;
  118. WebChromeClient::WebChromeClient(WebView *webView)
  119. : m_webView(webView)
  120. {
  121. }
  122. void WebChromeClient::chromeDestroyed()
  123. {
  124. delete this;
  125. }
  126. // These functions scale between window and WebView coordinates because JavaScript/DOM operations
  127. // assume that the WebView and the window share the same coordinate system.
  128. void WebChromeClient::setWindowRect(const FloatRect& rect)
  129. {
  130. NSRect windowRect = toDeviceSpace(rect, [m_webView window]);
  131. [[m_webView _UIDelegateForwarder] webView:m_webView setFrame:windowRect];
  132. }
  133. FloatRect WebChromeClient::windowRect()
  134. {
  135. NSRect windowRect = [[m_webView _UIDelegateForwarder] webViewFrame:m_webView];
  136. return toUserSpace(windowRect, [m_webView window]);
  137. }
  138. // FIXME: We need to add API for setting and getting this.
  139. FloatRect WebChromeClient::pageRect()
  140. {
  141. return [m_webView frame];
  142. }
  143. void WebChromeClient::focus()
  144. {
  145. [[m_webView _UIDelegateForwarder] webViewFocus:m_webView];
  146. }
  147. void WebChromeClient::unfocus()
  148. {
  149. [[m_webView _UIDelegateForwarder] webViewUnfocus:m_webView];
  150. }
  151. bool WebChromeClient::canTakeFocus(FocusDirection)
  152. {
  153. // There's unfortunately no way to determine if we will become first responder again
  154. // once we give it up, so we just have to guess that we won't.
  155. return true;
  156. }
  157. void WebChromeClient::takeFocus(FocusDirection direction)
  158. {
  159. if (direction == FocusDirectionForward) {
  160. // Since we're trying to move focus out of m_webView, and because
  161. // m_webView may contain subviews within it, we ask it for the next key
  162. // view of the last view in its key view loop. This makes m_webView
  163. // behave as if it had no subviews, which is the behavior we want.
  164. NSView *lastView = [m_webView _findLastViewInKeyViewLoop];
  165. // avoid triggering assertions if the WebView is the only thing in the key loop
  166. if ([m_webView _becomingFirstResponderFromOutside] && m_webView == [lastView nextValidKeyView])
  167. return;
  168. [[m_webView window] selectKeyViewFollowingView:lastView];
  169. } else {
  170. // avoid triggering assertions if the WebView is the only thing in the key loop
  171. if ([m_webView _becomingFirstResponderFromOutside] && m_webView == [m_webView previousValidKeyView])
  172. return;
  173. [[m_webView window] selectKeyViewPrecedingView:m_webView];
  174. }
  175. }
  176. void WebChromeClient::focusedNodeChanged(Node* node)
  177. {
  178. if (!node)
  179. return;
  180. if (!node->hasTagName(inputTag))
  181. return;
  182. HTMLInputElement* inputElement = static_cast<HTMLInputElement*>(node);
  183. if (!inputElement->isText())
  184. return;
  185. CallFormDelegate(m_webView, @selector(didFocusTextField:inFrame:), kit(inputElement), kit(inputElement->document()->frame()));
  186. }
  187. void WebChromeClient::focusedFrameChanged(Frame*)
  188. {
  189. }
  190. Page* WebChromeClient::createWindow(Frame* frame, const FrameLoadRequest&, const WindowFeatures& features, const NavigationAction&)
  191. {
  192. id delegate = [m_webView UIDelegate];
  193. WebView *newWebView;
  194. if ([delegate respondsToSelector:@selector(webView:createWebViewWithRequest:windowFeatures:)]) {
  195. NSNumber *x = features.xSet ? [[NSNumber alloc] initWithFloat:features.x] : nil;
  196. NSNumber *y = features.ySet ? [[NSNumber alloc] initWithFloat:features.y] : nil;
  197. NSNumber *width = features.widthSet ? [[NSNumber alloc] initWithFloat:features.width] : nil;
  198. NSNumber *height = features.heightSet ? [[NSNumber alloc] initWithFloat:features.height] : nil;
  199. NSNumber *menuBarVisible = [[NSNumber alloc] initWithBool:features.menuBarVisible];
  200. NSNumber *statusBarVisible = [[NSNumber alloc] initWithBool:features.statusBarVisible];
  201. NSNumber *toolBarVisible = [[NSNumber alloc] initWithBool:features.toolBarVisible];
  202. NSNumber *scrollbarsVisible = [[NSNumber alloc] initWithBool:features.scrollbarsVisible];
  203. NSNumber *resizable = [[NSNumber alloc] initWithBool:features.resizable];
  204. NSNumber *fullscreen = [[NSNumber alloc] initWithBool:features.fullscreen];
  205. NSNumber *dialog = [[NSNumber alloc] initWithBool:features.dialog];
  206. NSMutableDictionary *dictFeatures = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
  207. menuBarVisible, @"menuBarVisible",
  208. statusBarVisible, @"statusBarVisible",
  209. toolBarVisible, @"toolBarVisible",
  210. scrollbarsVisible, @"scrollbarsVisible",
  211. resizable, @"resizable",
  212. fullscreen, @"fullscreen",
  213. dialog, @"dialog",
  214. nil];
  215. if (x)
  216. [dictFeatures setObject:x forKey:@"x"];
  217. if (y)
  218. [dictFeatures setObject:y forKey:@"y"];
  219. if (width)
  220. [dictFeatures setObject:width forKey:@"width"];
  221. if (height)
  222. [dictFeatures setObject:height forKey:@"height"];
  223. newWebView = CallUIDelegate(m_webView, @selector(webView:createWebViewWithRequest:windowFeatures:), nil, dictFeatures);
  224. [dictFeatures release];
  225. [x release];
  226. [y release];
  227. [width release];
  228. [height release];
  229. [menuBarVisible release];
  230. [statusBarVisible release];
  231. [toolBarVisible release];
  232. [scrollbarsVisible release];
  233. [resizable release];
  234. [fullscreen release];
  235. [dialog release];
  236. } else if (features.dialog && [delegate respondsToSelector:@selector(webView:createWebViewModalDialogWithRequest:)]) {
  237. newWebView = CallUIDelegate(m_webView, @selector(webView:createWebViewModalDialogWithRequest:), nil);
  238. } else {
  239. newWebView = CallUIDelegate(m_webView, @selector(webView:createWebViewWithRequest:), nil);
  240. }
  241. #if USE(PLUGIN_HOST_PROCESS) && ENABLE(NETSCAPE_PLUGIN_API)
  242. if (newWebView)
  243. WebKit::NetscapePluginHostManager::shared().didCreateWindow();
  244. #endif
  245. return core(newWebView);
  246. }
  247. void WebChromeClient::show()
  248. {
  249. [[m_webView _UIDelegateForwarder] webViewShow:m_webView];
  250. }
  251. bool WebChromeClient::canRunModal()
  252. {
  253. return [[m_webView UIDelegate] respondsToSelector:@selector(webViewRunModal:)];
  254. }
  255. void WebChromeClient::runModal()
  256. {
  257. CallUIDelegate(m_webView, @selector(webViewRunModal:));
  258. }
  259. void WebChromeClient::setToolbarsVisible(bool b)
  260. {
  261. [[m_webView _UIDelegateForwarder] webView:m_webView setToolbarsVisible:b];
  262. }
  263. bool WebChromeClient::toolbarsVisible()
  264. {
  265. return CallUIDelegateReturningBoolean(NO, m_webView, @selector(webViewAreToolbarsVisible:));
  266. }
  267. void WebChromeClient::setStatusbarVisible(bool b)
  268. {
  269. [[m_webView _UIDelegateForwarder] webView:m_webView setStatusBarVisible:b];
  270. }
  271. bool WebChromeClient::statusbarVisible()
  272. {
  273. return CallUIDelegateReturningBoolean(NO, m_webView, @selector(webViewIsStatusBarVisible:));
  274. }
  275. void WebChromeClient::setScrollbarsVisible(bool b)
  276. {
  277. [[[m_webView mainFrame] frameView] setAllowsScrolling:b];
  278. }
  279. bool WebChromeClient::scrollbarsVisible()
  280. {
  281. return [[[m_webView mainFrame] frameView] allowsScrolling];
  282. }
  283. void WebChromeClient::setMenubarVisible(bool)
  284. {
  285. // The menubar is always visible in Mac OS X.
  286. return;
  287. }
  288. bool WebChromeClient::menubarVisible()
  289. {
  290. // The menubar is always visible in Mac OS X.
  291. return true;
  292. }
  293. void WebChromeClient::setResizable(bool b)
  294. {
  295. [[m_webView _UIDelegateForwarder] webView:m_webView setResizable:b];
  296. }
  297. inline static NSString *stringForMessageSource(MessageSource source)
  298. {
  299. switch (source) {
  300. case XMLMessageSource:
  301. return WebConsoleMessageXMLMessageSource;
  302. case JSMessageSource:
  303. return WebConsoleMessageJSMessageSource;
  304. case NetworkMessageSource:
  305. return WebConsoleMessageNetworkMessageSource;
  306. case ConsoleAPIMessageSource:
  307. return WebConsoleMessageConsoleAPIMessageSource;
  308. case StorageMessageSource:
  309. return WebConsoleMessageStorageMessageSource;
  310. case AppCacheMessageSource:
  311. return WebConsoleMessageAppCacheMessageSource;
  312. case RenderingMessageSource:
  313. return WebConsoleMessageRenderingMessageSource;
  314. case CSSMessageSource:
  315. return WebConsoleMessageCSSMessageSource;
  316. case SecurityMessageSource:
  317. return WebConsoleMessageSecurityMessageSource;
  318. case OtherMessageSource:
  319. return WebConsoleMessageOtherMessageSource;
  320. }
  321. ASSERT_NOT_REACHED();
  322. return @"";
  323. }
  324. inline static NSString *stringForMessageLevel(MessageLevel level)
  325. {
  326. switch (level) {
  327. case DebugMessageLevel:
  328. return WebConsoleMessageDebugMessageLevel;
  329. case LogMessageLevel:
  330. return WebConsoleMessageLogMessageLevel;
  331. case WarningMessageLevel:
  332. return WebConsoleMessageWarningMessageLevel;
  333. case ErrorMessageLevel:
  334. return WebConsoleMessageErrorMessageLevel;
  335. }
  336. ASSERT_NOT_REACHED();
  337. return @"";
  338. }
  339. void WebChromeClient::addMessageToConsole(MessageSource source, MessageLevel level, const String& message, unsigned int lineNumber, unsigned columnNumber, const String& sourceURL)
  340. {
  341. id delegate = [m_webView UIDelegate];
  342. BOOL respondsToNewSelector = NO;
  343. SEL selector = @selector(webView:addMessageToConsole:withSource:);
  344. if ([delegate respondsToSelector:selector])
  345. respondsToNewSelector = YES;
  346. else {
  347. // The old selector only takes JSMessageSource messages.
  348. if (source != JSMessageSource)
  349. return;
  350. selector = @selector(webView:addMessageToConsole:);
  351. if (![delegate respondsToSelector:selector])
  352. return;
  353. }
  354. NSString *messageSource = stringForMessageSource(source);
  355. NSDictionary *dictionary = [[NSDictionary alloc] initWithObjectsAndKeys:
  356. (NSString *)message, @"message",
  357. [NSNumber numberWithUnsignedInt:lineNumber], @"lineNumber",
  358. [NSNumber numberWithUnsignedInt:columnNumber], @"columnNumber",
  359. (NSString *)sourceURL, @"sourceURL",
  360. messageSource, @"MessageSource",
  361. stringForMessageLevel(level), @"MessageLevel",
  362. NULL];
  363. if (respondsToNewSelector)
  364. CallUIDelegate(m_webView, selector, dictionary, messageSource);
  365. else
  366. CallUIDelegate(m_webView, selector, dictionary);
  367. [dictionary release];
  368. }
  369. bool WebChromeClient::canRunBeforeUnloadConfirmPanel()
  370. {
  371. return [[m_webView UIDelegate] respondsToSelector:@selector(webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:)];
  372. }
  373. bool WebChromeClient::runBeforeUnloadConfirmPanel(const String& message, Frame* frame)
  374. {
  375. return CallUIDelegateReturningBoolean(true, m_webView, @selector(webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:), message, kit(frame));
  376. }
  377. void WebChromeClient::closeWindowSoon()
  378. {
  379. // We need to remove the parent WebView from WebViewSets here, before it actually
  380. // closes, to make sure that JavaScript code that executes before it closes
  381. // can't find it. Otherwise, window.open will select a closed WebView instead of
  382. // opening a new one <rdar://problem/3572585>.
  383. // We also need to stop the load to prevent further parsing or JavaScript execution
  384. // after the window has torn down <rdar://problem/4161660>.
  385. // FIXME: This code assumes that the UI delegate will respond to a webViewClose
  386. // message by actually closing the WebView. Safari guarantees this behavior, but other apps might not.
  387. // This approach is an inherent limitation of not making a close execute immediately
  388. // after a call to window.close.
  389. [m_webView setGroupName:nil];
  390. [m_webView stopLoading:nil];
  391. [m_webView performSelector:@selector(_closeWindow) withObject:nil afterDelay:0.0];
  392. }
  393. void WebChromeClient::runJavaScriptAlert(Frame* frame, const String& message)
  394. {
  395. id delegate = [m_webView UIDelegate];
  396. SEL selector = @selector(webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:);
  397. if ([delegate respondsToSelector:selector]) {
  398. CallUIDelegate(m_webView, selector, message, kit(frame));
  399. return;
  400. }
  401. // Call the old version of the delegate method if it is implemented.
  402. selector = @selector(webView:runJavaScriptAlertPanelWithMessage:);
  403. if ([delegate respondsToSelector:selector]) {
  404. CallUIDelegate(m_webView, selector, message);
  405. return;
  406. }
  407. }
  408. bool WebChromeClient::runJavaScriptConfirm(Frame* frame, const String& message)
  409. {
  410. id delegate = [m_webView UIDelegate];
  411. SEL selector = @selector(webView:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:);
  412. if ([delegate respondsToSelector:selector])
  413. return CallUIDelegateReturningBoolean(NO, m_webView, selector, message, kit(frame));
  414. // Call the old version of the delegate method if it is implemented.
  415. selector = @selector(webView:runJavaScriptConfirmPanelWithMessage:);
  416. if ([delegate respondsToSelector:selector])
  417. return CallUIDelegateReturningBoolean(NO, m_webView, selector, message);
  418. return NO;
  419. }
  420. bool WebChromeClient::runJavaScriptPrompt(Frame* frame, const String& prompt, const String& defaultText, String& result)
  421. {
  422. id delegate = [m_webView UIDelegate];
  423. SEL selector = @selector(webView:runJavaScriptTextInputPanelWithPrompt:defaultText:initiatedByFrame:);
  424. NSString *defaultString = defaultText;
  425. if ([delegate respondsToSelector:selector]) {
  426. result = (NSString *)CallUIDelegate(m_webView, selector, prompt, defaultString, kit(frame));
  427. return !result.isNull();
  428. }
  429. // Call the old version of the delegate method if it is implemented.
  430. selector = @selector(webView:runJavaScriptTextInputPanelWithPrompt:defaultText:);
  431. if ([delegate respondsToSelector:selector]) {
  432. result = (NSString *)CallUIDelegate(m_webView, selector, prompt, defaultString);
  433. return !result.isNull();
  434. }
  435. result = [[WebDefaultUIDelegate sharedUIDelegate] webView:m_webView runJavaScriptTextInputPanelWithPrompt:prompt defaultText:defaultString initiatedByFrame:kit(frame)];
  436. return !result.isNull();
  437. }
  438. bool WebChromeClient::shouldInterruptJavaScript()
  439. {
  440. return CallUIDelegateReturningBoolean(NO, m_webView, @selector(webViewShouldInterruptJavaScript:));
  441. }
  442. void WebChromeClient::setStatusbarText(const String& status)
  443. {
  444. // We want the temporaries allocated here to be released even before returning to the
  445. // event loop; see <http://bugs.webkit.org/show_bug.cgi?id=9880>.
  446. NSAutoreleasePool* localPool = [[NSAutoreleasePool alloc] init];
  447. CallUIDelegate(m_webView, @selector(webView:setStatusText:), (NSString *)status);
  448. [localPool drain];
  449. }
  450. IntRect WebChromeClient::windowResizerRect() const
  451. {
  452. return enclosingIntRect([[m_webView window] _growBoxRect]);
  453. }
  454. bool WebChromeClient::supportsImmediateInvalidation()
  455. {
  456. return true;
  457. }
  458. void WebChromeClient::invalidateRootView(const IntRect&, bool immediate)
  459. {
  460. if (immediate) {
  461. [[m_webView window] displayIfNeeded];
  462. [[m_webView window] flushWindowIfNeeded];
  463. }
  464. }
  465. void WebChromeClient::invalidateContentsAndRootView(const IntRect& rect, bool immediate)
  466. {
  467. }
  468. void WebChromeClient::invalidateContentsForSlowScroll(const IntRect& rect, bool immediate)
  469. {
  470. invalidateContentsAndRootView(rect, immediate);
  471. }
  472. void WebChromeClient::scroll(const IntSize&, const IntRect&, const IntRect&)
  473. {
  474. }
  475. IntPoint WebChromeClient::screenToRootView(const IntPoint& p) const
  476. {
  477. // FIXME: Implement this.
  478. return p;
  479. }
  480. IntRect WebChromeClient::rootViewToScreen(const IntRect& r) const
  481. {
  482. // FIXME: Implement this.
  483. return r;
  484. }
  485. PlatformPageClient WebChromeClient::platformPageClient() const
  486. {
  487. return 0;
  488. }
  489. void WebChromeClient::contentsSizeChanged(Frame*, const IntSize&) const
  490. {
  491. }
  492. void WebChromeClient::scrollRectIntoView(const IntRect& r) const
  493. {
  494. // FIXME: This scrolling behavior should be under the control of the embedding client,
  495. // perhaps in a delegate method, rather than something WebKit does unconditionally.
  496. NSView *coordinateView = [[[m_webView mainFrame] frameView] documentView];
  497. NSRect rect = r;
  498. for (NSView *view = m_webView; view; view = [view superview]) {
  499. if ([view isKindOfClass:[NSClipView class]]) {
  500. NSClipView *clipView = (NSClipView *)view;
  501. NSView *documentView = [clipView documentView];
  502. [documentView scrollRectToVisible:[documentView convertRect:rect fromView:coordinateView]];
  503. }
  504. }
  505. }
  506. // End host window methods.
  507. bool WebChromeClient::shouldUnavailablePluginMessageBeButton(RenderEmbeddedObject::PluginUnavailabilityReason pluginUnavailabilityReason) const
  508. {
  509. if (pluginUnavailabilityReason == RenderEmbeddedObject::PluginMissing)
  510. return [[m_webView UIDelegate] respondsToSelector:@selector(webView:didPressMissingPluginButton:)];
  511. return false;
  512. }
  513. void WebChromeClient::unavailablePluginButtonClicked(Element* element, RenderEmbeddedObject::PluginUnavailabilityReason pluginUnavailabilityReason) const
  514. {
  515. ASSERT(element->hasTagName(objectTag) || element->hasTagName(embedTag) || element->hasTagName(appletTag));
  516. ASSERT(pluginUnavailabilityReason == RenderEmbeddedObject::PluginMissing);
  517. CallUIDelegate(m_webView, @selector(webView:didPressMissingPluginButton:), kit(element));
  518. }
  519. void WebChromeClient::mouseDidMoveOverElement(const HitTestResult& result, unsigned modifierFlags)
  520. {
  521. WebElementDictionary *element = [[WebElementDictionary alloc] initWithHitTestResult:result];
  522. [m_webView _mouseDidMoveOverElement:element modifierFlags:modifierFlags];
  523. [element release];
  524. }
  525. void WebChromeClient::setToolTip(const String& toolTip, TextDirection)
  526. {
  527. NSView<WebDocumentView> *documentView = [[[m_webView _selectedOrMainFrame] frameView] documentView];
  528. if ([documentView isKindOfClass:[WebHTMLView class]])
  529. [(WebHTMLView *)documentView _setToolTip:toolTip];
  530. }
  531. void WebChromeClient::print(Frame* frame)
  532. {
  533. WebFrame *webFrame = kit(frame);
  534. if ([[m_webView UIDelegate] respondsToSelector:@selector(webView:printFrame:)])
  535. CallUIDelegate(m_webView, @selector(webView:printFrame:), webFrame);
  536. else
  537. CallUIDelegate(m_webView, @selector(webView:printFrameView:), [webFrame frameView]);
  538. }
  539. #if ENABLE(SQL_DATABASE)
  540. void WebChromeClient::exceededDatabaseQuota(Frame* frame, const String& databaseName, DatabaseDetails)
  541. {
  542. BEGIN_BLOCK_OBJC_EXCEPTIONS;
  543. WebSecurityOrigin *webOrigin = [[WebSecurityOrigin alloc] _initWithWebCoreSecurityOrigin:frame->document()->securityOrigin()];
  544. // FIXME: remove this workaround once shipping Safari has the necessary delegate implemented.
  545. if (WKAppVersionCheckLessThan(@"com.apple.Safari", -1, 3.1)) {
  546. const unsigned long long defaultQuota = 5 * 1024 * 1024; // 5 megabytes should hopefully be enough to test storage support.
  547. [[webOrigin databaseQuotaManager] setQuota:defaultQuota];
  548. } else
  549. CallUIDelegate(m_webView, @selector(webView:frame:exceededDatabaseQuotaForSecurityOrigin:database:), kit(frame), webOrigin, (NSString *)databaseName);
  550. [webOrigin release];
  551. END_BLOCK_OBJC_EXCEPTIONS;
  552. }
  553. #endif
  554. void WebChromeClient::reachedMaxAppCacheSize(int64_t spaceNeeded)
  555. {
  556. // FIXME: Free some space.
  557. }
  558. void WebChromeClient::reachedApplicationCacheOriginQuota(SecurityOrigin* origin, int64_t totalSpaceNeeded)
  559. {
  560. BEGIN_BLOCK_OBJC_EXCEPTIONS;
  561. WebSecurityOrigin *webOrigin = [[WebSecurityOrigin alloc] _initWithWebCoreSecurityOrigin:origin];
  562. CallUIDelegate(m_webView, @selector(webView:exceededApplicationCacheOriginQuotaForSecurityOrigin:totalSpaceNeeded:), webOrigin, static_cast<NSUInteger>(totalSpaceNeeded));
  563. [webOrigin release];
  564. END_BLOCK_OBJC_EXCEPTIONS;
  565. }
  566. void WebChromeClient::populateVisitedLinks()
  567. {
  568. if ([m_webView historyDelegate]) {
  569. WebHistoryDelegateImplementationCache* implementations = WebViewGetHistoryDelegateImplementations(m_webView);
  570. if (implementations->populateVisitedLinksFunc)
  571. CallHistoryDelegate(implementations->populateVisitedLinksFunc, m_webView, @selector(populateVisitedLinksForWebView:));
  572. return;
  573. }
  574. BEGIN_BLOCK_OBJC_EXCEPTIONS;
  575. [[WebHistory optionalSharedHistory] _addVisitedLinksToPageGroup:[m_webView page]->group()];
  576. END_BLOCK_OBJC_EXCEPTIONS;
  577. }
  578. #if ENABLE(DASHBOARD_SUPPORT)
  579. void WebChromeClient::annotatedRegionsChanged()
  580. {
  581. BEGIN_BLOCK_OBJC_EXCEPTIONS;
  582. CallUIDelegate(m_webView, @selector(webView:dashboardRegionsChanged:), [m_webView _dashboardRegions]);
  583. END_BLOCK_OBJC_EXCEPTIONS;
  584. }
  585. #endif
  586. FloatRect WebChromeClient::customHighlightRect(Node* node, const AtomicString& type, const FloatRect& lineRect)
  587. {
  588. BEGIN_BLOCK_OBJC_EXCEPTIONS;
  589. NSView *documentView = [[kit(node->document()->frame()) frameView] documentView];
  590. if (![documentView isKindOfClass:[WebHTMLView class]])
  591. return NSZeroRect;
  592. WebHTMLView *webHTMLView = (WebHTMLView *)documentView;
  593. id<WebHTMLHighlighter> highlighter = [webHTMLView _highlighterForType:type];
  594. return [highlighter highlightRectForLine:lineRect representedNode:kit(node)];
  595. END_BLOCK_OBJC_EXCEPTIONS;
  596. return NSZeroRect;
  597. }
  598. void WebChromeClient::paintCustomHighlight(Node* node, const AtomicString& type, const FloatRect& boxRect, const FloatRect& lineRect,
  599. bool behindText, bool entireLine)
  600. {
  601. BEGIN_BLOCK_OBJC_EXCEPTIONS;
  602. NSView *documentView = [[kit(node->document()->frame()) frameView] documentView];
  603. if (![documentView isKindOfClass:[WebHTMLView class]])
  604. return;
  605. WebHTMLView *webHTMLView = (WebHTMLView *)documentView;
  606. id<WebHTMLHighlighter> highlighter = [webHTMLView _highlighterForType:type];
  607. [highlighter paintHighlightForBox:boxRect onLine:lineRect behindText:behindText entireLine:entireLine representedNode:kit(node)];
  608. END_BLOCK_OBJC_EXCEPTIONS;
  609. }
  610. void WebChromeClient::runOpenPanel(Frame*, PassRefPtr<FileChooser> chooser)
  611. {
  612. BEGIN_BLOCK_OBJC_EXCEPTIONS;
  613. BOOL allowMultipleFiles = chooser->settings().allowsMultipleFiles;
  614. WebOpenPanelResultListener *listener = [[WebOpenPanelResultListener alloc] initWithChooser:chooser];
  615. id delegate = [m_webView UIDelegate];
  616. if ([delegate respondsToSelector:@selector(webView:runOpenPanelForFileButtonWithResultListener:allowMultipleFiles:)])
  617. CallUIDelegate(m_webView, @selector(webView:runOpenPanelForFileButtonWithResultListener:allowMultipleFiles:), listener, allowMultipleFiles);
  618. else if ([delegate respondsToSelector:@selector(webView:runOpenPanelForFileButtonWithResultListener:)])
  619. CallUIDelegate(m_webView, @selector(webView:runOpenPanelForFileButtonWithResultListener:), listener);
  620. else
  621. [listener cancel];
  622. [listener release];
  623. END_BLOCK_OBJC_EXCEPTIONS;
  624. }
  625. void WebChromeClient::loadIconForFiles(const Vector<String>& filenames, FileIconLoader* iconLoader)
  626. {
  627. iconLoader->notifyFinished(Icon::createIconForFiles(filenames));
  628. }
  629. void WebChromeClient::setCursor(const WebCore::Cursor& cursor)
  630. {
  631. if ([NSApp _cursorRectCursor])
  632. return;
  633. NSCursor *platformCursor = cursor.platformCursor();
  634. if ([NSCursor currentCursor] == platformCursor)
  635. return;
  636. [platformCursor set];
  637. }
  638. void WebChromeClient::setCursorHiddenUntilMouseMoves(bool hiddenUntilMouseMoves)
  639. {
  640. [NSCursor setHiddenUntilMouseMoves:hiddenUntilMouseMoves];
  641. }
  642. KeyboardUIMode WebChromeClient::keyboardUIMode()
  643. {
  644. BEGIN_BLOCK_OBJC_EXCEPTIONS;
  645. return [m_webView _keyboardUIMode];
  646. END_BLOCK_OBJC_EXCEPTIONS;
  647. return KeyboardAccessDefault;
  648. }
  649. NSResponder *WebChromeClient::firstResponder()
  650. {
  651. BEGIN_BLOCK_OBJC_EXCEPTIONS;
  652. return [[m_webView _UIDelegateForwarder] webViewFirstResponder:m_webView];
  653. END_BLOCK_OBJC_EXCEPTIONS;
  654. return nil;
  655. }
  656. void WebChromeClient::makeFirstResponder(NSResponder *responder)
  657. {
  658. BEGIN_BLOCK_OBJC_EXCEPTIONS;
  659. [m_webView _pushPerformingProgrammaticFocus];
  660. [[m_webView _UIDelegateForwarder] webView:m_webView makeFirstResponder:responder];
  661. [m_webView _popPerformingProgrammaticFocus];
  662. END_BLOCK_OBJC_EXCEPTIONS;
  663. }
  664. void WebChromeClient::enableSuddenTermination()
  665. {
  666. [[NSProcessInfo processInfo] enableSuddenTermination];
  667. }
  668. void WebChromeClient::disableSuddenTermination()
  669. {
  670. [[NSProcessInfo processInfo] disableSuddenTermination];
  671. }
  672. bool WebChromeClient::shouldReplaceWithGeneratedFileForUpload(const String& path, String& generatedFilename)
  673. {
  674. NSString* filename;
  675. if (![[m_webView _UIDelegateForwarder] webView:m_webView shouldReplaceUploadFile:path usingGeneratedFilename:&filename])
  676. return false;
  677. generatedFilename = filename;
  678. return true;
  679. }
  680. String WebChromeClient::generateReplacementFile(const String& path)
  681. {
  682. return [[m_webView _UIDelegateForwarder] webView:m_webView generateReplacementFile:path];
  683. }
  684. void WebChromeClient::elementDidFocus(const WebCore::Node* node)
  685. {
  686. CallUIDelegate(m_webView, @selector(webView:formDidFocusNode:), kit(const_cast<WebCore::Node*>(node)));
  687. }
  688. void WebChromeClient::elementDidBlur(const WebCore::Node* node)
  689. {
  690. CallUIDelegate(m_webView, @selector(webView:formDidBlurNode:), kit(const_cast<WebCore::Node*>(node)));
  691. }
  692. bool WebChromeClient::selectItemWritingDirectionIsNatural()
  693. {
  694. return false;
  695. }
  696. bool WebChromeClient::selectItemAlignmentFollowsMenuWritingDirection()
  697. {
  698. return true;
  699. }
  700. bool WebChromeClient::hasOpenedPopup() const
  701. {
  702. notImplemented();
  703. return false;
  704. }
  705. PassRefPtr<WebCore::PopupMenu> WebChromeClient::createPopupMenu(WebCore::PopupMenuClient* client) const
  706. {
  707. return adoptRef(new PopupMenuMac(client));
  708. }
  709. PassRefPtr<WebCore::SearchPopupMenu> WebChromeClient::createSearchPopupMenu(WebCore::PopupMenuClient* client) const
  710. {
  711. return adoptRef(new SearchPopupMenuMac(client));
  712. }
  713. bool WebChromeClient::shouldPaintEntireContents() const
  714. {
  715. NSView *documentView = [[[m_webView mainFrame] frameView] documentView];
  716. return [documentView layer];
  717. }
  718. #if USE(ACCELERATED_COMPOSITING)
  719. void WebChromeClient::attachRootGraphicsLayer(Frame* frame, GraphicsLayer* graphicsLayer)
  720. {
  721. BEGIN_BLOCK_OBJC_EXCEPTIONS;
  722. NSView *documentView = [[kit(frame) frameView] documentView];
  723. if (![documentView isKindOfClass:[WebHTMLView class]]) {
  724. // We should never be attaching when we don't have a WebHTMLView.
  725. ASSERT(!graphicsLayer);
  726. return;
  727. }
  728. WebHTMLView *webHTMLView = (WebHTMLView *)documentView;
  729. if (graphicsLayer)
  730. [webHTMLView attachRootLayer:graphicsLayer->platformLayer()];
  731. else
  732. [webHTMLView detachRootLayer];
  733. END_BLOCK_OBJC_EXCEPTIONS;
  734. }
  735. void WebChromeClient::setNeedsOneShotDrawingSynchronization()
  736. {
  737. BEGIN_BLOCK_OBJC_EXCEPTIONS;
  738. [m_webView _setNeedsOneShotDrawingSynchronization:YES];
  739. END_BLOCK_OBJC_EXCEPTIONS;
  740. }
  741. void WebChromeClient::scheduleCompositingLayerFlush()
  742. {
  743. BEGIN_BLOCK_OBJC_EXCEPTIONS;
  744. [m_webView _scheduleCompositingLayerFlush];
  745. END_BLOCK_OBJC_EXCEPTIONS;
  746. }
  747. #endif
  748. #if ENABLE(VIDEO)
  749. bool WebChromeClient::supportsFullscreenForNode(const Node* node)
  750. {
  751. return node->hasTagName(WebCore::HTMLNames::videoTag);
  752. }
  753. void WebChromeClient::enterFullscreenForNode(Node* node)
  754. {
  755. BEGIN_BLOCK_OBJC_EXCEPTIONS;
  756. [m_webView _enterFullscreenForNode:node];
  757. END_BLOCK_OBJC_EXCEPTIONS;
  758. }
  759. void WebChromeClient::exitFullscreenForNode(Node*)
  760. {
  761. BEGIN_BLOCK_OBJC_EXCEPTIONS;
  762. [m_webView _exitFullscreen];
  763. END_BLOCK_OBJC_EXCEPTIONS;
  764. }
  765. #endif
  766. #if ENABLE(FULLSCREEN_API)
  767. bool WebChromeClient::supportsFullScreenForElement(const Element* element, bool withKeyboard)
  768. {
  769. SEL selector = @selector(webView:supportsFullScreenForElement:withKeyboard:);
  770. if ([[m_webView UIDelegate] respondsToSelector:selector])
  771. return CallUIDelegateReturningBoolean(false, m_webView, selector, kit(const_cast<WebCore::Element*>(element)), withKeyboard);
  772. return [m_webView _supportsFullScreenForElement:const_cast<WebCore::Element*>(element) withKeyboard:withKeyboard];
  773. }
  774. void WebChromeClient::enterFullScreenForElement(Element* element)
  775. {
  776. SEL selector = @selector(webView:enterFullScreenForElement:listener:);
  777. if ([[m_webView UIDelegate] respondsToSelector:selector]) {
  778. WebKitFullScreenListener* listener = [[WebKitFullScreenListener alloc] initWithElement:element];
  779. CallUIDelegate(m_webView, selector, kit(element), listener);
  780. [listener release];
  781. } else
  782. [m_webView _enterFullScreenForElement:element];
  783. }
  784. void WebChromeClient::exitFullScreenForElement(Element* element)
  785. {
  786. SEL selector = @selector(webView:exitFullScreenForElement:listener:);
  787. if ([[m_webView UIDelegate] respondsToSelector:selector]) {
  788. WebKitFullScreenListener* listener = [[WebKitFullScreenListener alloc] initWithElement:element];
  789. CallUIDelegate(m_webView, selector, kit(element), listener);
  790. [listener release];
  791. } else
  792. [m_webView _exitFullScreenForElement:element];
  793. }
  794. void WebChromeClient::fullScreenRendererChanged(RenderBox* renderer)
  795. {
  796. SEL selector = @selector(webView:fullScreenRendererChanged:);
  797. if ([[m_webView UIDelegate] respondsToSelector:selector])
  798. CallUIDelegate(m_webView, selector, (id)renderer);
  799. }
  800. #endif