1 /* 2 * Copyright (C) 2010 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "config.h" 32 #include "WebViewImpl.h" 33 34 #include "AutoFillPopupMenuClient.h" 35 #include "AXObjectCache.h" 36 #include "BackForwardListChromium.h" 37 #include "CSSStyleSelector.h" 38 #include "CSSValueKeywords.h" 39 #include "Chrome.h" 40 #include "ColorSpace.h" 41 #include "CompositionUnderlineVectorBuilder.h" 42 #include "ContextMenu.h" 43 #include "ContextMenuController.h" 44 #include "ContextMenuItem.h" 45 #include "Cursor.h" 46 #include "DOMUtilitiesPrivate.h" 47 #include "DeviceOrientationClientProxy.h" 48 #include "Document.h" 49 #include "DocumentLoader.h" 50 #include "DragController.h" 51 #include "DragData.h" 52 #include "DragScrollTimer.h" 53 #include "Editor.h" 54 #include "EventHandler.h" 55 #include "Extensions3D.h" 56 #include "FocusController.h" 57 #include "FontDescription.h" 58 #include "FrameLoader.h" 59 #include "FrameTree.h" 60 #include "FrameView.h" 61 #include "GeolocationClientProxy.h" 62 #include "GraphicsContext.h" 63 #include "GraphicsContext3D.h" 64 #include "GraphicsContext3DInternal.h" 65 #include "HTMLInputElement.h" 66 #include "HTMLMediaElement.h" 67 #include "HTMLNames.h" 68 #include "HitTestResult.h" 69 #include "Image.h" 70 #include "ImageBuffer.h" 71 #include "InspectorController.h" 72 #include "KeyboardCodes.h" 73 #include "KeyboardEvent.h" 74 #include "MIMETypeRegistry.h" 75 #include "NodeRenderStyle.h" 76 #include "Page.h" 77 #include "PageGroup.h" 78 #include "PageGroupLoadDeferrer.h" 79 #include "Pasteboard.h" 80 #include "PlatformContextSkia.h" 81 #include "PlatformKeyboardEvent.h" 82 #include "PlatformMouseEvent.h" 83 #include "PlatformThemeChromiumGtk.h" 84 #include "PlatformWheelEvent.h" 85 #include "PopupMenuChromium.h" 86 #include "PopupMenuClient.h" 87 #include "ProgressTracker.h" 88 #include "RenderView.h" 89 #include "ResourceHandle.h" 90 #include "SecurityOrigin.h" 91 #include "SelectionController.h" 92 #include "Settings.h" 93 #include "SpeechInputClientImpl.h" 94 #include "Timer.h" 95 #include "TraceEvent.h" 96 #include "TypingCommand.h" 97 #include "UserGestureIndicator.h" 98 #include "Vector.h" 99 #include "WebAccessibilityObject.h" 100 #include "WebAutoFillClient.h" 101 #include "WebDevToolsAgentImpl.h" 102 #include "WebDevToolsAgentPrivate.h" 103 #include "WebDragData.h" 104 #include "WebFrameImpl.h" 105 #include "WebGraphicsContext3D.h" 106 #include "WebImage.h" 107 #include "WebInputElement.h" 108 #include "WebInputEvent.h" 109 #include "WebInputEventConversion.h" 110 #include "WebKit.h" 111 #include "WebKitClient.h" 112 #include "WebMediaPlayerAction.h" 113 #include "WebNode.h" 114 #include "WebPlugin.h" 115 #include "WebPluginContainerImpl.h" 116 #include "WebPoint.h" 117 #include "WebPopupMenuImpl.h" 118 #include "WebRect.h" 119 #include "WebRuntimeFeatures.h" 120 #include "WebSettingsImpl.h" 121 #include "WebString.h" 122 #include "WebVector.h" 123 #include "WebViewClient.h" 124 #include "cc/CCHeadsUpDisplay.h" 125 #include <wtf/ByteArray.h> 126 #include <wtf/CurrentTime.h> 127 #include <wtf/RefPtr.h> 128 129 #if USE(CG) 130 #include <CoreGraphics/CGBitmapContext.h> 131 #include <CoreGraphics/CGContext.h> 132 #endif 133 134 #if OS(WINDOWS) 135 #include "RenderThemeChromiumWin.h" 136 #else 137 #if OS(LINUX) || OS(FREEBSD) 138 #include "RenderThemeChromiumLinux.h" 139 #endif 140 #include "RenderTheme.h" 141 #endif 142 143 // Get rid of WTF's pow define so we can use std::pow. 144 #undef pow 145 #include <cmath> // for std::pow 146 147 using namespace WebCore; 148 149 namespace { 150 151 GraphicsContext3D::Attributes getCompositorContextAttributes() 152 { 153 // Explicitly disable antialiasing for the compositor. As of the time of 154 // this writing, the only platform that supported antialiasing for the 155 // compositor was Mac OS X, because the on-screen OpenGL context creation 156 // code paths on Windows and Linux didn't yet have multisampling support. 157 // Mac OS X essentially always behaves as though it's rendering offscreen. 158 // Multisampling has a heavy cost especially on devices with relatively low 159 // fill rate like most notebooks, and the Mac implementation would need to 160 // be optimized to resolve directly into the IOSurface shared between the 161 // GPU and browser processes. For these reasons and to avoid platform 162 // disparities we explicitly disable antialiasing. 163 GraphicsContext3D::Attributes attributes; 164 attributes.antialias = false; 165 return attributes; 166 } 167 168 } // anonymous namespace 169 170 namespace WebKit { 171 172 // Change the text zoom level by kTextSizeMultiplierRatio each time the user 173 // zooms text in or out (ie., change by 20%). The min and max values limit 174 // text zoom to half and 3x the original text size. These three values match 175 // those in Apple's port in WebKit/WebKit/WebView/WebView.mm 176 const double WebView::textSizeMultiplierRatio = 1.2; 177 const double WebView::minTextSizeMultiplier = 0.5; 178 const double WebView::maxTextSizeMultiplier = 3.0; 179 180 181 // The group name identifies a namespace of pages. Page group is used on OSX 182 // for some programs that use HTML views to display things that don't seem like 183 // web pages to the user (so shouldn't have visited link coloring). We only use 184 // one page group. 185 const char* pageGroupName = "default"; 186 187 // Used to defer all page activity in cases where the embedder wishes to run 188 // a nested event loop. Using a stack enables nesting of message loop invocations. 189 static Vector<PageGroupLoadDeferrer*> pageGroupLoadDeferrerStack; 190 191 // Ensure that the WebDragOperation enum values stay in sync with the original 192 // DragOperation constants. 193 #define COMPILE_ASSERT_MATCHING_ENUM(coreName) \ 194 COMPILE_ASSERT(int(coreName) == int(Web##coreName), dummy##coreName) 195 COMPILE_ASSERT_MATCHING_ENUM(DragOperationNone); 196 COMPILE_ASSERT_MATCHING_ENUM(DragOperationCopy); 197 COMPILE_ASSERT_MATCHING_ENUM(DragOperationLink); 198 COMPILE_ASSERT_MATCHING_ENUM(DragOperationGeneric); 199 COMPILE_ASSERT_MATCHING_ENUM(DragOperationPrivate); 200 COMPILE_ASSERT_MATCHING_ENUM(DragOperationMove); 201 COMPILE_ASSERT_MATCHING_ENUM(DragOperationDelete); 202 COMPILE_ASSERT_MATCHING_ENUM(DragOperationEvery); 203 204 static const PopupContainerSettings autoFillPopupSettings = { 205 false, // setTextOnIndexChange 206 false, // acceptOnAbandon 207 true, // loopSelectionNavigation 208 false // restrictWidthOfListBox (For security reasons show the entire entry 209 // so the user doesn't enter information he did not intend to.) 210 }; 211 212 static bool shouldUseExternalPopupMenus = false; 213 214 // WebView ---------------------------------------------------------------- 215 216 WebView* WebView::create(WebViewClient* client) 217 { 218 // Keep runtime flag for device motion turned off until it's implemented. 219 WebRuntimeFeatures::enableDeviceMotion(false); 220 221 // Pass the WebViewImpl's self-reference to the caller. 222 return adoptRef(new WebViewImpl(client)).leakRef(); 223 } 224 225 void WebView::setUseExternalPopupMenus(bool useExternalPopupMenus) 226 { 227 shouldUseExternalPopupMenus = useExternalPopupMenus; 228 } 229 230 void WebView::updateVisitedLinkState(unsigned long long linkHash) 231 { 232 Page::visitedStateChanged(PageGroup::pageGroup(pageGroupName), linkHash); 233 } 234 235 void WebView::resetVisitedLinkState() 236 { 237 Page::allVisitedStateChanged(PageGroup::pageGroup(pageGroupName)); 238 } 239 240 void WebView::willEnterModalLoop() 241 { 242 PageGroup* pageGroup = PageGroup::pageGroup(pageGroupName); 243 ASSERT(pageGroup); 244 245 if (pageGroup->pages().isEmpty()) 246 pageGroupLoadDeferrerStack.append(static_cast<PageGroupLoadDeferrer*>(0)); 247 else { 248 // Pick any page in the page group since we are deferring all pages. 249 pageGroupLoadDeferrerStack.append(new PageGroupLoadDeferrer(*pageGroup->pages().begin(), true)); 250 } 251 } 252 253 void WebView::didExitModalLoop() 254 { 255 ASSERT(pageGroupLoadDeferrerStack.size()); 256 257 delete pageGroupLoadDeferrerStack.last(); 258 pageGroupLoadDeferrerStack.removeLast(); 259 } 260 261 void WebViewImpl::initializeMainFrame(WebFrameClient* frameClient) 262 { 263 // NOTE: The WebFrameImpl takes a reference to itself within InitMainFrame 264 // and releases that reference once the corresponding Frame is destroyed. 265 RefPtr<WebFrameImpl> frame = WebFrameImpl::create(frameClient); 266 267 frame->initializeAsMainFrame(this); 268 269 // Restrict the access to the local file system 270 // (see WebView.mm WebView::_commonInitializationWithFrameName). 271 SecurityOrigin::setLocalLoadPolicy(SecurityOrigin::AllowLocalLoadsForLocalOnly); 272 } 273 274 void WebViewImpl::setDevToolsAgentClient(WebDevToolsAgentClient* devToolsClient) 275 { 276 if (devToolsClient) 277 m_devToolsAgent = new WebDevToolsAgentImpl(this, devToolsClient); 278 else 279 m_devToolsAgent.clear(); 280 } 281 282 void WebViewImpl::setAutoFillClient(WebAutoFillClient* autoFillClient) 283 { 284 m_autoFillClient = autoFillClient; 285 } 286 287 void WebViewImpl::setSpellCheckClient(WebSpellCheckClient* spellCheckClient) 288 { 289 m_spellCheckClient = spellCheckClient; 290 } 291 292 WebViewImpl::WebViewImpl(WebViewClient* client) 293 : m_client(client) 294 , m_autoFillClient(0) 295 , m_spellCheckClient(0) 296 , m_chromeClientImpl(this) 297 , m_contextMenuClientImpl(this) 298 , m_dragClientImpl(this) 299 , m_editorClientImpl(this) 300 , m_inspectorClientImpl(this) 301 , m_observedNewNavigation(false) 302 #ifndef NDEBUG 303 , m_newNavigationLoader(0) 304 #endif 305 , m_zoomLevel(0) 306 , m_minimumZoomLevel(zoomFactorToZoomLevel(minTextSizeMultiplier)) 307 , m_maximumZoomLevel(zoomFactorToZoomLevel(maxTextSizeMultiplier)) 308 , m_contextMenuAllowed(false) 309 , m_doingDragAndDrop(false) 310 , m_ignoreInputEvents(false) 311 , m_suppressNextKeypressEvent(false) 312 , m_initialNavigationPolicy(WebNavigationPolicyIgnore) 313 , m_imeAcceptEvents(true) 314 , m_operationsAllowed(WebDragOperationNone) 315 , m_dragOperation(WebDragOperationNone) 316 , m_autoFillPopupShowing(false) 317 , m_autoFillPopupClient(0) 318 , m_autoFillPopup(0) 319 , m_isTransparent(false) 320 , m_tabsToLinks(false) 321 , m_dragScrollTimer(new DragScrollTimer()) 322 #if USE(ACCELERATED_COMPOSITING) 323 , m_layerRenderer(0) 324 , m_isAcceleratedCompositingActive(false) 325 , m_compositorCreationFailed(false) 326 , m_recreatingGraphicsContext(false) 327 #endif 328 #if ENABLE(INPUT_SPEECH) 329 , m_speechInputClient(SpeechInputClientImpl::create(client)) 330 #endif 331 , m_deviceOrientationClientProxy(new DeviceOrientationClientProxy(client ? client->deviceOrientationClient() : 0)) 332 , m_geolocationClientProxy(new GeolocationClientProxy(client ? client->geolocationClient() : 0)) 333 { 334 // WebKit/win/WebView.cpp does the same thing, except they call the 335 // KJS specific wrapper around this method. We need to have threading 336 // initialized because CollatorICU requires it. 337 WTF::initializeThreading(); 338 WTF::initializeMainThread(); 339 340 // set to impossible point so we always get the first mouse pos 341 m_lastMousePosition = WebPoint(-1, -1); 342 343 Page::PageClients pageClients; 344 pageClients.chromeClient = &m_chromeClientImpl; 345 pageClients.contextMenuClient = &m_contextMenuClientImpl; 346 pageClients.editorClient = &m_editorClientImpl; 347 pageClients.dragClient = &m_dragClientImpl; 348 pageClients.inspectorClient = &m_inspectorClientImpl; 349 #if ENABLE(INPUT_SPEECH) 350 pageClients.speechInputClient = m_speechInputClient.get(); 351 #endif 352 pageClients.deviceOrientationClient = m_deviceOrientationClientProxy.get(); 353 pageClients.geolocationClient = m_geolocationClientProxy.get(); 354 pageClients.backForwardClient = BackForwardListChromium::create(this); 355 356 m_page.set(new Page(pageClients)); 357 358 m_geolocationClientProxy->setController(m_page->geolocationController()); 359 360 m_page->setGroupName(pageGroupName); 361 362 m_inspectorSettingsMap.set(new SettingsMap); 363 } 364 365 WebViewImpl::~WebViewImpl() 366 { 367 ASSERT(!m_page); 368 } 369 370 RenderTheme* WebViewImpl::theme() const 371 { 372 return m_page.get() ? m_page->theme() : RenderTheme::defaultTheme().get(); 373 } 374 375 WebFrameImpl* WebViewImpl::mainFrameImpl() 376 { 377 return m_page.get() ? WebFrameImpl::fromFrame(m_page->mainFrame()) : 0; 378 } 379 380 bool WebViewImpl::tabKeyCyclesThroughElements() const 381 { 382 ASSERT(m_page.get()); 383 return m_page->tabKeyCyclesThroughElements(); 384 } 385 386 void WebViewImpl::setTabKeyCyclesThroughElements(bool value) 387 { 388 if (m_page) 389 m_page->setTabKeyCyclesThroughElements(value); 390 } 391 392 void WebViewImpl::mouseMove(const WebMouseEvent& event) 393 { 394 if (!mainFrameImpl() || !mainFrameImpl()->frameView()) 395 return; 396 397 m_lastMousePosition = WebPoint(event.x, event.y); 398 399 // We call mouseMoved here instead of handleMouseMovedEvent because we need 400 // our ChromeClientImpl to receive changes to the mouse position and 401 // tooltip text, and mouseMoved handles all of that. 402 mainFrameImpl()->frame()->eventHandler()->mouseMoved( 403 PlatformMouseEventBuilder(mainFrameImpl()->frameView(), event)); 404 } 405 406 void WebViewImpl::mouseLeave(const WebMouseEvent& event) 407 { 408 // This event gets sent as the main frame is closing. In that case, just 409 // ignore it. 410 if (!mainFrameImpl() || !mainFrameImpl()->frameView()) 411 return; 412 413 m_client->setMouseOverURL(WebURL()); 414 415 mainFrameImpl()->frame()->eventHandler()->handleMouseMoveEvent( 416 PlatformMouseEventBuilder(mainFrameImpl()->frameView(), event)); 417 } 418 419 void WebViewImpl::mouseDown(const WebMouseEvent& event) 420 { 421 if (!mainFrameImpl() || !mainFrameImpl()->frameView()) 422 return; 423 424 // If there is a select popup open, close it as the user is clicking on 425 // the page (outside of the popup). We also save it so we can prevent a 426 // click on the select element from immediately reopening the popup. 427 RefPtr<WebCore::PopupContainer> selectPopup; 428 if (event.button == WebMouseEvent::ButtonLeft) { 429 selectPopup = m_selectPopup; 430 hideSelectPopup(); 431 ASSERT(!m_selectPopup); 432 } 433 434 m_lastMouseDownPoint = WebPoint(event.x, event.y); 435 436 RefPtr<Node> clickedNode; 437 if (event.button == WebMouseEvent::ButtonLeft) { 438 IntPoint point(event.x, event.y); 439 point = m_page->mainFrame()->view()->windowToContents(point); 440 HitTestResult result(m_page->mainFrame()->eventHandler()->hitTestResultAtPoint(point, false)); 441 Node* hitNode = result.innerNonSharedNode(); 442 443 // Take capture on a mouse down on a plugin so we can send it mouse events. 444 if (hitNode && hitNode->renderer() && hitNode->renderer()->isEmbeddedObject()) 445 m_mouseCaptureNode = hitNode; 446 447 // If a text field that has focus is clicked again, we should display the 448 // AutoFill popup. 449 RefPtr<Node> focusedNode = focusedWebCoreNode(); 450 if (focusedNode.get() && toHTMLInputElement(focusedNode.get())) { 451 if (hitNode == focusedNode) { 452 // Already focused text field was clicked, let's remember this. If 453 // focus has not changed after the mouse event is processed, we'll 454 // trigger the autocomplete. 455 clickedNode = focusedNode; 456 } 457 } 458 } 459 460 mainFrameImpl()->frame()->loader()->resetMultipleFormSubmissionProtection(); 461 462 mainFrameImpl()->frame()->eventHandler()->handleMousePressEvent( 463 PlatformMouseEventBuilder(mainFrameImpl()->frameView(), event)); 464 465 if (clickedNode.get() && clickedNode == focusedWebCoreNode()) { 466 // Focus has not changed, show the AutoFill popup. 467 static_cast<EditorClientImpl*>(m_page->editorClient())-> 468 showFormAutofillForNode(clickedNode.get()); 469 } 470 if (m_selectPopup && m_selectPopup == selectPopup) { 471 // That click triggered a select popup which is the same as the one that 472 // was showing before the click. It means the user clicked the select 473 // while the popup was showing, and as a result we first closed then 474 // immediately reopened the select popup. It needs to be closed. 475 hideSelectPopup(); 476 } 477 478 // Dispatch the contextmenu event regardless of if the click was swallowed. 479 // On Windows, we handle it on mouse up, not down. 480 #if OS(DARWIN) 481 if (event.button == WebMouseEvent::ButtonRight 482 || (event.button == WebMouseEvent::ButtonLeft 483 && event.modifiers & WebMouseEvent::ControlKey)) 484 mouseContextMenu(event); 485 #elif OS(LINUX) || OS(FREEBSD) 486 if (event.button == WebMouseEvent::ButtonRight) 487 mouseContextMenu(event); 488 #endif 489 } 490 491 void WebViewImpl::mouseContextMenu(const WebMouseEvent& event) 492 { 493 if (!mainFrameImpl() || !mainFrameImpl()->frameView()) 494 return; 495 496 m_page->contextMenuController()->clearContextMenu(); 497 498 PlatformMouseEventBuilder pme(mainFrameImpl()->frameView(), event); 499 500 // Find the right target frame. See issue 1186900. 501 HitTestResult result = hitTestResultForWindowPos(pme.pos()); 502 Frame* targetFrame; 503 if (result.innerNonSharedNode()) 504 targetFrame = result.innerNonSharedNode()->document()->frame(); 505 else 506 targetFrame = m_page->focusController()->focusedOrMainFrame(); 507 508 #if OS(WINDOWS) 509 targetFrame->view()->setCursor(pointerCursor()); 510 #endif 511 512 m_contextMenuAllowed = true; 513 targetFrame->eventHandler()->sendContextMenuEvent(pme); 514 m_contextMenuAllowed = false; 515 // Actually showing the context menu is handled by the ContextMenuClient 516 // implementation... 517 } 518 519 void WebViewImpl::mouseUp(const WebMouseEvent& event) 520 { 521 if (!mainFrameImpl() || !mainFrameImpl()->frameView()) 522 return; 523 524 #if OS(LINUX) || OS(FREEBSD) 525 // If the event was a middle click, attempt to copy text into the focused 526 // frame. We execute this before we let the page have a go at the event 527 // because the page may change what is focused during in its event handler. 528 // 529 // This code is in the mouse up handler. There is some debate about putting 530 // this here, as opposed to the mouse down handler. 531 // xterm: pastes on up. 532 // GTK: pastes on down. 533 // Firefox: pastes on up. 534 // Midori: couldn't paste at all with 0.1.2 535 // 536 // There is something of a webcompat angle to this well, as highlighted by 537 // crbug.com/14608. Pages can clear text boxes 'onclick' and, if we paste on 538 // down then the text is pasted just before the onclick handler runs and 539 // clears the text box. So it's important this happens after the 540 // handleMouseReleaseEvent() earlier in this function 541 if (event.button == WebMouseEvent::ButtonMiddle) { 542 Frame* focused = focusedWebCoreFrame(); 543 FrameView* view = m_page->mainFrame()->view(); 544 IntPoint clickPoint(m_lastMouseDownPoint.x, m_lastMouseDownPoint.y); 545 IntPoint contentPoint = view->windowToContents(clickPoint); 546 HitTestResult hitTestResult = focused->eventHandler()->hitTestResultAtPoint(contentPoint, false, false, ShouldHitTestScrollbars); 547 // We don't want to send a paste when middle clicking a scroll bar or a 548 // link (which will navigate later in the code). The main scrollbars 549 // have to be handled separately. 550 if (!hitTestResult.scrollbar() && !hitTestResult.isLiveLink() && focused && !view->scrollbarAtPoint(clickPoint)) { 551 Editor* editor = focused->editor(); 552 Pasteboard* pasteboard = Pasteboard::generalPasteboard(); 553 bool oldSelectionMode = pasteboard->isSelectionMode(); 554 pasteboard->setSelectionMode(true); 555 editor->command(AtomicString("Paste")).execute(); 556 pasteboard->setSelectionMode(oldSelectionMode); 557 } 558 } 559 #endif 560 561 mainFrameImpl()->frame()->eventHandler()->handleMouseReleaseEvent( 562 PlatformMouseEventBuilder(mainFrameImpl()->frameView(), event)); 563 564 #if OS(WINDOWS) 565 // Dispatch the contextmenu event regardless of if the click was swallowed. 566 // On Mac/Linux, we handle it on mouse down, not up. 567 if (event.button == WebMouseEvent::ButtonRight) 568 mouseContextMenu(event); 569 #endif 570 } 571 572 bool WebViewImpl::mouseWheel(const WebMouseWheelEvent& event) 573 { 574 PlatformWheelEventBuilder platformEvent(mainFrameImpl()->frameView(), event); 575 return mainFrameImpl()->frame()->eventHandler()->handleWheelEvent(platformEvent); 576 } 577 578 bool WebViewImpl::keyEvent(const WebKeyboardEvent& event) 579 { 580 ASSERT((event.type == WebInputEvent::RawKeyDown) 581 || (event.type == WebInputEvent::KeyDown) 582 || (event.type == WebInputEvent::KeyUp)); 583 584 // Please refer to the comments explaining the m_suppressNextKeypressEvent 585 // member. 586 // The m_suppressNextKeypressEvent is set if the KeyDown is handled by 587 // Webkit. A keyDown event is typically associated with a keyPress(char) 588 // event and a keyUp event. We reset this flag here as this is a new keyDown 589 // event. 590 m_suppressNextKeypressEvent = false; 591 592 // Give any select popup a chance at consuming the key event. 593 if (selectPopupHandleKeyEvent(event)) 594 return true; 595 596 // Give Autocomplete a chance to consume the key events it is interested in. 597 if (autocompleteHandleKeyEvent(event)) 598 return true; 599 600 Frame* frame = focusedWebCoreFrame(); 601 if (!frame) 602 return false; 603 604 EventHandler* handler = frame->eventHandler(); 605 if (!handler) 606 return keyEventDefault(event); 607 608 #if OS(WINDOWS) || OS(LINUX) || OS(FREEBSD) 609 const WebInputEvent::Type contextMenuTriggeringEventType = 610 #if OS(WINDOWS) 611 WebInputEvent::KeyUp; 612 #elif OS(LINUX) || OS(FREEBSD) 613 WebInputEvent::RawKeyDown; 614 #endif 615 616 bool isUnmodifiedMenuKey = !(event.modifiers & WebInputEvent::InputModifiers) && event.windowsKeyCode == VKEY_APPS; 617 bool isShiftF10 = event.modifiers == WebInputEvent::ShiftKey && event.windowsKeyCode == VKEY_F10; 618 if ((isUnmodifiedMenuKey || isShiftF10) && event.type == contextMenuTriggeringEventType) { 619 sendContextMenuEvent(event); 620 return true; 621 } 622 #endif // OS(WINDOWS) || OS(LINUX) || OS(FREEBSD) 623 624 PlatformKeyboardEventBuilder evt(event); 625 626 if (handler->keyEvent(evt)) { 627 if (WebInputEvent::RawKeyDown == event.type) { 628 // Suppress the next keypress event unless the focused node is a plug-in node. 629 // (Flash needs these keypress events to handle non-US keyboards.) 630 Node* node = frame->document()->focusedNode(); 631 if (!node || !node->renderer() || !node->renderer()->isEmbeddedObject()) 632 m_suppressNextKeypressEvent = true; 633 } 634 return true; 635 } 636 637 return keyEventDefault(event); 638 } 639 640 bool WebViewImpl::selectPopupHandleKeyEvent(const WebKeyboardEvent& event) 641 { 642 if (!m_selectPopup) 643 return false; 644 645 return m_selectPopup->handleKeyEvent(PlatformKeyboardEventBuilder(event)); 646 } 647 648 bool WebViewImpl::autocompleteHandleKeyEvent(const WebKeyboardEvent& event) 649 { 650 if (!m_autoFillPopupShowing 651 // Home and End should be left to the text field to process. 652 || event.windowsKeyCode == VKEY_HOME 653 || event.windowsKeyCode == VKEY_END) 654 return false; 655 656 // Pressing delete triggers the removal of the selected suggestion from the DB. 657 if (event.windowsKeyCode == VKEY_DELETE 658 && m_autoFillPopup->selectedIndex() != -1) { 659 Node* node = focusedWebCoreNode(); 660 if (!node || (node->nodeType() != Node::ELEMENT_NODE)) { 661 ASSERT_NOT_REACHED(); 662 return false; 663 } 664 Element* element = static_cast<Element*>(node); 665 if (!element->hasLocalName(HTMLNames::inputTag)) { 666 ASSERT_NOT_REACHED(); 667 return false; 668 } 669 670 int selectedIndex = m_autoFillPopup->selectedIndex(); 671 672 if (!m_autoFillPopupClient->canRemoveSuggestionAtIndex(selectedIndex)) 673 return false; 674 675 WebString name = WebInputElement(static_cast<HTMLInputElement*>(element)).nameForAutofill(); 676 WebString value = m_autoFillPopupClient->itemText(selectedIndex); 677 m_autoFillClient->removeAutocompleteSuggestion(name, value); 678 // Update the entries in the currently showing popup to reflect the 679 // deletion. 680 m_autoFillPopupClient->removeSuggestionAtIndex(selectedIndex); 681 refreshAutoFillPopup(); 682 return false; 683 } 684 685 if (!m_autoFillPopup->isInterestedInEventForKey(event.windowsKeyCode)) 686 return false; 687 688 if (m_autoFillPopup->handleKeyEvent(PlatformKeyboardEventBuilder(event))) { 689 // We need to ignore the next Char event after this otherwise pressing 690 // enter when selecting an item in the menu will go to the page. 691 if (WebInputEvent::RawKeyDown == event.type) 692 m_suppressNextKeypressEvent = true; 693 return true; 694 } 695 696 return false; 697 } 698 699 bool WebViewImpl::charEvent(const WebKeyboardEvent& event) 700 { 701 ASSERT(event.type == WebInputEvent::Char); 702 703 // Please refer to the comments explaining the m_suppressNextKeypressEvent 704 // member. The m_suppressNextKeypressEvent is set if the KeyDown is 705 // handled by Webkit. A keyDown event is typically associated with a 706 // keyPress(char) event and a keyUp event. We reset this flag here as it 707 // only applies to the current keyPress event. 708 bool suppress = m_suppressNextKeypressEvent; 709 m_suppressNextKeypressEvent = false; 710 711 Frame* frame = focusedWebCoreFrame(); 712 if (!frame) 713 return suppress; 714 715 EventHandler* handler = frame->eventHandler(); 716 if (!handler) 717 return suppress || keyEventDefault(event); 718 719 PlatformKeyboardEventBuilder evt(event); 720 if (!evt.isCharacterKey()) 721 return true; 722 723 // Accesskeys are triggered by char events and can't be suppressed. 724 if (handler->handleAccessKey(evt)) 725 return true; 726 727 // Safari 3.1 does not pass off windows system key messages (WM_SYSCHAR) to 728 // the eventHandler::keyEvent. We mimic this behavior on all platforms since 729 // for now we are converting other platform's key events to windows key 730 // events. 731 if (evt.isSystemKey()) 732 return false; 733 734 if (!suppress && !handler->keyEvent(evt)) 735 return keyEventDefault(event); 736 737 return true; 738 } 739 740 #if ENABLE(TOUCH_EVENTS) 741 bool WebViewImpl::touchEvent(const WebTouchEvent& event) 742 { 743 if (!mainFrameImpl() || !mainFrameImpl()->frameView()) 744 return false; 745 746 PlatformTouchEventBuilder touchEventBuilder(mainFrameImpl()->frameView(), event); 747 return mainFrameImpl()->frame()->eventHandler()->handleTouchEvent(touchEventBuilder); 748 } 749 #endif 750 751 #if OS(WINDOWS) || OS(LINUX) || OS(FREEBSD) 752 // Mac has no way to open a context menu based on a keyboard event. 753 bool WebViewImpl::sendContextMenuEvent(const WebKeyboardEvent& event) 754 { 755 // The contextMenuController() holds onto the last context menu that was 756 // popped up on the page until a new one is created. We need to clear 757 // this menu before propagating the event through the DOM so that we can 758 // detect if we create a new menu for this event, since we won't create 759 // a new menu if the DOM swallows the event and the defaultEventHandler does 760 // not run. 761 page()->contextMenuController()->clearContextMenu(); 762 763 m_contextMenuAllowed = true; 764 Frame* focusedFrame = page()->focusController()->focusedOrMainFrame(); 765 bool handled = focusedFrame->eventHandler()->sendContextMenuEventForKey(); 766 m_contextMenuAllowed = false; 767 return handled; 768 } 769 #endif 770 771 bool WebViewImpl::keyEventDefault(const WebKeyboardEvent& event) 772 { 773 Frame* frame = focusedWebCoreFrame(); 774 if (!frame) 775 return false; 776 777 switch (event.type) { 778 case WebInputEvent::Char: 779 if (event.windowsKeyCode == VKEY_SPACE) { 780 int keyCode = ((event.modifiers & WebInputEvent::ShiftKey) ? VKEY_PRIOR : VKEY_NEXT); 781 return scrollViewWithKeyboard(keyCode, event.modifiers); 782 } 783 break; 784 case WebInputEvent::RawKeyDown: 785 if (event.modifiers == WebInputEvent::ControlKey) { 786 switch (event.windowsKeyCode) { 787 #if !OS(DARWIN) 788 case 'A': 789 focusedFrame()->executeCommand(WebString::fromUTF8("SelectAll")); 790 return true; 791 case VKEY_INSERT: 792 case 'C': 793 focusedFrame()->executeCommand(WebString::fromUTF8("Copy")); 794 return true; 795 #endif 796 // Match FF behavior in the sense that Ctrl+home/end are the only Ctrl 797 // key combinations which affect scrolling. Safari is buggy in the 798 // sense that it scrolls the page for all Ctrl+scrolling key 799 // combinations. For e.g. Ctrl+pgup/pgdn/up/down, etc. 800 case VKEY_HOME: 801 case VKEY_END: 802 break; 803 default: 804 return false; 805 } 806 } 807 if (!event.isSystemKey && !(event.modifiers & WebInputEvent::ShiftKey)) 808 return scrollViewWithKeyboard(event.windowsKeyCode, event.modifiers); 809 break; 810 default: 811 break; 812 } 813 return false; 814 } 815 816 bool WebViewImpl::scrollViewWithKeyboard(int keyCode, int modifiers) 817 { 818 ScrollDirection scrollDirection; 819 ScrollGranularity scrollGranularity; 820 #if OS(DARWIN) 821 // Control-Up/Down should be PageUp/Down on Mac. 822 if (modifiers & WebMouseEvent::ControlKey) { 823 if (keyCode == VKEY_UP) 824 keyCode = VKEY_PRIOR; 825 else if (keyCode == VKEY_DOWN) 826 keyCode = VKEY_NEXT; 827 } 828 #endif 829 if (!mapKeyCodeForScroll(keyCode, &scrollDirection, &scrollGranularity)) 830 return false; 831 return propagateScroll(scrollDirection, scrollGranularity); 832 } 833 834 bool WebViewImpl::mapKeyCodeForScroll(int keyCode, 835 WebCore::ScrollDirection* scrollDirection, 836 WebCore::ScrollGranularity* scrollGranularity) 837 { 838 switch (keyCode) { 839 case VKEY_LEFT: 840 *scrollDirection = ScrollLeft; 841 *scrollGranularity = ScrollByLine; 842 break; 843 case VKEY_RIGHT: 844 *scrollDirection = ScrollRight; 845 *scrollGranularity = ScrollByLine; 846 break; 847 case VKEY_UP: 848 *scrollDirection = ScrollUp; 849 *scrollGranularity = ScrollByLine; 850 break; 851 case VKEY_DOWN: 852 *scrollDirection = ScrollDown; 853 *scrollGranularity = ScrollByLine; 854 break; 855 case VKEY_HOME: 856 *scrollDirection = ScrollUp; 857 *scrollGranularity = ScrollByDocument; 858 break; 859 case VKEY_END: 860 *scrollDirection = ScrollDown; 861 *scrollGranularity = ScrollByDocument; 862 break; 863 case VKEY_PRIOR: // page up 864 *scrollDirection = ScrollUp; 865 *scrollGranularity = ScrollByPage; 866 break; 867 case VKEY_NEXT: // page down 868 *scrollDirection = ScrollDown; 869 *scrollGranularity = ScrollByPage; 870 break; 871 default: 872 return false; 873 } 874 875 return true; 876 } 877 878 void WebViewImpl::hideSelectPopup() 879 { 880 if (m_selectPopup.get()) 881 m_selectPopup->hidePopup(); 882 } 883 884 bool WebViewImpl::propagateScroll(ScrollDirection scrollDirection, 885 ScrollGranularity scrollGranularity) 886 { 887 Frame* frame = focusedWebCoreFrame(); 888 if (!frame) 889 return false; 890 891 bool scrollHandled = frame->eventHandler()->scrollOverflow(scrollDirection, scrollGranularity); 892 Frame* currentFrame = frame; 893 while (!scrollHandled && currentFrame) { 894 scrollHandled = currentFrame->view()->scroll(scrollDirection, scrollGranularity); 895 currentFrame = currentFrame->tree()->parent(); 896 } 897 return scrollHandled; 898 } 899 900 void WebViewImpl::popupOpened(WebCore::PopupContainer* popupContainer) 901 { 902 if (popupContainer->popupType() == WebCore::PopupContainer::Select) { 903 ASSERT(!m_selectPopup); 904 m_selectPopup = popupContainer; 905 } 906 } 907 908 void WebViewImpl::popupClosed(WebCore::PopupContainer* popupContainer) 909 { 910 if (popupContainer->popupType() == WebCore::PopupContainer::Select) { 911 ASSERT(m_selectPopup.get()); 912 m_selectPopup = 0; 913 } 914 } 915 916 void WebViewImpl::hideAutoFillPopup() 917 { 918 if (m_autoFillPopupShowing) { 919 m_autoFillPopup->hidePopup(); 920 m_autoFillPopupShowing = false; 921 } 922 } 923 924 Frame* WebViewImpl::focusedWebCoreFrame() const 925 { 926 return m_page.get() ? m_page->focusController()->focusedOrMainFrame() : 0; 927 } 928 929 WebViewImpl* WebViewImpl::fromPage(Page* page) 930 { 931 if (!page) 932 return 0; 933 934 ChromeClientImpl* chromeClient = static_cast<ChromeClientImpl*>(page->chrome()->client()); 935 return static_cast<WebViewImpl*>(chromeClient->webView()); 936 } 937 938 // WebWidget ------------------------------------------------------------------ 939 940 void WebViewImpl::close() 941 { 942 RefPtr<WebFrameImpl> mainFrameImpl; 943 944 if (m_page.get()) { 945 // Initiate shutdown for the entire frameset. This will cause a lot of 946 // notifications to be sent. 947 if (m_page->mainFrame()) { 948 mainFrameImpl = WebFrameImpl::fromFrame(m_page->mainFrame()); 949 m_page->mainFrame()->loader()->frameDetached(); 950 } 951 m_page.clear(); 952 } 953 954 // Should happen after m_page.clear(). 955 if (m_devToolsAgent.get()) 956 m_devToolsAgent.clear(); 957 958 // Reset the delegate to prevent notifications being sent as we're being 959 // deleted. 960 m_client = 0; 961 962 deref(); // Balances ref() acquired in WebView::create 963 } 964 965 void WebViewImpl::resize(const WebSize& newSize) 966 { 967 if (m_size == newSize) 968 return; 969 m_size = newSize; 970 971 if (mainFrameImpl()->frameView()) { 972 mainFrameImpl()->frameView()->resize(m_size.width, m_size.height); 973 mainFrameImpl()->frame()->eventHandler()->sendResizeEvent(); 974 } 975 976 if (m_client) { 977 if (isAcceleratedCompositingActive()) { 978 #if USE(ACCELERATED_COMPOSITING) 979 updateLayerRendererViewport(); 980 #endif 981 } else { 982 WebRect damagedRect(0, 0, m_size.width, m_size.height); 983 m_client->didInvalidateRect(damagedRect); 984 } 985 } 986 987 #if USE(ACCELERATED_COMPOSITING) 988 if (m_layerRenderer && isAcceleratedCompositingActive()) { 989 m_layerRenderer->resizeOnscreenContent(IntSize(std::max(1, m_size.width), 990 std::max(1, m_size.height))); 991 } 992 #endif 993 } 994 995 void WebViewImpl::animate() 996 { 997 #if ENABLE(REQUEST_ANIMATION_FRAME) 998 WebFrameImpl* webframe = mainFrameImpl(); 999 if (webframe) { 1000 FrameView* view = webframe->frameView(); 1001 if (view) 1002 view->serviceScriptedAnimations(convertSecondsToDOMTimeStamp(currentTime())); 1003 } 1004 #endif 1005 } 1006 1007 void WebViewImpl::layout() 1008 { 1009 1010 WebFrameImpl* webframe = mainFrameImpl(); 1011 if (webframe) { 1012 // In order for our child HWNDs (NativeWindowWidgets) to update properly, 1013 // they need to be told that we are updating the screen. The problem is 1014 // that the native widgets need to recalculate their clip region and not 1015 // overlap any of our non-native widgets. To force the resizing, call 1016 // setFrameRect(). This will be a quick operation for most frames, but 1017 // the NativeWindowWidgets will update a proper clipping region. 1018 FrameView* view = webframe->frameView(); 1019 if (view) 1020 view->setFrameRect(view->frameRect()); 1021 1022 // setFrameRect may have the side-effect of causing existing page 1023 // layout to be invalidated, so layout needs to be called last. 1024 1025 webframe->layout(); 1026 } 1027 } 1028 1029 #if USE(ACCELERATED_COMPOSITING) 1030 void WebViewImpl::doPixelReadbackToCanvas(WebCanvas* canvas, const IntRect& rect) 1031 { 1032 #if USE(SKIA) 1033 PlatformContextSkia context(canvas); 1034 1035 // PlatformGraphicsContext is actually a pointer to PlatformContextSkia 1036 GraphicsContext gc(reinterpret_cast<PlatformGraphicsContext*>(&context)); 1037 int bitmapHeight = canvas->getDevice()->accessBitmap(false).height(); 1038 #elif USE(CG) 1039 GraphicsContext gc(canvas); 1040 int bitmapHeight = CGBitmapContextGetHeight(reinterpret_cast<CGContextRef>(canvas)); 1041 #else 1042 notImplemented(); 1043 #endif 1044 // Compute rect to sample from inverted GPU buffer. 1045 IntRect invertRect(rect.x(), bitmapHeight - rect.maxY(), rect.width(), rect.height()); 1046 1047 OwnPtr<ImageBuffer> imageBuffer(ImageBuffer::create(rect.size())); 1048 RefPtr<ByteArray> pixelArray(ByteArray::create(rect.width() * rect.height() * 4)); 1049 if (imageBuffer.get() && pixelArray.get()) { 1050 m_layerRenderer->getFramebufferPixels(pixelArray->data(), invertRect); 1051 imageBuffer->putPremultipliedImageData(pixelArray.get(), rect.size(), IntRect(IntPoint(), rect.size()), IntPoint()); 1052 gc.save(); 1053 gc.translate(IntSize(0, bitmapHeight)); 1054 gc.scale(FloatSize(1.0f, -1.0f)); 1055 // Use invertRect in next line, so that transform above inverts it back to 1056 // desired destination rect. 1057 gc.drawImageBuffer(imageBuffer.get(), ColorSpaceDeviceRGB, invertRect.location()); 1058 gc.restore(); 1059 } 1060 } 1061 #endif 1062 1063 void WebViewImpl::paint(WebCanvas* canvas, const WebRect& rect) 1064 { 1065 if (isAcceleratedCompositingActive()) { 1066 #if USE(ACCELERATED_COMPOSITING) 1067 doComposite(); 1068 1069 // If a canvas was passed in, we use it to grab a copy of the 1070 // freshly-rendered pixels. 1071 if (canvas) { 1072 // Clip rect to the confines of the rootLayerTexture. 1073 IntRect resizeRect(rect); 1074 resizeRect.intersect(IntRect(IntPoint(), m_layerRenderer->viewportSize())); 1075 doPixelReadbackToCanvas(canvas, resizeRect); 1076 } 1077 #endif 1078 } else { 1079 WebFrameImpl* webframe = mainFrameImpl(); 1080 if (webframe) 1081 webframe->paint(canvas, rect); 1082 } 1083 } 1084 1085 void WebViewImpl::themeChanged() 1086 { 1087 if (!page()) 1088 return; 1089 FrameView* view = page()->mainFrame()->view(); 1090 1091 WebRect damagedRect(0, 0, m_size.width, m_size.height); 1092 view->invalidateRect(damagedRect); 1093 } 1094 1095 void WebViewImpl::composite(bool finish) 1096 { 1097 #if USE(ACCELERATED_COMPOSITING) 1098 TRACE_EVENT("WebViewImpl::composite", this, 0); 1099 if (m_recreatingGraphicsContext) { 1100 // reallocateRenderer will request a repaint whether or not it succeeded 1101 // in creating a new context. 1102 reallocateRenderer(); 1103 m_recreatingGraphicsContext = false; 1104 return; 1105 } 1106 doComposite(); 1107 1108 // Finish if requested. 1109 if (finish) 1110 m_layerRenderer->finish(); 1111 1112 // Put result onscreen. 1113 m_layerRenderer->present(); 1114 1115 GraphicsContext3D* context = m_layerRenderer->context(); 1116 if (context->getExtensions()->getGraphicsResetStatusARB() != GraphicsContext3D::NO_ERROR) { 1117 // Trying to recover the context right here will not work if GPU process 1118 // died. This is because GpuChannelHost::OnErrorMessage will only be 1119 // called at the next iteration of the message loop, reverting our 1120 // recovery attempts here. Instead, we detach the root layer from the 1121 // renderer, recreate the renderer at the next message loop iteration 1122 // and request a repaint yet again. 1123 m_recreatingGraphicsContext = true; 1124 setRootLayerNeedsDisplay(); 1125 } 1126 #endif 1127 } 1128 1129 const WebInputEvent* WebViewImpl::m_currentInputEvent = 0; 1130 1131 bool WebViewImpl::handleInputEvent(const WebInputEvent& inputEvent) 1132 { 1133 UserGestureIndicator gestureIndicator(WebInputEvent::isUserGestureEventType(inputEvent.type) ? DefinitelyProcessingUserGesture : PossiblyProcessingUserGesture); 1134 1135 // If we've started a drag and drop operation, ignore input events until 1136 // we're done. 1137 if (m_doingDragAndDrop) 1138 return true; 1139 1140 if (m_ignoreInputEvents) 1141 return true; 1142 1143 m_currentInputEvent = &inputEvent; 1144 1145 if (m_mouseCaptureNode.get() && WebInputEvent::isMouseEventType(inputEvent.type)) { 1146 // Save m_mouseCaptureNode since mouseCaptureLost() will clear it. 1147 RefPtr<Node> node = m_mouseCaptureNode; 1148 1149 // Not all platforms call mouseCaptureLost() directly. 1150 if (inputEvent.type == WebInputEvent::MouseUp) 1151 mouseCaptureLost(); 1152 1153 AtomicString eventType; 1154 switch (inputEvent.type) { 1155 case WebInputEvent::MouseMove: 1156 eventType = eventNames().mousemoveEvent; 1157 break; 1158 case WebInputEvent::MouseLeave: 1159 eventType = eventNames().mouseoutEvent; 1160 break; 1161 case WebInputEvent::MouseDown: 1162 eventType = eventNames().mousedownEvent; 1163 break; 1164 case WebInputEvent::MouseUp: 1165 eventType = eventNames().mouseupEvent; 1166 break; 1167 default: 1168 ASSERT_NOT_REACHED(); 1169 } 1170 1171 node->dispatchMouseEvent( 1172 PlatformMouseEventBuilder(mainFrameImpl()->frameView(), *static_cast<const WebMouseEvent*>(&inputEvent)), 1173 eventType, static_cast<const WebMouseEvent*>(&inputEvent)->clickCount); 1174 m_currentInputEvent = 0; 1175 return true; 1176 } 1177 1178 bool handled = true; 1179 1180 // FIXME: WebKit seems to always return false on mouse events processing 1181 // methods. For now we'll assume it has processed them (as we are only 1182 // interested in whether keyboard events are processed). 1183 switch (inputEvent.type) { 1184 case WebInputEvent::MouseMove: 1185 mouseMove(*static_cast<const WebMouseEvent*>(&inputEvent)); 1186 break; 1187 1188 case WebInputEvent::MouseLeave: 1189 mouseLeave(*static_cast<const WebMouseEvent*>(&inputEvent)); 1190 break; 1191 1192 case WebInputEvent::MouseWheel: 1193 handled = mouseWheel(*static_cast<const WebMouseWheelEvent*>(&inputEvent)); 1194 break; 1195 1196 case WebInputEvent::MouseDown: 1197 mouseDown(*static_cast<const WebMouseEvent*>(&inputEvent)); 1198 break; 1199 1200 case WebInputEvent::MouseUp: 1201 mouseUp(*static_cast<const WebMouseEvent*>(&inputEvent)); 1202 break; 1203 1204 case WebInputEvent::RawKeyDown: 1205 case WebInputEvent::KeyDown: 1206 case WebInputEvent::KeyUp: 1207 handled = keyEvent(*static_cast<const WebKeyboardEvent*>(&inputEvent)); 1208 break; 1209 1210 case WebInputEvent::Char: 1211 handled = charEvent(*static_cast<const WebKeyboardEvent*>(&inputEvent)); 1212 break; 1213 1214 #if ENABLE(TOUCH_EVENTS) 1215 case WebInputEvent::TouchStart: 1216 case WebInputEvent::TouchMove: 1217 case WebInputEvent::TouchEnd: 1218 case WebInputEvent::TouchCancel: 1219 handled = touchEvent(*static_cast<const WebTouchEvent*>(&inputEvent)); 1220 break; 1221 #endif 1222 1223 default: 1224 handled = false; 1225 } 1226 1227 m_currentInputEvent = 0; 1228 1229 return handled; 1230 } 1231 1232 void WebViewImpl::mouseCaptureLost() 1233 { 1234 m_mouseCaptureNode = 0; 1235 } 1236 1237 void WebViewImpl::setFocus(bool enable) 1238 { 1239 m_page->focusController()->setFocused(enable); 1240 if (enable) { 1241 // Note that we don't call setActive() when disabled as this cause extra 1242 // focus/blur events to be dispatched. 1243 m_page->focusController()->setActive(true); 1244 RefPtr<Frame> focusedFrame = m_page->focusController()->focusedFrame(); 1245 if (focusedFrame) { 1246 Node* focusedNode = focusedFrame->document()->focusedNode(); 1247 if (focusedNode && focusedNode->isElementNode() 1248 && focusedFrame->selection()->selection().isNone()) { 1249 // If the selection was cleared while the WebView was not 1250 // focused, then the focus element shows with a focus ring but 1251 // no caret and does respond to keyboard inputs. 1252 Element* element = static_cast<Element*>(focusedNode); 1253 if (element->isTextFormControl()) 1254 element->updateFocusAppearance(true); 1255 else if (focusedNode->isContentEditable()) { 1256 // updateFocusAppearance() selects all the text of 1257 // contentseditable DIVs. So we set the selection explicitly 1258 // instead. Note that this has the side effect of moving the 1259 // caret back to the beginning of the text. 1260 Position position(focusedNode, 0, 1261 Position::PositionIsOffsetInAnchor); 1262 focusedFrame->selection()->setSelection( 1263 VisibleSelection(position, SEL_DEFAULT_AFFINITY)); 1264 } 1265 } 1266 } 1267 m_imeAcceptEvents = true; 1268 } else { 1269 hideAutoFillPopup(); 1270 hideSelectPopup(); 1271 1272 // Clear focus on the currently focused frame if any. 1273 if (!m_page.get()) 1274 return; 1275 1276 Frame* frame = m_page->mainFrame(); 1277 if (!frame) 1278 return; 1279 1280 RefPtr<Frame> focusedFrame = m_page->focusController()->focusedFrame(); 1281 if (focusedFrame.get()) { 1282 // Finish an ongoing composition to delete the composition node. 1283 Editor* editor = focusedFrame->editor(); 1284 if (editor && editor->hasComposition()) 1285 editor->confirmComposition(); 1286 m_imeAcceptEvents = false; 1287 } 1288 } 1289 } 1290 1291 bool WebViewImpl::setComposition( 1292 const WebString& text, 1293 const WebVector<WebCompositionUnderline>& underlines, 1294 int selectionStart, 1295 int selectionEnd) 1296 { 1297 Frame* focused = focusedWebCoreFrame(); 1298 if (!focused || !m_imeAcceptEvents) 1299 return false; 1300 Editor* editor = focused->editor(); 1301 if (!editor) 1302 return false; 1303 1304 // The input focus has been moved to another WebWidget object. 1305 // We should use this |editor| object only to complete the ongoing 1306 // composition. 1307 if (!editor->canEdit() && !editor->hasComposition()) 1308 return false; 1309 1310 // We should verify the parent node of this IME composition node are 1311 // editable because JavaScript may delete a parent node of the composition 1312 // node. In this case, WebKit crashes while deleting texts from the parent 1313 // node, which doesn't exist any longer. 1314 PassRefPtr<Range> range = editor->compositionRange(); 1315 if (range) { 1316 const Node* node = range->startContainer(); 1317 if (!node || !node->isContentEditable()) 1318 return false; 1319 } 1320 1321 // If we're not going to fire a keypress event, then the keydown event was 1322 // canceled. In that case, cancel any existing composition. 1323 if (text.isEmpty() || m_suppressNextKeypressEvent) { 1324 // A browser process sent an IPC message which does not contain a valid 1325 // string, which means an ongoing composition has been canceled. 1326 // If the ongoing composition has been canceled, replace the ongoing 1327 // composition string with an empty string and complete it. 1328 String emptyString; 1329 Vector<CompositionUnderline> emptyUnderlines; 1330 editor->setComposition(emptyString, emptyUnderlines, 0, 0); 1331 return text.isEmpty(); 1332 } 1333 1334 // When the range of composition underlines overlap with the range between 1335 // selectionStart and selectionEnd, WebKit somehow won't paint the selection 1336 // at all (see InlineTextBox::paint() function in InlineTextBox.cpp). 1337 // But the selection range actually takes effect. 1338 editor->setComposition(String(text), 1339 CompositionUnderlineVectorBuilder(underlines), 1340 selectionStart, selectionEnd); 1341 1342 return editor->hasComposition(); 1343 } 1344 1345 bool WebViewImpl::confirmComposition() 1346 { 1347 return confirmComposition(WebString()); 1348 } 1349 1350 bool WebViewImpl::confirmComposition(const WebString& text) 1351 { 1352 Frame* focused = focusedWebCoreFrame(); 1353 if (!focused || !m_imeAcceptEvents) 1354 return false; 1355 Editor* editor = focused->editor(); 1356 if (!editor || (!editor->hasComposition() && !text.length())) 1357 return false; 1358 1359 // We should verify the parent node of this IME composition node are 1360 // editable because JavaScript may delete a parent node of the composition 1361 // node. In this case, WebKit crashes while deleting texts from the parent 1362 // node, which doesn't exist any longer. 1363 PassRefPtr<Range> range = editor->compositionRange(); 1364 if (range) { 1365 const Node* node = range->startContainer(); 1366 if (!node || !node->isContentEditable()) 1367 return false; 1368 } 1369 1370 if (editor->hasComposition()) { 1371 if (text.length()) 1372 editor->confirmComposition(String(text)); 1373 else 1374 editor->confirmComposition(); 1375 } else 1376 editor->insertText(String(text), 0); 1377 1378 return true; 1379 } 1380 1381 WebTextInputType WebViewImpl::textInputType() 1382 { 1383 WebTextInputType type = WebTextInputTypeNone; 1384 const Frame* focused = focusedWebCoreFrame(); 1385 if (!focused) 1386 return type; 1387 1388 const Editor* editor = focused->editor(); 1389 if (!editor || !editor->canEdit()) 1390 return type; 1391 1392 SelectionController* controller = focused->selection(); 1393 if (!controller) 1394 return type; 1395 1396 const Node* node = controller->start().deprecatedNode(); 1397 if (!node) 1398 return type; 1399 1400 // FIXME: Support more text input types when necessary, eg. Number, 1401 // Date, Email, URL, etc. 1402 if (controller->isInPasswordField()) 1403 type = WebTextInputTypePassword; 1404 else if (node->shouldUseInputMethod()) 1405 type = WebTextInputTypeText; 1406 1407 return type; 1408 } 1409 1410 WebRect WebViewImpl::caretOrSelectionBounds() 1411 { 1412 WebRect rect; 1413 const Frame* focused = focusedWebCoreFrame(); 1414 if (!focused) 1415 return rect; 1416 1417 SelectionController* controller = focused->selection(); 1418 if (!controller) 1419 return rect; 1420 1421 const FrameView* view = focused->view(); 1422 if (!view) 1423 return rect; 1424 1425 const Node* node = controller->base().containerNode(); 1426 if (!node || !node->renderer()) 1427 return rect; 1428 1429 if (controller->isCaret()) 1430 rect = view->contentsToWindow(controller->absoluteCaretBounds()); 1431 else if (controller->isRange()) { 1432 node = controller->extent().containerNode(); 1433 RefPtr<Range> range = controller->toNormalizedRange(); 1434 if (!node || !node->renderer() || !range) 1435 return rect; 1436 rect = view->contentsToWindow(focused->editor()->firstRectForRange(range.get())); 1437 } 1438 return rect; 1439 } 1440 1441 bool WebViewImpl::selectionRange(WebPoint& start, WebPoint& end) const 1442 { 1443 const Frame* frame = focusedWebCoreFrame(); 1444 if (!frame) 1445 return false; 1446 RefPtr<Range> selectedRange = frame->selection()->toNormalizedRange(); 1447 RefPtr<Range> range(Range::create(selectedRange->startContainer()->document(), 1448 selectedRange->startContainer(), 1449 selectedRange->startOffset(), 1450 selectedRange->startContainer(), 1451 selectedRange->startOffset())); 1452 1453 IntRect rect = frame->editor()->firstRectForRange(range.get()); 1454 start.x = rect.x(); 1455 start.y = rect.y() + rect.height() - 1; 1456 1457 range = Range::create(selectedRange->endContainer()->document(), 1458 selectedRange->endContainer(), 1459 selectedRange->endOffset(), 1460 selectedRange->endContainer(), 1461 selectedRange->endOffset()); 1462 1463 rect = frame->editor()->firstRectForRange(range.get()); 1464 end.x = rect.x() + rect.width() - 1; 1465 end.y = rect.y() + rect.height() - 1; 1466 1467 start = frame->view()->contentsToWindow(start); 1468 end = frame->view()->contentsToWindow(end); 1469 return true; 1470 } 1471 1472 void WebViewImpl::setTextDirection(WebTextDirection direction) 1473 { 1474 // The Editor::setBaseWritingDirection() function checks if we can change 1475 // the text direction of the selected node and updates its DOM "dir" 1476 // attribute and its CSS "direction" property. 1477 // So, we just call the function as Safari does. 1478 const Frame* focused = focusedWebCoreFrame(); 1479 if (!focused) 1480 return; 1481 1482 Editor* editor = focused->editor(); 1483 if (!editor || !editor->canEdit()) 1484 return; 1485 1486 switch (direction) { 1487 case WebTextDirectionDefault: 1488 editor->setBaseWritingDirection(NaturalWritingDirection); 1489 break; 1490 1491 case WebTextDirectionLeftToRight: 1492 editor->setBaseWritingDirection(LeftToRightWritingDirection); 1493 break; 1494 1495 case WebTextDirectionRightToLeft: 1496 editor->setBaseWritingDirection(RightToLeftWritingDirection); 1497 break; 1498 1499 default: 1500 notImplemented(); 1501 break; 1502 } 1503 } 1504 1505 bool WebViewImpl::isAcceleratedCompositingActive() const 1506 { 1507 #if USE(ACCELERATED_COMPOSITING) 1508 return m_isAcceleratedCompositingActive; 1509 #else 1510 return false; 1511 #endif 1512 } 1513 1514 // WebView -------------------------------------------------------------------- 1515 1516 WebSettings* WebViewImpl::settings() 1517 { 1518 if (!m_webSettings.get()) 1519 m_webSettings.set(new WebSettingsImpl(m_page->settings())); 1520 ASSERT(m_webSettings.get()); 1521 return m_webSettings.get(); 1522 } 1523 1524 WebString WebViewImpl::pageEncoding() const 1525 { 1526 if (!m_page.get()) 1527 return WebString(); 1528 1529 return m_page->mainFrame()->document()->loader()->writer()->encoding(); 1530 } 1531 1532 void WebViewImpl::setPageEncoding(const WebString& encodingName) 1533 { 1534 if (!m_page.get()) 1535 return; 1536 1537 // Only change override encoding, don't change default encoding. 1538 // Note that the new encoding must be 0 if it isn't supposed to be set. 1539 String newEncodingName; 1540 if (!encodingName.isEmpty()) 1541 newEncodingName = encodingName; 1542 m_page->mainFrame()->loader()->reloadWithOverrideEncoding(newEncodingName); 1543 } 1544 1545 bool WebViewImpl::dispatchBeforeUnloadEvent() 1546 { 1547 // FIXME: This should really cause a recursive depth-first walk of all 1548 // frames in the tree, calling each frame's onbeforeunload. At the moment, 1549 // we're consistent with Safari 3.1, not IE/FF. 1550 Frame* frame = m_page->mainFrame(); 1551 if (!frame) 1552 return true; 1553 1554 return frame->loader()->shouldClose(); 1555 } 1556 1557 void WebViewImpl::dispatchUnloadEvent() 1558 { 1559 // Run unload handlers. 1560 m_page->mainFrame()->loader()->closeURL(); 1561 } 1562 1563 WebFrame* WebViewImpl::mainFrame() 1564 { 1565 return mainFrameImpl(); 1566 } 1567 1568 WebFrame* WebViewImpl::findFrameByName( 1569 const WebString& name, WebFrame* relativeToFrame) 1570 { 1571 if (!relativeToFrame) 1572 relativeToFrame = mainFrame(); 1573 Frame* frame = static_cast<WebFrameImpl*>(relativeToFrame)->frame(); 1574 frame = frame->tree()->find(name); 1575 return WebFrameImpl::fromFrame(frame); 1576 } 1577 1578 WebFrame* WebViewImpl::focusedFrame() 1579 { 1580 return WebFrameImpl::fromFrame(focusedWebCoreFrame()); 1581 } 1582 1583 void WebViewImpl::setFocusedFrame(WebFrame* frame) 1584 { 1585 if (!frame) { 1586 // Clears the focused frame if any. 1587 Frame* frame = focusedWebCoreFrame(); 1588 if (frame) 1589 frame->selection()->setFocused(false); 1590 return; 1591 } 1592 WebFrameImpl* frameImpl = static_cast<WebFrameImpl*>(frame); 1593 Frame* webcoreFrame = frameImpl->frame(); 1594 webcoreFrame->page()->focusController()->setFocusedFrame(webcoreFrame); 1595 } 1596 1597 void WebViewImpl::setInitialFocus(bool reverse) 1598 { 1599 if (!m_page.get()) 1600 return; 1601 1602 // Since we don't have a keyboard event, we'll create one. 1603 WebKeyboardEvent keyboardEvent; 1604 keyboardEvent.type = WebInputEvent::RawKeyDown; 1605 if (reverse) 1606 keyboardEvent.modifiers = WebInputEvent::ShiftKey; 1607 1608 // VK_TAB which is only defined on Windows. 1609 keyboardEvent.windowsKeyCode = 0x09; 1610 PlatformKeyboardEventBuilder platformEvent(keyboardEvent); 1611 RefPtr<KeyboardEvent> webkitEvent = KeyboardEvent::create(platformEvent, 0); 1612 1613 Frame* frame = page()->focusController()->focusedOrMainFrame(); 1614 if (Document* document = frame->document()) 1615 document->setFocusedNode(0); 1616 page()->focusController()->setInitialFocus( 1617 reverse ? FocusDirectionBackward : FocusDirectionForward, 1618 webkitEvent.get()); 1619 } 1620 1621 void WebViewImpl::clearFocusedNode() 1622 { 1623 if (!m_page.get()) 1624 return; 1625 1626 RefPtr<Frame> frame = m_page->mainFrame(); 1627 if (!frame.get()) 1628 return; 1629 1630 RefPtr<Document> document = frame->document(); 1631 if (!document.get()) 1632 return; 1633 1634 RefPtr<Node> oldFocusedNode = document->focusedNode(); 1635 1636 // Clear the focused node. 1637 document->setFocusedNode(0); 1638 1639 if (!oldFocusedNode.get()) 1640 return; 1641 1642 // If a text field has focus, we need to make sure the selection controller 1643 // knows to remove selection from it. Otherwise, the text field is still 1644 // processing keyboard events even though focus has been moved to the page and 1645 // keystrokes get eaten as a result. 1646 if (oldFocusedNode->hasTagName(HTMLNames::textareaTag) 1647 || (oldFocusedNode->hasTagName(HTMLNames::inputTag) 1648 && static_cast<HTMLInputElement*>(oldFocusedNode.get())->isTextField())) { 1649 // Clear the selection. 1650 SelectionController* selection = frame->selection(); 1651 selection->clear(); 1652 } 1653 } 1654 1655 void WebViewImpl::scrollFocusedNodeIntoView() 1656 { 1657 Node* focusedNode = focusedWebCoreNode(); 1658 if (focusedNode && focusedNode->isElementNode()) { 1659 Element* elementNode = static_cast<Element*>(focusedNode); 1660 elementNode->scrollIntoViewIfNeeded(true); 1661 } 1662 } 1663 1664 double WebViewImpl::zoomLevel() 1665 { 1666 return m_zoomLevel; 1667 } 1668 1669 double WebViewImpl::setZoomLevel(bool textOnly, double zoomLevel) 1670 { 1671 if (zoomLevel < m_minimumZoomLevel) 1672 m_zoomLevel = m_minimumZoomLevel; 1673 else if (zoomLevel > m_maximumZoomLevel) 1674 m_zoomLevel = m_maximumZoomLevel; 1675 else 1676 m_zoomLevel = zoomLevel; 1677 1678 Frame* frame = mainFrameImpl()->frame(); 1679 WebPluginContainerImpl* pluginContainer = WebFrameImpl::pluginContainerFromFrame(frame); 1680 if (pluginContainer) 1681 pluginContainer->plugin()->setZoomLevel(m_zoomLevel, textOnly); 1682 else { 1683 float zoomFactor = static_cast<float>(zoomLevelToZoomFactor(m_zoomLevel)); 1684 if (textOnly) 1685 frame->setPageAndTextZoomFactors(1, zoomFactor); 1686 else 1687 frame->setPageAndTextZoomFactors(zoomFactor, 1); 1688 } 1689 return m_zoomLevel; 1690 } 1691 1692 void WebViewImpl::zoomLimitsChanged(double minimumZoomLevel, 1693 double maximumZoomLevel) 1694 { 1695 m_minimumZoomLevel = minimumZoomLevel; 1696 m_maximumZoomLevel = maximumZoomLevel; 1697 m_client->zoomLimitsChanged(m_minimumZoomLevel, m_maximumZoomLevel); 1698 } 1699 1700 void WebViewImpl::fullFramePluginZoomLevelChanged(double zoomLevel) 1701 { 1702 if (zoomLevel == m_zoomLevel) 1703 return; 1704 1705 m_zoomLevel = std::max(std::min(zoomLevel, m_maximumZoomLevel), m_minimumZoomLevel); 1706 m_client->zoomLevelChanged(); 1707 } 1708 1709 double WebView::zoomLevelToZoomFactor(double zoomLevel) 1710 { 1711 return std::pow(textSizeMultiplierRatio, zoomLevel); 1712 } 1713 1714 double WebView::zoomFactorToZoomLevel(double factor) 1715 { 1716 // Since factor = 1.2^level, level = log(factor) / log(1.2) 1717 return log(factor) / log(textSizeMultiplierRatio); 1718 } 1719 1720 void WebViewImpl::performMediaPlayerAction(const WebMediaPlayerAction& action, 1721 const WebPoint& location) 1722 { 1723 HitTestResult result = 1724 hitTestResultForWindowPos(location); 1725 RefPtr<Node> node = result.innerNonSharedNode(); 1726 if (!node->hasTagName(HTMLNames::videoTag) && !node->hasTagName(HTMLNames::audioTag)) 1727 return; 1728 1729 RefPtr<HTMLMediaElement> mediaElement = 1730 static_pointer_cast<HTMLMediaElement>(node); 1731 switch (action.type) { 1732 case WebMediaPlayerAction::Play: 1733 if (action.enable) 1734 mediaElement->play(mediaElement->processingUserGesture()); 1735 else 1736 mediaElement->pause(mediaElement->processingUserGesture()); 1737 break; 1738 case WebMediaPlayerAction::Mute: 1739 mediaElement->setMuted(action.enable); 1740 break; 1741 case WebMediaPlayerAction::Loop: 1742 mediaElement->setLoop(action.enable); 1743 break; 1744 case WebMediaPlayerAction::Controls: 1745 mediaElement->setControls(action.enable); 1746 break; 1747 default: 1748 ASSERT_NOT_REACHED(); 1749 } 1750 } 1751 1752 void WebViewImpl::copyImageAt(const WebPoint& point) 1753 { 1754 if (!m_page.get()) 1755 return; 1756 1757 HitTestResult result = hitTestResultForWindowPos(point); 1758 1759 if (result.absoluteImageURL().isEmpty()) { 1760 // There isn't actually an image at these coordinates. Might be because 1761 // the window scrolled while the context menu was open or because the page 1762 // changed itself between when we thought there was an image here and when 1763 // we actually tried to retreive the image. 1764 // 1765 // FIXME: implement a cache of the most recent HitTestResult to avoid having 1766 // to do two hit tests. 1767 return; 1768 } 1769 1770 m_page->mainFrame()->editor()->copyImage(result); 1771 } 1772 1773 void WebViewImpl::dragSourceEndedAt( 1774 const WebPoint& clientPoint, 1775 const WebPoint& screenPoint, 1776 WebDragOperation operation) 1777 { 1778 PlatformMouseEvent pme(clientPoint, 1779 screenPoint, 1780 LeftButton, MouseEventMoved, 0, false, false, false, 1781 false, 0); 1782 m_page->mainFrame()->eventHandler()->dragSourceEndedAt(pme, 1783 static_cast<DragOperation>(operation)); 1784 m_dragScrollTimer->stop(); 1785 } 1786 1787 void WebViewImpl::dragSourceMovedTo( 1788 const WebPoint& clientPoint, 1789 const WebPoint& screenPoint, 1790 WebDragOperation operation) 1791 { 1792 m_dragScrollTimer->triggerScroll(mainFrameImpl()->frameView(), clientPoint); 1793 } 1794 1795 void WebViewImpl::dragSourceSystemDragEnded() 1796 { 1797 // It's possible for us to get this callback while not doing a drag if 1798 // it's from a previous page that got unloaded. 1799 if (m_doingDragAndDrop) { 1800 m_page->dragController()->dragEnded(); 1801 m_doingDragAndDrop = false; 1802 } 1803 } 1804 1805 WebDragOperation WebViewImpl::dragTargetDragEnter( 1806 const WebDragData& webDragData, 1807 const WebPoint& clientPoint, 1808 const WebPoint& screenPoint, 1809 WebDragOperationsMask operationsAllowed) 1810 { 1811 ASSERT(!m_currentDragData.get()); 1812 1813 m_currentDragData = webDragData; 1814 m_operationsAllowed = operationsAllowed; 1815 1816 return dragTargetDragEnterOrOver(clientPoint, screenPoint, DragEnter); 1817 } 1818 1819 WebDragOperation WebViewImpl::dragTargetDragOver( 1820 const WebPoint& clientPoint, 1821 const WebPoint& screenPoint, 1822 WebDragOperationsMask operationsAllowed) 1823 { 1824 m_operationsAllowed = operationsAllowed; 1825 1826 return dragTargetDragEnterOrOver(clientPoint, screenPoint, DragOver); 1827 } 1828 1829 void WebViewImpl::dragTargetDragLeave() 1830 { 1831 ASSERT(m_currentDragData.get()); 1832 1833 DragData dragData( 1834 m_currentDragData.get(), 1835 IntPoint(), 1836 IntPoint(), 1837 static_cast<DragOperation>(m_operationsAllowed)); 1838 1839 m_page->dragController()->dragExited(&dragData); 1840 1841 // FIXME: why is the drag scroll timer not stopped here? 1842 1843 m_dragOperation = WebDragOperationNone; 1844 m_currentDragData = 0; 1845 } 1846 1847 void WebViewImpl::dragTargetDrop(const WebPoint& clientPoint, 1848 const WebPoint& screenPoint) 1849 { 1850 ASSERT(m_currentDragData.get()); 1851 1852 // If this webview transitions from the "drop accepting" state to the "not 1853 // accepting" state, then our IPC message reply indicating that may be in- 1854 // flight, or else delayed by javascript processing in this webview. If a 1855 // drop happens before our IPC reply has reached the browser process, then 1856 // the browser forwards the drop to this webview. So only allow a drop to 1857 // proceed if our webview m_dragOperation state is not DragOperationNone. 1858 1859 if (m_dragOperation == WebDragOperationNone) { // IPC RACE CONDITION: do not allow this drop. 1860 dragTargetDragLeave(); 1861 return; 1862 } 1863 1864 DragData dragData( 1865 m_currentDragData.get(), 1866 clientPoint, 1867 screenPoint, 1868 static_cast<DragOperation>(m_operationsAllowed)); 1869 1870 m_page->dragController()->performDrag(&dragData); 1871 1872 m_dragOperation = WebDragOperationNone; 1873 m_currentDragData = 0; 1874 1875 m_dragScrollTimer->stop(); 1876 } 1877 1878 WebDragOperation WebViewImpl::dragTargetDragEnterOrOver(const WebPoint& clientPoint, const WebPoint& screenPoint, DragAction dragAction) 1879 { 1880 ASSERT(m_currentDragData.get()); 1881 1882 DragData dragData( 1883 m_currentDragData.get(), 1884 clientPoint, 1885 screenPoint, 1886 static_cast<DragOperation>(m_operationsAllowed)); 1887 1888 DragOperation dropEffect; 1889 if (dragAction == DragEnter) 1890 dropEffect = m_page->dragController()->dragEntered(&dragData); 1891 else 1892 dropEffect = m_page->dragController()->dragUpdated(&dragData); 1893 1894 // Mask the drop effect operation against the drag source's allowed operations. 1895 if (!(dropEffect & dragData.draggingSourceOperationMask())) 1896 dropEffect = DragOperationNone; 1897 1898 m_dragOperation = static_cast<WebDragOperation>(dropEffect); 1899 1900 if (dragAction == DragOver) 1901 m_dragScrollTimer->triggerScroll(mainFrameImpl()->frameView(), clientPoint); 1902 else 1903 m_dragScrollTimer->stop(); 1904 1905 return m_dragOperation; 1906 } 1907 1908 unsigned long WebViewImpl::createUniqueIdentifierForRequest() 1909 { 1910 if (m_page) 1911 return m_page->progress()->createUniqueIdentifier(); 1912 return 0; 1913 } 1914 1915 void WebViewImpl::inspectElementAt(const WebPoint& point) 1916 { 1917 if (!m_page.get()) 1918 return; 1919 1920 if (point.x == -1 || point.y == -1) 1921 m_page->inspectorController()->inspect(0); 1922 else { 1923 HitTestResult result = hitTestResultForWindowPos(point); 1924 1925 if (!result.innerNonSharedNode()) 1926 return; 1927 1928 m_page->inspectorController()->inspect(result.innerNonSharedNode()); 1929 } 1930 } 1931 1932 WebString WebViewImpl::inspectorSettings() const 1933 { 1934 return m_inspectorSettings; 1935 } 1936 1937 void WebViewImpl::setInspectorSettings(const WebString& settings) 1938 { 1939 m_inspectorSettings = settings; 1940 } 1941 1942 bool WebViewImpl::inspectorSetting(const WebString& key, WebString* value) const 1943 { 1944 if (!m_inspectorSettingsMap->contains(key)) 1945 return false; 1946 *value = m_inspectorSettingsMap->get(key); 1947 return true; 1948 } 1949 1950 void WebViewImpl::setInspectorSetting(const WebString& key, 1951 const WebString& value) 1952 { 1953 m_inspectorSettingsMap->set(key, value); 1954 client()->didUpdateInspectorSetting(key, value); 1955 } 1956 1957 WebDevToolsAgent* WebViewImpl::devToolsAgent() 1958 { 1959 return m_devToolsAgent.get(); 1960 } 1961 1962 WebAccessibilityObject WebViewImpl::accessibilityObject() 1963 { 1964 if (!mainFrameImpl()) 1965 return WebAccessibilityObject(); 1966 1967 Document* document = mainFrameImpl()->frame()->document(); 1968 return WebAccessibilityObject( 1969 document->axObjectCache()->getOrCreate(document->renderer())); 1970 } 1971 1972 void WebViewImpl::applyAutoFillSuggestions( 1973 const WebNode& node, 1974 const WebVector<WebString>& names, 1975 const WebVector<WebString>& labels, 1976 const WebVector<WebString>& icons, 1977 const WebVector<int>& uniqueIDs, 1978 int separatorIndex) 1979 { 1980 ASSERT(names.size() == labels.size()); 1981 ASSERT(names.size() == uniqueIDs.size()); 1982 ASSERT(separatorIndex < static_cast<int>(names.size())); 1983 1984 if (names.isEmpty()) { 1985 hideAutoFillPopup(); 1986 return; 1987 } 1988 1989 RefPtr<Node> focusedNode = focusedWebCoreNode(); 1990 // If the node for which we queried the AutoFill suggestions is not the 1991 // focused node, then we have nothing to do. FIXME: also check the 1992 // caret is at the end and that the text has not changed. 1993 if (!focusedNode || focusedNode != PassRefPtr<Node>(node)) { 1994 hideAutoFillPopup(); 1995 return; 1996 } 1997 1998 HTMLInputElement* inputElem = 1999 static_cast<HTMLInputElement*>(focusedNode.get()); 2000 2001 // The first time the AutoFill popup is shown we'll create the client and 2002 // the popup. 2003 if (!m_autoFillPopupClient.get()) 2004 m_autoFillPopupClient.set(new AutoFillPopupMenuClient); 2005 2006 m_autoFillPopupClient->initialize( 2007 inputElem, names, labels, icons, uniqueIDs, separatorIndex); 2008 2009 if (!m_autoFillPopup.get()) { 2010 m_autoFillPopup = PopupContainer::create(m_autoFillPopupClient.get(), 2011 PopupContainer::Suggestion, 2012 autoFillPopupSettings); 2013 } 2014 2015 if (m_autoFillPopupShowing) { 2016 refreshAutoFillPopup(); 2017 } else { 2018 m_autoFillPopup->showInRect(focusedNode->getRect(), focusedNode->ownerDocument()->view(), 0); 2019 m_autoFillPopupShowing = true; 2020 } 2021 } 2022 2023 void WebViewImpl::hidePopups() 2024 { 2025 hideSelectPopup(); 2026 hideAutoFillPopup(); 2027 } 2028 2029 void WebViewImpl::performCustomContextMenuAction(unsigned action) 2030 { 2031 if (!m_page) 2032 return; 2033 ContextMenu* menu = m_page->contextMenuController()->contextMenu(); 2034 if (!menu) 2035 return; 2036 ContextMenuItem* item = menu->itemWithAction(static_cast<ContextMenuAction>(ContextMenuItemBaseCustomTag + action)); 2037 if (item) 2038 m_page->contextMenuController()->contextMenuItemSelected(item); 2039 m_page->contextMenuController()->clearContextMenu(); 2040 } 2041 2042 // WebView -------------------------------------------------------------------- 2043 2044 void WebViewImpl::setIsTransparent(bool isTransparent) 2045 { 2046 // Set any existing frames to be transparent. 2047 Frame* frame = m_page->mainFrame(); 2048 while (frame) { 2049 frame->view()->setTransparent(isTransparent); 2050 frame = frame->tree()->traverseNext(); 2051 } 2052 2053 // Future frames check this to know whether to be transparent. 2054 m_isTransparent = isTransparent; 2055 } 2056 2057 bool WebViewImpl::isTransparent() const 2058 { 2059 return m_isTransparent; 2060 } 2061 2062 void WebViewImpl::setIsActive(bool active) 2063 { 2064 if (page() && page()->focusController()) 2065 page()->focusController()->setActive(active); 2066 } 2067 2068 bool WebViewImpl::isActive() const 2069 { 2070 return (page() && page()->focusController()) ? page()->focusController()->isActive() : false; 2071 } 2072 2073 void WebViewImpl::setDomainRelaxationForbidden(bool forbidden, const WebString& scheme) 2074 { 2075 SecurityOrigin::setDomainRelaxationForbiddenForURLScheme(forbidden, String(scheme)); 2076 } 2077 2078 void WebViewImpl::setScrollbarColors(unsigned inactiveColor, 2079 unsigned activeColor, 2080 unsigned trackColor) { 2081 #if OS(LINUX) || OS(FREEBSD) 2082 PlatformThemeChromiumGtk::setScrollbarColors(inactiveColor, 2083 activeColor, 2084 trackColor); 2085 #endif 2086 } 2087 2088 void WebViewImpl::setSelectionColors(unsigned activeBackgroundColor, 2089 unsigned activeForegroundColor, 2090 unsigned inactiveBackgroundColor, 2091 unsigned inactiveForegroundColor) { 2092 #if OS(LINUX) || OS(FREEBSD) 2093 RenderThemeChromiumLinux::setSelectionColors(activeBackgroundColor, 2094 activeForegroundColor, 2095 inactiveBackgroundColor, 2096 inactiveForegroundColor); 2097 theme()->platformColorsDidChange(); 2098 #endif 2099 } 2100 2101 void WebView::addUserScript(const WebString& sourceCode, 2102 const WebVector<WebString>& patternsIn, 2103 WebView::UserScriptInjectAt injectAt, 2104 WebView::UserContentInjectIn injectIn) 2105 { 2106 OwnPtr<Vector<String> > patterns(new Vector<String>); 2107 for (size_t i = 0; i < patternsIn.size(); ++i) 2108 patterns->append(patternsIn[i]); 2109 2110 PageGroup* pageGroup = PageGroup::pageGroup(pageGroupName); 2111 RefPtr<DOMWrapperWorld> world(DOMWrapperWorld::create()); 2112 pageGroup->addUserScriptToWorld(world.get(), sourceCode, WebURL(), patterns.release(), 0, 2113 static_cast<UserScriptInjectionTime>(injectAt), 2114 static_cast<UserContentInjectedFrames>(injectIn)); 2115 } 2116 2117 void WebView::addUserStyleSheet(const WebString& sourceCode, 2118 const WebVector<WebString>& patternsIn, 2119 WebView::UserContentInjectIn injectIn, 2120 WebView::UserStyleInjectionTime injectionTime) 2121 { 2122 OwnPtr<Vector<String> > patterns(new Vector<String>); 2123 for (size_t i = 0; i < patternsIn.size(); ++i) 2124 patterns->append(patternsIn[i]); 2125 2126 PageGroup* pageGroup = PageGroup::pageGroup(pageGroupName); 2127 RefPtr<DOMWrapperWorld> world(DOMWrapperWorld::create()); 2128 2129 // FIXME: Current callers always want the level to be "author". It probably makes sense to let 2130 // callers specify this though, since in other cases the caller will probably want "user" level. 2131 // 2132 // FIXME: It would be nice to populate the URL correctly, instead of passing an empty URL. 2133 pageGroup->addUserStyleSheetToWorld(world.get(), sourceCode, WebURL(), patterns.release(), 0, 2134 static_cast<UserContentInjectedFrames>(injectIn), 2135 UserStyleAuthorLevel, 2136 static_cast<WebCore::UserStyleInjectionTime>(injectionTime)); 2137 } 2138 2139 void WebView::removeAllUserContent() 2140 { 2141 PageGroup* pageGroup = PageGroup::pageGroup(pageGroupName); 2142 pageGroup->removeAllUserContent(); 2143 } 2144 2145 void WebViewImpl::didCommitLoad(bool* isNewNavigation) 2146 { 2147 if (isNewNavigation) 2148 *isNewNavigation = m_observedNewNavigation; 2149 2150 #ifndef NDEBUG 2151 ASSERT(!m_observedNewNavigation 2152 || m_page->mainFrame()->loader()->documentLoader() == m_newNavigationLoader); 2153 m_newNavigationLoader = 0; 2154 #endif 2155 m_observedNewNavigation = false; 2156 } 2157 2158 bool WebViewImpl::useExternalPopupMenus() 2159 { 2160 return shouldUseExternalPopupMenus; 2161 } 2162 2163 bool WebViewImpl::navigationPolicyFromMouseEvent(unsigned short button, 2164 bool ctrl, bool shift, 2165 bool alt, bool meta, 2166 WebNavigationPolicy* policy) 2167 { 2168 #if OS(WINDOWS) || OS(LINUX) || OS(FREEBSD) || OS(SOLARIS) 2169 const bool newTabModifier = (button == 1) || ctrl; 2170 #elif OS(DARWIN) 2171 const bool newTabModifier = (button == 1) || meta; 2172 #endif 2173 if (!newTabModifier && !shift && !alt) 2174 return false; 2175 2176 ASSERT(policy); 2177 if (newTabModifier) { 2178 if (shift) 2179 *policy = WebNavigationPolicyNewForegroundTab; 2180 else 2181 *policy = WebNavigationPolicyNewBackgroundTab; 2182 } else { 2183 if (shift) 2184 *policy = WebNavigationPolicyNewWindow; 2185 else 2186 *policy = WebNavigationPolicyDownload; 2187 } 2188 return true; 2189 } 2190 2191 void WebViewImpl::startDragging(const WebDragData& dragData, 2192 WebDragOperationsMask mask, 2193 const WebImage& dragImage, 2194 const WebPoint& dragImageOffset) 2195 { 2196 if (!m_client) 2197 return; 2198 ASSERT(!m_doingDragAndDrop); 2199 m_doingDragAndDrop = true; 2200 m_client->startDragging(dragData, mask, dragImage, dragImageOffset); 2201 } 2202 2203 void WebViewImpl::observeNewNavigation() 2204 { 2205 m_observedNewNavigation = true; 2206 #ifndef NDEBUG 2207 m_newNavigationLoader = m_page->mainFrame()->loader()->documentLoader(); 2208 #endif 2209 } 2210 2211 void WebViewImpl::setIgnoreInputEvents(bool newValue) 2212 { 2213 ASSERT(m_ignoreInputEvents != newValue); 2214 m_ignoreInputEvents = newValue; 2215 } 2216 2217 #if ENABLE(NOTIFICATIONS) 2218 NotificationPresenterImpl* WebViewImpl::notificationPresenterImpl() 2219 { 2220 if (!m_notificationPresenter.isInitialized() && m_client) 2221 m_notificationPresenter.initialize(m_client->notificationPresenter()); 2222 return &m_notificationPresenter; 2223 } 2224 #endif 2225 2226 void WebViewImpl::refreshAutoFillPopup() 2227 { 2228 ASSERT(m_autoFillPopupShowing); 2229 2230 // Hide the popup if it has become empty. 2231 if (!m_autoFillPopupClient->listSize()) { 2232 hideAutoFillPopup(); 2233 return; 2234 } 2235 2236 IntRect oldBounds = m_autoFillPopup->frameRect(); 2237 m_autoFillPopup->refresh(focusedWebCoreNode()->getRect()); 2238 IntRect newBounds = m_autoFillPopup->frameRect(); 2239 // Let's resize the backing window if necessary. 2240 if (oldBounds != newBounds) { 2241 WebPopupMenuImpl* popupMenu = 2242 static_cast<WebPopupMenuImpl*>(m_autoFillPopup->client()); 2243 if (popupMenu) 2244 popupMenu->client()->setWindowRect(newBounds); 2245 } 2246 } 2247 2248 Node* WebViewImpl::focusedWebCoreNode() 2249 { 2250 Frame* frame = m_page->focusController()->focusedFrame(); 2251 if (!frame) 2252 return 0; 2253 2254 Document* document = frame->document(); 2255 if (!document) 2256 return 0; 2257 2258 return document->focusedNode(); 2259 } 2260 2261 HitTestResult WebViewImpl::hitTestResultForWindowPos(const IntPoint& pos) 2262 { 2263 IntPoint docPoint(m_page->mainFrame()->view()->windowToContents(pos)); 2264 return m_page->mainFrame()->eventHandler()->hitTestResultAtPoint(docPoint, false); 2265 } 2266 2267 void WebViewImpl::setTabsToLinks(bool enable) 2268 { 2269 m_tabsToLinks = enable; 2270 } 2271 2272 bool WebViewImpl::tabsToLinks() const 2273 { 2274 return m_tabsToLinks; 2275 } 2276 2277 #if USE(ACCELERATED_COMPOSITING) 2278 bool WebViewImpl::allowsAcceleratedCompositing() 2279 { 2280 return !m_compositorCreationFailed; 2281 } 2282 2283 bool WebViewImpl::pageHasRTLStyle() const 2284 { 2285 if (!page()) 2286 return false; 2287 Document* document = page()->mainFrame()->document(); 2288 if (!document) 2289 return false; 2290 RenderView* renderView = document->renderView(); 2291 if (!renderView) 2292 return false; 2293 RenderStyle* style = renderView->style(); 2294 if (!style) 2295 return false; 2296 return (style->direction() == RTL); 2297 } 2298 2299 void WebViewImpl::setRootGraphicsLayer(WebCore::PlatformLayer* layer) 2300 { 2301 setIsAcceleratedCompositingActive(layer); 2302 if (m_layerRenderer) 2303 m_layerRenderer->setRootLayer(layer); 2304 2305 IntRect damagedRect(0, 0, m_size.width, m_size.height); 2306 if (m_isAcceleratedCompositingActive) 2307 invalidateRootLayerRect(damagedRect); 2308 else 2309 m_client->didInvalidateRect(damagedRect); 2310 } 2311 2312 void WebViewImpl::setRootLayerNeedsDisplay() 2313 { 2314 m_client->scheduleComposite(); 2315 } 2316 2317 2318 void WebViewImpl::scrollRootLayerRect(const IntSize& scrollDelta, const IntRect& clipRect) 2319 { 2320 updateLayerRendererViewport(); 2321 setRootLayerNeedsDisplay(); 2322 } 2323 2324 void WebViewImpl::invalidateRootLayerRect(const IntRect& rect) 2325 { 2326 ASSERT(m_layerRenderer); 2327 2328 if (!page()) 2329 return; 2330 2331 FrameView* view = page()->mainFrame()->view(); 2332 IntRect dirtyRect = view->windowToContents(rect); 2333 updateLayerRendererViewport(); 2334 m_layerRenderer->invalidateRootLayerRect(dirtyRect); 2335 setRootLayerNeedsDisplay(); 2336 } 2337 2338 class WebViewImplContentPainter : public TilePaintInterface { 2339 WTF_MAKE_NONCOPYABLE(WebViewImplContentPainter); 2340 public: 2341 static PassOwnPtr<WebViewImplContentPainter*> create(WebViewImpl* webViewImpl) 2342 { 2343 return adoptPtr(new WebViewImplContentPainter(webViewImpl)); 2344 } 2345 2346 virtual void paint(GraphicsContext& context, const IntRect& contentRect) 2347 { 2348 Page* page = m_webViewImpl->page(); 2349 if (!page) 2350 return; 2351 FrameView* view = page->mainFrame()->view(); 2352 view->paintContents(&context, contentRect); 2353 } 2354 2355 private: 2356 explicit WebViewImplContentPainter(WebViewImpl* webViewImpl) 2357 : m_webViewImpl(webViewImpl) 2358 { 2359 } 2360 2361 WebViewImpl* m_webViewImpl; 2362 }; 2363 2364 void WebViewImpl::setIsAcceleratedCompositingActive(bool active) 2365 { 2366 PlatformBridge::histogramEnumeration("GPU.setIsAcceleratedCompositingActive", active * 2 + m_isAcceleratedCompositingActive, 4); 2367 2368 if (m_isAcceleratedCompositingActive == active) 2369 return; 2370 2371 if (!active) { 2372 m_isAcceleratedCompositingActive = false; 2373 // We need to finish all GL rendering before sending 2374 // didActivateAcceleratedCompositing(false) to prevent 2375 // flickering when compositing turns off. 2376 if (m_layerRenderer) 2377 m_layerRenderer->finish(); 2378 m_client->didActivateAcceleratedCompositing(false); 2379 } else if (m_layerRenderer) { 2380 m_isAcceleratedCompositingActive = true; 2381 m_layerRenderer->resizeOnscreenContent(WebCore::IntSize(std::max(1, m_size.width), 2382 std::max(1, m_size.height))); 2383 2384 m_client->didActivateAcceleratedCompositing(true); 2385 } else { 2386 RefPtr<GraphicsContext3D> context = m_temporaryOnscreenGraphicsContext3D.release(); 2387 if (!context) { 2388 context = GraphicsContext3D::create(getCompositorContextAttributes(), m_page->chrome(), GraphicsContext3D::RenderDirectlyToHostWindow); 2389 if (context) 2390 context->reshape(std::max(1, m_size.width), std::max(1, m_size.height)); 2391 } 2392 2393 2394 m_layerRenderer = LayerRendererChromium::create(context.release(), WebViewImplContentPainter::create(this)); 2395 if (m_layerRenderer) { 2396 m_client->didActivateAcceleratedCompositing(true); 2397 m_isAcceleratedCompositingActive = true; 2398 m_compositorCreationFailed = false; 2399 } else { 2400 m_isAcceleratedCompositingActive = false; 2401 m_client->didActivateAcceleratedCompositing(false); 2402 m_compositorCreationFailed = true; 2403 } 2404 } 2405 if (page()) 2406 page()->mainFrame()->view()->setClipsRepaints(!m_isAcceleratedCompositingActive); 2407 } 2408 2409 void WebViewImpl::doComposite() 2410 { 2411 ASSERT(m_layerRenderer); 2412 if (!m_layerRenderer) { 2413 setIsAcceleratedCompositingActive(false); 2414 return; 2415 } 2416 2417 ASSERT(isAcceleratedCompositingActive()); 2418 if (!page()) 2419 return; 2420 2421 m_layerRenderer->setCompositeOffscreen(settings()->compositeToTextureEnabled()); 2422 2423 CCHeadsUpDisplay* hud = m_layerRenderer->headsUpDisplay(); 2424 hud->setShowFPSCounter(settings()->showFPSCounter()); 2425 hud->setShowPlatformLayerTree(settings()->showPlatformLayerTree()); 2426 2427 m_layerRenderer->updateAndDrawLayers(); 2428 } 2429 2430 void WebViewImpl::reallocateRenderer() 2431 { 2432 RefPtr<GraphicsContext3D> newContext = m_temporaryOnscreenGraphicsContext3D.get(); 2433 WebGraphicsContext3D* webContext = GraphicsContext3DInternal::extractWebGraphicsContext3D(newContext.get()); 2434 if (!newContext || !webContext || webContext->isContextLost()) 2435 newContext = GraphicsContext3D::create( 2436 getCompositorContextAttributes(), m_page->chrome(), GraphicsContext3D::RenderDirectlyToHostWindow); 2437 // GraphicsContext3D::create might fail and return 0, in that case LayerRendererChromium::create will also return 0. 2438 RefPtr<LayerRendererChromium> layerRenderer = LayerRendererChromium::create(newContext, WebViewImplContentPainter::create(this)); 2439 2440 // Reattach the root layer. Child layers will get reattached as a side effect of updateLayersRecursive. 2441 if (layerRenderer) { 2442 m_layerRenderer->transferRootLayer(layerRenderer.get()); 2443 m_layerRenderer = layerRenderer; 2444 // FIXME: In MacOS newContext->reshape method needs to be called to 2445 // allocate IOSurfaces. All calls to create a context followed by 2446 // reshape should really be extracted into one function; it is not 2447 // immediately obvious that GraphicsContext3D object will not 2448 // function properly until its reshape method is called. 2449 newContext->reshape(std::max(1, m_size.width), std::max(1, m_size.height)); 2450 setRootGraphicsLayer(m_layerRenderer->rootLayer()); 2451 // Forces ViewHostMsg_DidActivateAcceleratedCompositing to be sent so 2452 // that the browser process can reacquire surfaces. 2453 m_client->didActivateAcceleratedCompositing(true); 2454 } else 2455 setRootGraphicsLayer(0); 2456 } 2457 #endif 2458 2459 void WebViewImpl::updateLayerRendererViewport() 2460 { 2461 ASSERT(m_layerRenderer); 2462 2463 if (!page()) 2464 return; 2465 2466 FrameView* view = page()->mainFrame()->view(); 2467 IntRect contentRect = view->visibleContentRect(false); 2468 IntRect visibleRect = view->visibleContentRect(true); 2469 IntPoint scroll(view->scrollX(), view->scrollY()); 2470 2471 m_layerRenderer->setViewport(visibleRect, contentRect, scroll); 2472 } 2473 2474 WebGraphicsContext3D* WebViewImpl::graphicsContext3D() 2475 { 2476 #if USE(ACCELERATED_COMPOSITING) 2477 if (m_page->settings()->acceleratedCompositingEnabled() && allowsAcceleratedCompositing()) { 2478 if (m_layerRenderer) { 2479 WebGraphicsContext3D* webContext = GraphicsContext3DInternal::extractWebGraphicsContext3D(m_layerRenderer->context()); 2480 if (webContext && !webContext->isContextLost()) 2481 return webContext; 2482 } 2483 if (m_temporaryOnscreenGraphicsContext3D) { 2484 WebGraphicsContext3D* webContext = GraphicsContext3DInternal::extractWebGraphicsContext3D(m_temporaryOnscreenGraphicsContext3D.get()); 2485 if (webContext && !webContext->isContextLost()) 2486 return webContext; 2487 } 2488 m_temporaryOnscreenGraphicsContext3D = GraphicsContext3D::create(getCompositorContextAttributes(), m_page->chrome(), GraphicsContext3D::RenderDirectlyToHostWindow); 2489 if (m_temporaryOnscreenGraphicsContext3D) 2490 m_temporaryOnscreenGraphicsContext3D->reshape(std::max(1, m_size.width), std::max(1, m_size.height)); 2491 return GraphicsContext3DInternal::extractWebGraphicsContext3D(m_temporaryOnscreenGraphicsContext3D.get()); 2492 } 2493 #endif 2494 return 0; 2495 } 2496 2497 } // namespace WebKit 2498