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 147using namespace WebCore; 148 149namespace { 150 151GraphicsContext3D::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 170namespace 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 176const double WebView::textSizeMultiplierRatio = 1.2; 177const double WebView::minTextSizeMultiplier = 0.5; 178const 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. 185const 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. 189static 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) 195COMPILE_ASSERT_MATCHING_ENUM(DragOperationNone); 196COMPILE_ASSERT_MATCHING_ENUM(DragOperationCopy); 197COMPILE_ASSERT_MATCHING_ENUM(DragOperationLink); 198COMPILE_ASSERT_MATCHING_ENUM(DragOperationGeneric); 199COMPILE_ASSERT_MATCHING_ENUM(DragOperationPrivate); 200COMPILE_ASSERT_MATCHING_ENUM(DragOperationMove); 201COMPILE_ASSERT_MATCHING_ENUM(DragOperationDelete); 202COMPILE_ASSERT_MATCHING_ENUM(DragOperationEvery); 203 204static 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 212static bool shouldUseExternalPopupMenus = false; 213 214// WebView ---------------------------------------------------------------- 215 216WebView* 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 225void WebView::setUseExternalPopupMenus(bool useExternalPopupMenus) 226{ 227 shouldUseExternalPopupMenus = useExternalPopupMenus; 228} 229 230void WebView::updateVisitedLinkState(unsigned long long linkHash) 231{ 232 Page::visitedStateChanged(PageGroup::pageGroup(pageGroupName), linkHash); 233} 234 235void WebView::resetVisitedLinkState() 236{ 237 Page::allVisitedStateChanged(PageGroup::pageGroup(pageGroupName)); 238} 239 240void 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 253void WebView::didExitModalLoop() 254{ 255 ASSERT(pageGroupLoadDeferrerStack.size()); 256 257 delete pageGroupLoadDeferrerStack.last(); 258 pageGroupLoadDeferrerStack.removeLast(); 259} 260 261void 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 274void WebViewImpl::setDevToolsAgentClient(WebDevToolsAgentClient* devToolsClient) 275{ 276 if (devToolsClient) 277 m_devToolsAgent = new WebDevToolsAgentImpl(this, devToolsClient); 278 else 279 m_devToolsAgent.clear(); 280} 281 282void WebViewImpl::setAutoFillClient(WebAutoFillClient* autoFillClient) 283{ 284 m_autoFillClient = autoFillClient; 285} 286 287void WebViewImpl::setSpellCheckClient(WebSpellCheckClient* spellCheckClient) 288{ 289 m_spellCheckClient = spellCheckClient; 290} 291 292WebViewImpl::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 365WebViewImpl::~WebViewImpl() 366{ 367 ASSERT(!m_page); 368} 369 370RenderTheme* WebViewImpl::theme() const 371{ 372 return m_page.get() ? m_page->theme() : RenderTheme::defaultTheme().get(); 373} 374 375WebFrameImpl* WebViewImpl::mainFrameImpl() 376{ 377 return m_page.get() ? WebFrameImpl::fromFrame(m_page->mainFrame()) : 0; 378} 379 380bool WebViewImpl::tabKeyCyclesThroughElements() const 381{ 382 ASSERT(m_page.get()); 383 return m_page->tabKeyCyclesThroughElements(); 384} 385 386void WebViewImpl::setTabKeyCyclesThroughElements(bool value) 387{ 388 if (m_page) 389 m_page->setTabKeyCyclesThroughElements(value); 390} 391 392void 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 406void 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 419void 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 491void 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 519void 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 572bool WebViewImpl::mouseWheel(const WebMouseWheelEvent& event) 573{ 574 PlatformWheelEventBuilder platformEvent(mainFrameImpl()->frameView(), event); 575 return mainFrameImpl()->frame()->eventHandler()->handleWheelEvent(platformEvent); 576} 577 578bool 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 640bool WebViewImpl::selectPopupHandleKeyEvent(const WebKeyboardEvent& event) 641{ 642 if (!m_selectPopup) 643 return false; 644 645 return m_selectPopup->handleKeyEvent(PlatformKeyboardEventBuilder(event)); 646} 647 648bool 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 699bool 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) 741bool 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. 753bool 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 771bool 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 816bool 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 834bool 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 878void WebViewImpl::hideSelectPopup() 879{ 880 if (m_selectPopup.get()) 881 m_selectPopup->hidePopup(); 882} 883 884bool 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 900void WebViewImpl::popupOpened(WebCore::PopupContainer* popupContainer) 901{ 902 if (popupContainer->popupType() == WebCore::PopupContainer::Select) { 903 ASSERT(!m_selectPopup); 904 m_selectPopup = popupContainer; 905 } 906} 907 908void 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 916void WebViewImpl::hideAutoFillPopup() 917{ 918 if (m_autoFillPopupShowing) { 919 m_autoFillPopup->hidePopup(); 920 m_autoFillPopupShowing = false; 921 } 922} 923 924Frame* WebViewImpl::focusedWebCoreFrame() const 925{ 926 return m_page.get() ? m_page->focusController()->focusedOrMainFrame() : 0; 927} 928 929WebViewImpl* 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 940void 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 965void 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 995void 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 1007void 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) 1030void 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 1063void 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 1085void 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 1095void 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 1129const WebInputEvent* WebViewImpl::m_currentInputEvent = 0; 1130 1131bool 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 1232void WebViewImpl::mouseCaptureLost() 1233{ 1234 m_mouseCaptureNode = 0; 1235} 1236 1237void 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 1291bool 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 1345bool WebViewImpl::confirmComposition() 1346{ 1347 return confirmComposition(WebString()); 1348} 1349 1350bool 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 1381WebTextInputType 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 1410WebRect 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 1441bool 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 1472void 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 1505bool 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 1516WebSettings* 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 1524WebString WebViewImpl::pageEncoding() const 1525{ 1526 if (!m_page.get()) 1527 return WebString(); 1528 1529 return m_page->mainFrame()->document()->loader()->writer()->encoding(); 1530} 1531 1532void 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 1545bool 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 1557void WebViewImpl::dispatchUnloadEvent() 1558{ 1559 // Run unload handlers. 1560 m_page->mainFrame()->loader()->closeURL(); 1561} 1562 1563WebFrame* WebViewImpl::mainFrame() 1564{ 1565 return mainFrameImpl(); 1566} 1567 1568WebFrame* 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 1578WebFrame* WebViewImpl::focusedFrame() 1579{ 1580 return WebFrameImpl::fromFrame(focusedWebCoreFrame()); 1581} 1582 1583void 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 1597void 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 1621void 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 1655void 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 1664double WebViewImpl::zoomLevel() 1665{ 1666 return m_zoomLevel; 1667} 1668 1669double 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 1692void 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 1700void 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 1709double WebView::zoomLevelToZoomFactor(double zoomLevel) 1710{ 1711 return std::pow(textSizeMultiplierRatio, zoomLevel); 1712} 1713 1714double 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 1720void 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 1752void 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 1773void 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 1787void WebViewImpl::dragSourceMovedTo( 1788 const WebPoint& clientPoint, 1789 const WebPoint& screenPoint, 1790 WebDragOperation operation) 1791{ 1792 m_dragScrollTimer->triggerScroll(mainFrameImpl()->frameView(), clientPoint); 1793} 1794 1795void 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 1805WebDragOperation 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 1819WebDragOperation 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 1829void 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 1847void 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 1878WebDragOperation 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 1908unsigned long WebViewImpl::createUniqueIdentifierForRequest() 1909{ 1910 if (m_page) 1911 return m_page->progress()->createUniqueIdentifier(); 1912 return 0; 1913} 1914 1915void 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 1932WebString WebViewImpl::inspectorSettings() const 1933{ 1934 return m_inspectorSettings; 1935} 1936 1937void WebViewImpl::setInspectorSettings(const WebString& settings) 1938{ 1939 m_inspectorSettings = settings; 1940} 1941 1942bool 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 1950void WebViewImpl::setInspectorSetting(const WebString& key, 1951 const WebString& value) 1952{ 1953 m_inspectorSettingsMap->set(key, value); 1954 client()->didUpdateInspectorSetting(key, value); 1955} 1956 1957WebDevToolsAgent* WebViewImpl::devToolsAgent() 1958{ 1959 return m_devToolsAgent.get(); 1960} 1961 1962WebAccessibilityObject 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 1972void 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 2023void WebViewImpl::hidePopups() 2024{ 2025 hideSelectPopup(); 2026 hideAutoFillPopup(); 2027} 2028 2029void 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 2044void 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 2057bool WebViewImpl::isTransparent() const 2058{ 2059 return m_isTransparent; 2060} 2061 2062void WebViewImpl::setIsActive(bool active) 2063{ 2064 if (page() && page()->focusController()) 2065 page()->focusController()->setActive(active); 2066} 2067 2068bool WebViewImpl::isActive() const 2069{ 2070 return (page() && page()->focusController()) ? page()->focusController()->isActive() : false; 2071} 2072 2073void WebViewImpl::setDomainRelaxationForbidden(bool forbidden, const WebString& scheme) 2074{ 2075 SecurityOrigin::setDomainRelaxationForbiddenForURLScheme(forbidden, String(scheme)); 2076} 2077 2078void 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 2088void 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 2101void 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 2117void 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 2139void WebView::removeAllUserContent() 2140{ 2141 PageGroup* pageGroup = PageGroup::pageGroup(pageGroupName); 2142 pageGroup->removeAllUserContent(); 2143} 2144 2145void 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 2158bool WebViewImpl::useExternalPopupMenus() 2159{ 2160 return shouldUseExternalPopupMenus; 2161} 2162 2163bool 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 2191void 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 2203void WebViewImpl::observeNewNavigation() 2204{ 2205 m_observedNewNavigation = true; 2206#ifndef NDEBUG 2207 m_newNavigationLoader = m_page->mainFrame()->loader()->documentLoader(); 2208#endif 2209} 2210 2211void WebViewImpl::setIgnoreInputEvents(bool newValue) 2212{ 2213 ASSERT(m_ignoreInputEvents != newValue); 2214 m_ignoreInputEvents = newValue; 2215} 2216 2217#if ENABLE(NOTIFICATIONS) 2218NotificationPresenterImpl* 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 2226void 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 2248Node* 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 2261HitTestResult 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 2267void WebViewImpl::setTabsToLinks(bool enable) 2268{ 2269 m_tabsToLinks = enable; 2270} 2271 2272bool WebViewImpl::tabsToLinks() const 2273{ 2274 return m_tabsToLinks; 2275} 2276 2277#if USE(ACCELERATED_COMPOSITING) 2278bool WebViewImpl::allowsAcceleratedCompositing() 2279{ 2280 return !m_compositorCreationFailed; 2281} 2282 2283bool 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 2299void 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 2312void WebViewImpl::setRootLayerNeedsDisplay() 2313{ 2314 m_client->scheduleComposite(); 2315} 2316 2317 2318void WebViewImpl::scrollRootLayerRect(const IntSize& scrollDelta, const IntRect& clipRect) 2319{ 2320 updateLayerRendererViewport(); 2321 setRootLayerNeedsDisplay(); 2322} 2323 2324void 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 2338class WebViewImplContentPainter : public TilePaintInterface { 2339 WTF_MAKE_NONCOPYABLE(WebViewImplContentPainter); 2340public: 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 2355private: 2356 explicit WebViewImplContentPainter(WebViewImpl* webViewImpl) 2357 : m_webViewImpl(webViewImpl) 2358 { 2359 } 2360 2361 WebViewImpl* m_webViewImpl; 2362}; 2363 2364void 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 2409void 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 2430void 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 2459void 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 2474WebGraphicsContext3D* 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