Home | History | Annotate | Download | only in web
      1 /*
      2  * Copyright (C) 2011, 2012 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 "public/platform/Platform.h"
     35 #include "public/platform/WebDragData.h"
     36 #include "public/platform/WebFloatPoint.h"
     37 #include "public/platform/WebGestureCurve.h"
     38 #include "public/platform/WebImage.h"
     39 #include "public/platform/WebLayer.h"
     40 #include "public/platform/WebLayerTreeView.h"
     41 #include "public/platform/WebPoint.h"
     42 #include "public/platform/WebRect.h"
     43 #include "public/platform/WebString.h"
     44 #include "public/platform/WebVector.h"
     45 #include "wtf/CurrentTime.h"
     46 #include "wtf/MainThread.h"
     47 #include "wtf/RefPtr.h"
     48 #include "wtf/TemporaryChange.h"
     49 #include "wtf/Uint8ClampedArray.h"
     50 #include "AutofillPopupMenuClient.h"
     51 #include "CSSValueKeywords.h"
     52 #include "CompositionUnderlineVectorBuilder.h"
     53 #include "ContextFeaturesClientImpl.h"
     54 #include "DeviceOrientationClientProxy.h"
     55 #include "FullscreenController.h"
     56 #include "GeolocationClientProxy.h"
     57 #include "GraphicsLayerFactoryChromium.h"
     58 #include "HTMLNames.h"
     59 #include "LinkHighlight.h"
     60 #include "LocalFileSystemClient.h"
     61 #include "PageWidgetDelegate.h"
     62 #include "PinchViewports.h"
     63 #include "PopupContainer.h"
     64 #include "PrerendererClientImpl.h"
     65 #include "RuntimeEnabledFeatures.h"
     66 #include "SpeechInputClientImpl.h"
     67 #include "SpeechRecognitionClientProxy.h"
     68 #include "ValidationMessageClientImpl.h"
     69 #include "ViewportAnchor.h"
     70 #include "WebAccessibilityObject.h"
     71 #include "WebActiveWheelFlingParameters.h"
     72 #include "WebAutofillClient.h"
     73 #include "WebDevToolsAgentImpl.h"
     74 #include "WebDevToolsAgentPrivate.h"
     75 #include "WebFrameImpl.h"
     76 #include "WebHelperPluginImpl.h"
     77 #include "WebHitTestResult.h"
     78 #include "WebInputElement.h"
     79 #include "WebInputEvent.h"
     80 #include "WebInputEventConversion.h"
     81 #include "WebMediaPlayerAction.h"
     82 #include "WebNode.h"
     83 #include "WebPagePopupImpl.h"
     84 #include "WebPlugin.h"
     85 #include "WebPluginAction.h"
     86 #include "WebPluginContainerImpl.h"
     87 #include "WebPopupMenuImpl.h"
     88 #include "WebRange.h"
     89 #include "WebSettingsImpl.h"
     90 #include "WebTextInputInfo.h"
     91 #include "WebViewClient.h"
     92 #include "WebWindowFeatures.h"
     93 #include "core/accessibility/AXObjectCache.h"
     94 #include "core/css/resolver/StyleResolver.h"
     95 #include "core/dom/Document.h"
     96 #include "core/dom/DocumentMarkerController.h"
     97 #include "core/dom/KeyboardEvent.h"
     98 #include "core/dom/NodeRenderStyle.h"
     99 #include "core/dom/Text.h"
    100 #include "core/dom/WheelEvent.h"
    101 #include "core/editing/Editor.h"
    102 #include "core/editing/FrameSelection.h"
    103 #include "core/editing/InputMethodController.h"
    104 #include "core/editing/TextIterator.h"
    105 #include "core/html/HTMLInputElement.h"
    106 #include "core/html/HTMLMediaElement.h"
    107 #include "core/html/HTMLTextAreaElement.h"
    108 #include "core/html/HTMLVideoElement.h"
    109 #include "core/inspector/InspectorController.h"
    110 #include "core/inspector/InspectorInstrumentation.h"
    111 #include "core/loader/DocumentLoader.h"
    112 #include "core/loader/FrameLoader.h"
    113 #include "core/loader/UniqueIdentifier.h"
    114 #include "core/page/Chrome.h"
    115 #include "core/page/ContextMenuController.h"
    116 #include "core/page/DragController.h"
    117 #include "core/page/DragSession.h"
    118 #include "core/page/EventHandler.h"
    119 #include "core/page/FocusController.h"
    120 #include "core/page/Frame.h"
    121 #include "core/page/FrameTree.h"
    122 #include "core/page/FrameView.h"
    123 #include "core/page/Page.h"
    124 #include "core/page/PageGroup.h"
    125 #include "core/page/PageGroupLoadDeferrer.h"
    126 #include "core/page/PagePopupClient.h"
    127 #include "core/page/PointerLockController.h"
    128 #include "core/page/Settings.h"
    129 #include "core/page/TouchDisambiguation.h"
    130 #include "core/platform/ContextMenu.h"
    131 #include "core/platform/ContextMenuItem.h"
    132 #include "core/platform/Cursor.h"
    133 #include "core/platform/DragData.h"
    134 #include "core/platform/MIMETypeRegistry.h"
    135 #include "core/platform/NotImplemented.h"
    136 #include "core/platform/PlatformGestureEvent.h"
    137 #include "core/platform/PlatformKeyboardEvent.h"
    138 #include "core/platform/PlatformMouseEvent.h"
    139 #include "core/platform/PlatformWheelEvent.h"
    140 #include "core/platform/PopupMenuClient.h"
    141 #include "core/platform/Timer.h"
    142 #include "core/platform/chromium/ChromiumDataObject.h"
    143 #include "core/platform/chromium/KeyboardCodes.h"
    144 #include "core/platform/chromium/TraceEvent.h"
    145 #include "core/platform/chromium/support/WebActiveGestureAnimation.h"
    146 #include "core/platform/graphics/Color.h"
    147 #include "core/platform/graphics/ColorSpace.h"
    148 #include "core/platform/graphics/Extensions3D.h"
    149 #include "core/platform/graphics/FontCache.h"
    150 #include "core/platform/graphics/FontDescription.h"
    151 #include "core/platform/graphics/GraphicsContext.h"
    152 #include "core/platform/graphics/GraphicsContext3D.h"
    153 #include "core/platform/graphics/Image.h"
    154 #include "core/platform/graphics/ImageBuffer.h"
    155 #include "core/platform/graphics/chromium/LayerPainterChromium.h"
    156 #include "core/platform/graphics/gpu/SharedGraphicsContext3D.h"
    157 #include "core/rendering/RenderView.h"
    158 #include "core/rendering/RenderWidget.h"
    159 #include "core/rendering/TextAutosizer.h"
    160 #include "modules/geolocation/GeolocationController.h"
    161 #include "weborigin/SchemeRegistry.h"
    162 #include "weborigin/SecurityOrigin.h"
    163 #include "weborigin/SecurityPolicy.h"
    164 #include "painting/ContinuousPainter.h"
    165 
    166 #if ENABLE(DEFAULT_RENDER_THEME)
    167 #include "core/platform/chromium/PlatformThemeChromiumDefault.h"
    168 #include "core/rendering/RenderThemeChromiumDefault.h"
    169 #endif
    170 
    171 #if OS(WINDOWS)
    172 #if !ENABLE(DEFAULT_RENDER_THEME)
    173 #include "core/rendering/RenderThemeChromiumWin.h"
    174 #endif
    175 #else
    176 #include "core/rendering/RenderTheme.h"
    177 #endif
    178 
    179 // Get rid of WTF's pow define so we can use std::pow.
    180 #undef pow
    181 #include <cmath> // for std::pow
    182 
    183 using namespace WebCore;
    184 using namespace std;
    185 
    186 // The following constants control parameters for automated scaling of webpages
    187 // (such as due to a double tap gesture or find in page etc.). These are
    188 // experimentally determined.
    189 static const int touchPointPadding = 32;
    190 static const int nonUserInitiatedPointPadding = 11;
    191 static const float minScaleDifference = 0.01f;
    192 static const float doubleTapZoomContentDefaultMargin = 5;
    193 static const float doubleTapZoomContentMinimumMargin = 2;
    194 static const double doubleTapZoomAnimationDurationInSeconds = 0.25;
    195 static const float doubleTapZoomAlreadyLegibleRatio = 1.2f;
    196 
    197 static const double multipleTargetsZoomAnimationDurationInSeconds = 0.25;
    198 static const double findInPageAnimationDurationInSeconds = 0;
    199 
    200 // Constants for viewport anchoring on resize.
    201 static const float viewportAnchorXCoord = 0.5f;
    202 static const float viewportAnchorYCoord = 0;
    203 
    204 // Constants for zooming in on a focused text field.
    205 static const double scrollAndScaleAnimationDurationInSeconds = 0.2;
    206 static const int minReadableCaretHeight = 18;
    207 static const float minScaleChangeToTriggerZoom = 1.05f;
    208 static const float leftBoxRatio = 0.3f;
    209 static const int caretPadding = 10;
    210 
    211 namespace WebKit {
    212 
    213 // Change the text zoom level by kTextSizeMultiplierRatio each time the user
    214 // zooms text in or out (ie., change by 20%).  The min and max values limit
    215 // text zoom to half and 3x the original text size.  These three values match
    216 // those in Apple's port in WebKit/WebKit/WebView/WebView.mm
    217 const double WebView::textSizeMultiplierRatio = 1.2;
    218 const double WebView::minTextSizeMultiplier = 0.5;
    219 const double WebView::maxTextSizeMultiplier = 3.0;
    220 
    221 // Used to defer all page activity in cases where the embedder wishes to run
    222 // a nested event loop. Using a stack enables nesting of message loop invocations.
    223 static Vector<PageGroupLoadDeferrer*>& pageGroupLoadDeferrerStack()
    224 {
    225     DEFINE_STATIC_LOCAL(Vector<PageGroupLoadDeferrer*>, deferrerStack, ());
    226     return deferrerStack;
    227 }
    228 
    229 // Ensure that the WebDragOperation enum values stay in sync with the original
    230 // DragOperation constants.
    231 #define COMPILE_ASSERT_MATCHING_ENUM(coreName) \
    232     COMPILE_ASSERT(int(coreName) == int(Web##coreName), dummy##coreName)
    233 COMPILE_ASSERT_MATCHING_ENUM(DragOperationNone);
    234 COMPILE_ASSERT_MATCHING_ENUM(DragOperationCopy);
    235 COMPILE_ASSERT_MATCHING_ENUM(DragOperationLink);
    236 COMPILE_ASSERT_MATCHING_ENUM(DragOperationGeneric);
    237 COMPILE_ASSERT_MATCHING_ENUM(DragOperationPrivate);
    238 COMPILE_ASSERT_MATCHING_ENUM(DragOperationMove);
    239 COMPILE_ASSERT_MATCHING_ENUM(DragOperationDelete);
    240 COMPILE_ASSERT_MATCHING_ENUM(DragOperationEvery);
    241 
    242 static const PopupContainerSettings autofillPopupSettings = {
    243     false, // setTextOnIndexChange
    244     false, // acceptOnAbandon
    245     true, // loopSelectionNavigation
    246     false // restrictWidthOfListBox (For security reasons show the entire entry
    247           // so the user doesn't enter information he did not intend to.)
    248 };
    249 
    250 static bool shouldUseExternalPopupMenus = false;
    251 
    252 static int webInputEventKeyStateToPlatformEventKeyState(int webInputEventKeyState)
    253 {
    254     int platformEventKeyState = 0;
    255     if (webInputEventKeyState & WebInputEvent::ShiftKey)
    256         platformEventKeyState = platformEventKeyState | WebCore::PlatformEvent::ShiftKey;
    257     if (webInputEventKeyState & WebInputEvent::ControlKey)
    258         platformEventKeyState = platformEventKeyState | WebCore::PlatformEvent::CtrlKey;
    259     if (webInputEventKeyState & WebInputEvent::AltKey)
    260         platformEventKeyState = platformEventKeyState | WebCore::PlatformEvent::AltKey;
    261     if (webInputEventKeyState & WebInputEvent::MetaKey)
    262         platformEventKeyState = platformEventKeyState | WebCore::PlatformEvent::MetaKey;
    263     return platformEventKeyState;
    264 }
    265 
    266 // WebView ----------------------------------------------------------------
    267 
    268 WebView* WebView::create(WebViewClient* client)
    269 {
    270     // Pass the WebViewImpl's self-reference to the caller.
    271     return adoptRef(new WebViewImpl(client)).leakRef();
    272 }
    273 
    274 void WebView::setUseExternalPopupMenus(bool useExternalPopupMenus)
    275 {
    276     shouldUseExternalPopupMenus = useExternalPopupMenus;
    277 }
    278 
    279 void WebView::updateVisitedLinkState(unsigned long long linkHash)
    280 {
    281     Page::visitedStateChanged(PageGroup::sharedGroup(), linkHash);
    282 }
    283 
    284 void WebView::resetVisitedLinkState()
    285 {
    286     Page::allVisitedStateChanged(PageGroup::sharedGroup());
    287 }
    288 
    289 void WebView::willEnterModalLoop()
    290 {
    291     PageGroup* pageGroup = PageGroup::sharedGroup();
    292 
    293     // We allow deferring inspector only when it is running in a separate process (no pages in a shared group)
    294     // to support debugger tests in DRT.
    295     if (pageGroup->pages().isEmpty())
    296         pageGroup = PageGroup::inspectorGroup();
    297 
    298     if (pageGroup->pages().isEmpty())
    299         pageGroupLoadDeferrerStack().append(static_cast<PageGroupLoadDeferrer*>(0));
    300     else {
    301         // Pick any page in the page group since we are deferring all pages.
    302         pageGroupLoadDeferrerStack().append(new PageGroupLoadDeferrer(*pageGroup->pages().begin(), true));
    303     }
    304 }
    305 
    306 void WebView::didExitModalLoop()
    307 {
    308     ASSERT(pageGroupLoadDeferrerStack().size());
    309 
    310     delete pageGroupLoadDeferrerStack().last();
    311     pageGroupLoadDeferrerStack().removeLast();
    312 }
    313 
    314 void WebViewImpl::initializeMainFrame(WebFrameClient* frameClient)
    315 {
    316     // NOTE: The WebFrameImpl takes a reference to itself within InitMainFrame
    317     // and releases that reference once the corresponding Frame is destroyed.
    318     RefPtr<WebFrameImpl> frame = WebFrameImpl::create(frameClient);
    319 
    320     frame->initializeAsMainFrame(page());
    321 }
    322 
    323 void WebViewImpl::initializeHelperPluginFrame(WebFrameClient* client)
    324 {
    325     RefPtr<WebFrameImpl> frame = WebFrameImpl::create(client);
    326 }
    327 
    328 void WebViewImpl::setAutofillClient(WebAutofillClient* autofillClient)
    329 {
    330     m_autofillClient = autofillClient;
    331 }
    332 
    333 void WebViewImpl::setDevToolsAgentClient(WebDevToolsAgentClient* devToolsClient)
    334 {
    335     if (devToolsClient)
    336         m_devToolsAgent = adoptPtr(new WebDevToolsAgentImpl(this, devToolsClient));
    337     else
    338         m_devToolsAgent.clear();
    339 }
    340 
    341 void WebViewImpl::setValidationMessageClient(WebValidationMessageClient* client)
    342 {
    343     ASSERT(client);
    344     m_validationMessage = ValidationMessageClientImpl::create(*this, *client);
    345     m_page->setValidationMessageClient(m_validationMessage.get());
    346 }
    347 
    348 void WebViewImpl::setPermissionClient(WebPermissionClient* permissionClient)
    349 {
    350     m_permissionClient = permissionClient;
    351     m_featureSwitchClient->setPermissionClient(permissionClient);
    352 }
    353 
    354 void WebViewImpl::setPrerendererClient(WebPrerendererClient* prerendererClient)
    355 {
    356     providePrerendererClientTo(m_page.get(), new PrerendererClientImpl(prerendererClient));
    357 }
    358 
    359 void WebViewImpl::setSpellCheckClient(WebSpellCheckClient* spellCheckClient)
    360 {
    361     m_spellCheckClient = spellCheckClient;
    362 }
    363 
    364 void WebViewImpl::setPasswordGeneratorClient(WebPasswordGeneratorClient* client)
    365 {
    366     m_passwordGeneratorClient = client;
    367 }
    368 
    369 WebViewImpl::WebViewImpl(WebViewClient* client)
    370     : m_client(client)
    371     , m_autofillClient(0)
    372     , m_permissionClient(0)
    373     , m_spellCheckClient(0)
    374     , m_passwordGeneratorClient(0)
    375     , m_chromeClientImpl(this)
    376     , m_contextMenuClientImpl(this)
    377     , m_dragClientImpl(this)
    378     , m_editorClientImpl(this)
    379     , m_inspectorClientImpl(this)
    380     , m_backForwardClientImpl(this)
    381     , m_fixedLayoutSizeLock(false)
    382     , m_shouldAutoResize(false)
    383     , m_observedNewNavigation(false)
    384 #ifndef NDEBUG
    385     , m_newNavigationLoader(0)
    386 #endif
    387     , m_zoomLevel(0)
    388     , m_minimumZoomLevel(zoomFactorToZoomLevel(minTextSizeMultiplier))
    389     , m_maximumZoomLevel(zoomFactorToZoomLevel(maxTextSizeMultiplier))
    390     , m_savedPageScaleFactor(0)
    391     , m_doubleTapZoomPageScaleFactor(0)
    392     , m_doubleTapZoomPending(false)
    393     , m_enableFakePageScaleAnimationForTesting(false)
    394     , m_fakePageScaleAnimationPageScaleFactor(0)
    395     , m_fakePageScaleAnimationUseAnchor(false)
    396     , m_contextMenuAllowed(false)
    397     , m_doingDragAndDrop(false)
    398     , m_ignoreInputEvents(false)
    399     , m_suppressNextKeypressEvent(false)
    400     , m_imeAcceptEvents(true)
    401     , m_operationsAllowed(WebDragOperationNone)
    402     , m_dragOperation(WebDragOperationNone)
    403     , m_featureSwitchClient(adoptPtr(new ContextFeaturesClientImpl()))
    404     , m_autofillPopupShowing(false)
    405     , m_autofillPopup(0)
    406     , m_isTransparent(false)
    407     , m_tabsToLinks(false)
    408     , m_benchmarkSupport(this)
    409     , m_layerTreeView(0)
    410     , m_rootLayer(0)
    411     , m_rootGraphicsLayer(0)
    412     , m_graphicsLayerFactory(adoptPtr(new GraphicsLayerFactoryChromium(this)))
    413     , m_isAcceleratedCompositingActive(false)
    414     , m_layerTreeViewCommitsDeferred(false)
    415     , m_compositorCreationFailed(false)
    416     , m_recreatingGraphicsContext(false)
    417 #if ENABLE(INPUT_SPEECH)
    418     , m_speechInputClient(SpeechInputClientImpl::create(client))
    419 #endif
    420     , m_speechRecognitionClient(SpeechRecognitionClientProxy::create(client ? client->speechRecognizer() : 0))
    421     , m_deviceOrientationClientProxy(adoptPtr(new DeviceOrientationClientProxy(client ? client->deviceOrientationClient() : 0)))
    422     , m_geolocationClientProxy(adoptPtr(new GeolocationClientProxy(client ? client->geolocationClient() : 0)))
    423     , m_userMediaClientImpl(this)
    424     , m_midiClientImpl(this)
    425 #if ENABLE(NAVIGATOR_CONTENT_UTILS)
    426     , m_navigatorContentUtilsClient(NavigatorContentUtilsClientImpl::create(this))
    427 #endif
    428     , m_flingModifier(0)
    429     , m_flingSourceDevice(false)
    430     , m_fullscreenController(FullscreenController::create(this))
    431     , m_showFPSCounter(false)
    432     , m_showPaintRects(false)
    433     , m_showDebugBorders(false)
    434     , m_continuousPaintingEnabled(false)
    435     , m_showScrollBottleneckRects(false)
    436     , m_baseBackgroundColor(Color::white)
    437     , m_helperPluginCloseTimer(this, &WebViewImpl::closePendingHelperPlugins)
    438 {
    439     Page::PageClients pageClients;
    440     pageClients.chromeClient = &m_chromeClientImpl;
    441     pageClients.contextMenuClient = &m_contextMenuClientImpl;
    442     pageClients.editorClient = &m_editorClientImpl;
    443     pageClients.dragClient = &m_dragClientImpl;
    444     pageClients.inspectorClient = &m_inspectorClientImpl;
    445     pageClients.backForwardClient = &m_backForwardClientImpl;
    446 
    447     m_page = adoptPtr(new Page(pageClients));
    448     provideUserMediaTo(m_page.get(), &m_userMediaClientImpl);
    449     provideMIDITo(m_page.get(), &m_midiClientImpl);
    450 #if ENABLE(INPUT_SPEECH)
    451     provideSpeechInputTo(m_page.get(), m_speechInputClient.get());
    452 #endif
    453     provideSpeechRecognitionTo(m_page.get(), m_speechRecognitionClient.get());
    454 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
    455     provideNotification(m_page.get(), notificationPresenterImpl());
    456 #endif
    457 #if ENABLE(NAVIGATOR_CONTENT_UTILS)
    458     provideNavigatorContentUtilsTo(m_page.get(), m_navigatorContentUtilsClient.get());
    459 #endif
    460 
    461     provideContextFeaturesTo(m_page.get(), m_featureSwitchClient.get());
    462     provideDeviceOrientationTo(m_page.get(), m_deviceOrientationClientProxy.get());
    463     provideGeolocationTo(m_page.get(), m_geolocationClientProxy.get());
    464     m_geolocationClientProxy->setController(GeolocationController::from(m_page.get()));
    465 
    466     provideLocalFileSystemTo(m_page.get(), LocalFileSystemClient::create());
    467 
    468     m_page->setGroupType(Page::SharedPageGroup);
    469 
    470     unsigned layoutMilestones = DidFirstLayout | DidFirstVisuallyNonEmptyLayout;
    471     m_page->addLayoutMilestones(static_cast<LayoutMilestones>(layoutMilestones));
    472 
    473     if (m_client) {
    474         setDeviceScaleFactor(m_client->screenInfo().deviceScaleFactor);
    475         setVisibilityState(m_client->visibilityState(), true);
    476     }
    477 
    478     m_inspectorSettingsMap = adoptPtr(new SettingsMap);
    479 }
    480 
    481 WebViewImpl::~WebViewImpl()
    482 {
    483     ASSERT(!m_page);
    484     ASSERT(!m_helperPluginCloseTimer.isActive());
    485     ASSERT(m_helperPluginsPendingClose.isEmpty());
    486 }
    487 
    488 RenderTheme* WebViewImpl::theme() const
    489 {
    490     return m_page ? m_page->theme() : RenderTheme::defaultTheme().get();
    491 }
    492 
    493 WebFrameImpl* WebViewImpl::mainFrameImpl()
    494 {
    495     return m_page ? WebFrameImpl::fromFrame(m_page->mainFrame()) : 0;
    496 }
    497 
    498 bool WebViewImpl::tabKeyCyclesThroughElements() const
    499 {
    500     ASSERT(m_page);
    501     return m_page->tabKeyCyclesThroughElements();
    502 }
    503 
    504 void WebViewImpl::setTabKeyCyclesThroughElements(bool value)
    505 {
    506     if (m_page)
    507         m_page->setTabKeyCyclesThroughElements(value);
    508 }
    509 
    510 void WebViewImpl::handleMouseLeave(Frame& mainFrame, const WebMouseEvent& event)
    511 {
    512     m_client->setMouseOverURL(WebURL());
    513     PageWidgetEventHandler::handleMouseLeave(mainFrame, event);
    514 }
    515 
    516 void WebViewImpl::handleMouseDown(Frame& mainFrame, const WebMouseEvent& event)
    517 {
    518     // If there is a popup open, close it as the user is clicking on the page (outside of the
    519     // popup). We also save it so we can prevent a click on an element from immediately
    520     // reopening the same popup.
    521     RefPtr<WebCore::PopupContainer> selectPopup;
    522     RefPtr<WebPagePopupImpl> pagePopup;
    523     if (event.button == WebMouseEvent::ButtonLeft) {
    524         selectPopup = m_selectPopup;
    525         pagePopup = m_pagePopup;
    526         hidePopups();
    527         ASSERT(!m_selectPopup);
    528         ASSERT(!m_pagePopup);
    529     }
    530 
    531     m_lastMouseDownPoint = WebPoint(event.x, event.y);
    532 
    533     if (event.button == WebMouseEvent::ButtonLeft) {
    534         IntPoint point(event.x, event.y);
    535         point = m_page->mainFrame()->view()->windowToContents(point);
    536         HitTestResult result(m_page->mainFrame()->eventHandler()->hitTestResultAtPoint(point));
    537         Node* hitNode = result.innerNonSharedNode();
    538 
    539         // Take capture on a mouse down on a plugin so we can send it mouse events.
    540         if (hitNode && hitNode->renderer() && hitNode->renderer()->isEmbeddedObject()) {
    541             m_mouseCaptureNode = hitNode;
    542             TRACE_EVENT_ASYNC_BEGIN0("input", "capturing mouse", this);
    543         }
    544     }
    545 
    546     PageWidgetEventHandler::handleMouseDown(mainFrame, event);
    547 
    548     if (m_selectPopup && m_selectPopup == selectPopup) {
    549         // That click triggered a select popup which is the same as the one that
    550         // was showing before the click.  It means the user clicked the select
    551         // while the popup was showing, and as a result we first closed then
    552         // immediately reopened the select popup.  It needs to be closed.
    553         hideSelectPopup();
    554     }
    555 
    556     if (m_pagePopup && pagePopup && m_pagePopup->hasSamePopupClient(pagePopup.get())) {
    557         // That click triggered a page popup that is the same as the one we just closed.
    558         // It needs to be closed.
    559         closePagePopup(m_pagePopup.get());
    560     }
    561 
    562     // Dispatch the contextmenu event regardless of if the click was swallowed.
    563     // On Windows, we handle it on mouse up, not down.
    564 #if OS(DARWIN)
    565     if (event.button == WebMouseEvent::ButtonRight
    566         || (event.button == WebMouseEvent::ButtonLeft
    567             && event.modifiers & WebMouseEvent::ControlKey))
    568         mouseContextMenu(event);
    569 #elif OS(UNIX)
    570     if (event.button == WebMouseEvent::ButtonRight)
    571         mouseContextMenu(event);
    572 #endif
    573 }
    574 
    575 void WebViewImpl::mouseContextMenu(const WebMouseEvent& event)
    576 {
    577     if (!mainFrameImpl() || !mainFrameImpl()->frameView())
    578         return;
    579 
    580     m_page->contextMenuController()->clearContextMenu();
    581 
    582     PlatformMouseEventBuilder pme(mainFrameImpl()->frameView(), event);
    583 
    584     // Find the right target frame. See issue 1186900.
    585     HitTestResult result = hitTestResultForWindowPos(pme.position());
    586     Frame* targetFrame;
    587     if (result.innerNonSharedNode())
    588         targetFrame = result.innerNonSharedNode()->document()->frame();
    589     else
    590         targetFrame = m_page->focusController().focusedOrMainFrame();
    591 
    592 #if OS(WINDOWS)
    593     targetFrame->view()->setCursor(pointerCursor());
    594 #endif
    595 
    596     m_contextMenuAllowed = true;
    597     targetFrame->eventHandler()->sendContextMenuEvent(pme);
    598     m_contextMenuAllowed = false;
    599     // Actually showing the context menu is handled by the ContextMenuClient
    600     // implementation...
    601 }
    602 
    603 void WebViewImpl::handleMouseUp(Frame& mainFrame, const WebMouseEvent& event)
    604 {
    605     PageWidgetEventHandler::handleMouseUp(mainFrame, event);
    606 
    607 #if OS(WINDOWS)
    608     // Dispatch the contextmenu event regardless of if the click was swallowed.
    609     // On Mac/Linux, we handle it on mouse down, not up.
    610     if (event.button == WebMouseEvent::ButtonRight)
    611         mouseContextMenu(event);
    612 #endif
    613 }
    614 
    615 bool WebViewImpl::handleMouseWheel(Frame& mainFrame, const WebMouseWheelEvent& event)
    616 {
    617     hidePopups();
    618     return PageWidgetEventHandler::handleMouseWheel(mainFrame, event);
    619 }
    620 
    621 void WebViewImpl::scrollBy(const WebFloatSize& delta)
    622 {
    623     if (m_flingSourceDevice == WebGestureEvent::Touchpad) {
    624         WebMouseWheelEvent syntheticWheel;
    625         const float tickDivisor = WebCore::WheelEvent::TickMultiplier;
    626 
    627         syntheticWheel.deltaX = delta.width;
    628         syntheticWheel.deltaY = delta.height;
    629         syntheticWheel.wheelTicksX = delta.width / tickDivisor;
    630         syntheticWheel.wheelTicksY = delta.height / tickDivisor;
    631         syntheticWheel.hasPreciseScrollingDeltas = true;
    632         syntheticWheel.x = m_positionOnFlingStart.x;
    633         syntheticWheel.y = m_positionOnFlingStart.y;
    634         syntheticWheel.globalX = m_globalPositionOnFlingStart.x;
    635         syntheticWheel.globalY = m_globalPositionOnFlingStart.y;
    636         syntheticWheel.modifiers = m_flingModifier;
    637 
    638         if (m_page && m_page->mainFrame() && m_page->mainFrame()->view())
    639             handleMouseWheel(*m_page->mainFrame(), syntheticWheel);
    640     } else {
    641         WebGestureEvent syntheticGestureEvent;
    642 
    643         syntheticGestureEvent.type = WebInputEvent::GestureScrollUpdateWithoutPropagation;
    644         syntheticGestureEvent.data.scrollUpdate.deltaX = delta.width;
    645         syntheticGestureEvent.data.scrollUpdate.deltaY = delta.height;
    646         syntheticGestureEvent.x = m_positionOnFlingStart.x;
    647         syntheticGestureEvent.y = m_positionOnFlingStart.y;
    648         syntheticGestureEvent.globalX = m_globalPositionOnFlingStart.x;
    649         syntheticGestureEvent.globalY = m_globalPositionOnFlingStart.y;
    650         syntheticGestureEvent.modifiers = m_flingModifier;
    651         syntheticGestureEvent.sourceDevice = WebGestureEvent::Touchscreen;
    652 
    653         if (m_page && m_page->mainFrame() && m_page->mainFrame()->view())
    654             handleGestureEvent(syntheticGestureEvent);
    655     }
    656 }
    657 
    658 bool WebViewImpl::handleGestureEvent(const WebGestureEvent& event)
    659 {
    660     bool eventSwallowed = false;
    661     bool eventCancelled = false; // for disambiguation
    662 
    663     // Special handling for slow-path fling gestures, which have no PlatformGestureEvent equivalent.
    664     switch (event.type) {
    665     case WebInputEvent::GestureFlingStart: {
    666         if (mainFrameImpl()->frame()->eventHandler()->isScrollbarHandlingGestures()) {
    667             m_client->didHandleGestureEvent(event, eventCancelled);
    668             return eventSwallowed;
    669         }
    670         m_client->cancelScheduledContentIntents();
    671         m_positionOnFlingStart = WebPoint(event.x / pageScaleFactor(), event.y / pageScaleFactor());
    672         m_globalPositionOnFlingStart = WebPoint(event.globalX, event.globalY);
    673         m_flingModifier = event.modifiers;
    674         m_flingSourceDevice = event.sourceDevice;
    675         OwnPtr<WebGestureCurve> flingCurve = adoptPtr(Platform::current()->createFlingAnimationCurve(event.sourceDevice, WebFloatPoint(event.data.flingStart.velocityX, event.data.flingStart.velocityY), WebSize()));
    676         m_gestureAnimation = WebActiveGestureAnimation::createAtAnimationStart(flingCurve.release(), this);
    677         scheduleAnimation();
    678         eventSwallowed = true;
    679 
    680         m_client->didHandleGestureEvent(event, eventCancelled);
    681         return eventSwallowed;
    682     }
    683     case WebInputEvent::GestureFlingCancel:
    684         if (m_gestureAnimation) {
    685             m_gestureAnimation.clear();
    686             if (m_layerTreeView)
    687                 m_layerTreeView->didStopFlinging();
    688             eventSwallowed = true;
    689         }
    690 
    691         m_client->didHandleGestureEvent(event, eventCancelled);
    692         return eventSwallowed;
    693     default:
    694         break;
    695     }
    696 
    697     PlatformGestureEventBuilder platformEvent(mainFrameImpl()->frameView(), event);
    698 
    699     // Handle link highlighting outside the main switch to avoid getting lost in the
    700     // complicated set of cases handled below.
    701     switch (event.type) {
    702     case WebInputEvent::GestureTapDown:
    703         // Queue a highlight animation, then hand off to regular handler.
    704 #if OS(LINUX)
    705         if (settingsImpl()->gestureTapHighlightEnabled())
    706             enableTapHighlight(platformEvent);
    707 #endif
    708         break;
    709     case WebInputEvent::GestureTapCancel:
    710     case WebInputEvent::GestureTap:
    711     case WebInputEvent::GestureLongPress:
    712         if (m_linkHighlight)
    713             m_linkHighlight->startHighlightAnimationIfNeeded();
    714         break;
    715     default:
    716         break;
    717     }
    718 
    719     switch (event.type) {
    720     case WebInputEvent::GestureTap: {
    721         m_client->cancelScheduledContentIntents();
    722         if (detectContentOnTouch(platformEvent.position())) {
    723             eventSwallowed = true;
    724             break;
    725         }
    726 
    727         RefPtr<WebCore::PopupContainer> selectPopup;
    728         selectPopup = m_selectPopup;
    729         hideSelectPopup();
    730         ASSERT(!m_selectPopup);
    731 
    732         // Don't trigger a disambiguation popup on sites designed for mobile devices.
    733         // Instead, assume that the page has been designed with big enough buttons and links.
    734         if (event.data.tap.width > 0 && !shouldDisableDesktopWorkarounds()) {
    735             // FIXME: didTapMultipleTargets should just take a rect instead of
    736             // an event.
    737             WebGestureEvent scaledEvent = event;
    738             scaledEvent.x = event.x / pageScaleFactor();
    739             scaledEvent.y = event.y / pageScaleFactor();
    740             scaledEvent.data.tap.width = event.data.tap.width / pageScaleFactor();
    741             scaledEvent.data.tap.height = event.data.tap.height / pageScaleFactor();
    742             IntRect boundingBox(scaledEvent.x - scaledEvent.data.tap.width / 2, scaledEvent.y - scaledEvent.data.tap.height / 2, scaledEvent.data.tap.width, scaledEvent.data.tap.height);
    743             Vector<IntRect> goodTargets;
    744             findGoodTouchTargets(boundingBox, mainFrameImpl()->frame(), goodTargets);
    745             // FIXME: replace touch adjustment code when numberOfGoodTargets == 1?
    746             // Single candidate case is currently handled by: https://bugs.webkit.org/show_bug.cgi?id=85101
    747             if (goodTargets.size() >= 2 && m_client && m_client->didTapMultipleTargets(scaledEvent, goodTargets)) {
    748                 eventSwallowed = true;
    749                 eventCancelled = true;
    750                 break;
    751             }
    752         }
    753 
    754         eventSwallowed = mainFrameImpl()->frame()->eventHandler()->handleGestureEvent(platformEvent);
    755 
    756         if (m_selectPopup && m_selectPopup == selectPopup) {
    757             // That tap triggered a select popup which is the same as the one that
    758             // was showing before the tap. It means the user tapped the select
    759             // while the popup was showing, and as a result we first closed then
    760             // immediately reopened the select popup. It needs to be closed.
    761             hideSelectPopup();
    762         }
    763 
    764         break;
    765     }
    766     case WebInputEvent::GestureTwoFingerTap:
    767     case WebInputEvent::GestureLongPress:
    768     case WebInputEvent::GestureLongTap: {
    769         if (!mainFrameImpl() || !mainFrameImpl()->frameView())
    770             break;
    771 
    772         m_client->cancelScheduledContentIntents();
    773         m_page->contextMenuController()->clearContextMenu();
    774         m_contextMenuAllowed = true;
    775         eventSwallowed = mainFrameImpl()->frame()->eventHandler()->handleGestureEvent(platformEvent);
    776         m_contextMenuAllowed = false;
    777 
    778         break;
    779     }
    780     case WebInputEvent::GestureTapDown: {
    781         m_client->cancelScheduledContentIntents();
    782         eventSwallowed = mainFrameImpl()->frame()->eventHandler()->handleGestureEvent(platformEvent);
    783         break;
    784     }
    785     case WebInputEvent::GestureDoubleTap:
    786         if (m_webSettings->doubleTapToZoomEnabled() && minimumPageScaleFactor() != maximumPageScaleFactor()) {
    787             m_client->cancelScheduledContentIntents();
    788             animateDoubleTapZoom(platformEvent.position());
    789         }
    790         // GestureDoubleTap is currently only used by Android for zooming. For WebCore,
    791         // GestureTap with tap count = 2 is used instead. So we drop GestureDoubleTap here.
    792         eventSwallowed = true;
    793         break;
    794     case WebInputEvent::GestureScrollBegin:
    795     case WebInputEvent::GesturePinchBegin:
    796         m_client->cancelScheduledContentIntents();
    797     case WebInputEvent::GestureScrollEnd:
    798     case WebInputEvent::GestureScrollUpdate:
    799     case WebInputEvent::GestureScrollUpdateWithoutPropagation:
    800     case WebInputEvent::GestureTapCancel:
    801     case WebInputEvent::GestureTapUnconfirmed:
    802     case WebInputEvent::GesturePinchEnd:
    803     case WebInputEvent::GesturePinchUpdate: {
    804         eventSwallowed = mainFrameImpl()->frame()->eventHandler()->handleGestureEvent(platformEvent);
    805         break;
    806     }
    807     default:
    808         ASSERT_NOT_REACHED();
    809     }
    810     m_client->didHandleGestureEvent(event, eventCancelled);
    811     return eventSwallowed;
    812 }
    813 
    814 void WebViewImpl::transferActiveWheelFlingAnimation(const WebActiveWheelFlingParameters& parameters)
    815 {
    816     TRACE_EVENT0("webkit", "WebViewImpl::transferActiveWheelFlingAnimation");
    817     ASSERT(!m_gestureAnimation);
    818     m_positionOnFlingStart = parameters.point;
    819     m_globalPositionOnFlingStart = parameters.globalPoint;
    820     m_flingModifier = parameters.modifiers;
    821     OwnPtr<WebGestureCurve> curve = adoptPtr(Platform::current()->createFlingAnimationCurve(parameters.sourceDevice, WebFloatPoint(parameters.delta), parameters.cumulativeScroll));
    822     m_gestureAnimation = WebActiveGestureAnimation::createWithTimeOffset(curve.release(), this, parameters.startTime);
    823     scheduleAnimation();
    824 }
    825 
    826 bool WebViewImpl::startPageScaleAnimation(const IntPoint& targetPosition, bool useAnchor, float newScale, double durationInSeconds)
    827 {
    828     WebPoint clampedPoint = targetPosition;
    829     if (!useAnchor) {
    830         clampedPoint = clampOffsetAtScale(targetPosition, newScale);
    831         if (!durationInSeconds) {
    832             setPageScaleFactor(newScale, clampedPoint);
    833             return false;
    834         }
    835     }
    836     if (useAnchor && newScale == pageScaleFactor())
    837         return false;
    838 
    839     if (m_enableFakePageScaleAnimationForTesting) {
    840         m_fakePageScaleAnimationTargetPosition = targetPosition;
    841         m_fakePageScaleAnimationUseAnchor = useAnchor;
    842         m_fakePageScaleAnimationPageScaleFactor = newScale;
    843     } else {
    844         if (!m_layerTreeView)
    845             return false;
    846         m_layerTreeView->startPageScaleAnimation(targetPosition, useAnchor, newScale, durationInSeconds);
    847     }
    848     return true;
    849 }
    850 
    851 void WebViewImpl::enableFakePageScaleAnimationForTesting(bool enable)
    852 {
    853     m_enableFakePageScaleAnimationForTesting = enable;
    854 }
    855 
    856 WebViewBenchmarkSupport* WebViewImpl::benchmarkSupport()
    857 {
    858     return &m_benchmarkSupport;
    859 }
    860 
    861 void WebViewImpl::setShowFPSCounter(bool show)
    862 {
    863     if (m_layerTreeView) {
    864         TRACE_EVENT0("webkit", "WebViewImpl::setShowFPSCounter");
    865         m_layerTreeView->setShowFPSCounter(show);
    866     }
    867     m_showFPSCounter = show;
    868 }
    869 
    870 void WebViewImpl::setShowPaintRects(bool show)
    871 {
    872     if (m_layerTreeView) {
    873         TRACE_EVENT0("webkit", "WebViewImpl::setShowPaintRects");
    874         m_layerTreeView->setShowPaintRects(show);
    875     }
    876     m_showPaintRects = show;
    877 }
    878 
    879 void WebViewImpl::setShowDebugBorders(bool show)
    880 {
    881     if (m_layerTreeView)
    882         m_layerTreeView->setShowDebugBorders(show);
    883     m_showDebugBorders = show;
    884 }
    885 
    886 void WebViewImpl::setContinuousPaintingEnabled(bool enabled)
    887 {
    888     if (m_layerTreeView) {
    889         TRACE_EVENT0("webkit", "WebViewImpl::setContinuousPaintingEnabled");
    890         m_layerTreeView->setContinuousPaintingEnabled(enabled);
    891     }
    892     m_continuousPaintingEnabled = enabled;
    893     m_client->scheduleAnimation();
    894 }
    895 
    896 void WebViewImpl::setShowScrollBottleneckRects(bool show)
    897 {
    898     if (m_layerTreeView)
    899         m_layerTreeView->setShowScrollBottleneckRects(show);
    900     m_showScrollBottleneckRects = show;
    901 }
    902 
    903 bool WebViewImpl::handleKeyEvent(const WebKeyboardEvent& event)
    904 {
    905     ASSERT((event.type == WebInputEvent::RawKeyDown)
    906         || (event.type == WebInputEvent::KeyDown)
    907         || (event.type == WebInputEvent::KeyUp));
    908 
    909     // Halt an in-progress fling on a key event.
    910     if (m_gestureAnimation) {
    911         m_gestureAnimation.clear();
    912         if (m_layerTreeView)
    913             m_layerTreeView->didStopFlinging();
    914     }
    915 
    916     // Please refer to the comments explaining the m_suppressNextKeypressEvent
    917     // member.
    918     // The m_suppressNextKeypressEvent is set if the KeyDown is handled by
    919     // Webkit. A keyDown event is typically associated with a keyPress(char)
    920     // event and a keyUp event. We reset this flag here as this is a new keyDown
    921     // event.
    922     m_suppressNextKeypressEvent = false;
    923 
    924     // If there is a select popup, it should be the one processing the event,
    925     // not the page.
    926     if (m_selectPopup)
    927         return m_selectPopup->handleKeyEvent(PlatformKeyboardEventBuilder(event));
    928     if (m_pagePopup) {
    929         m_pagePopup->handleKeyEvent(PlatformKeyboardEventBuilder(event));
    930         // We need to ignore the next Char event after this otherwise pressing
    931         // enter when selecting an item in the popup will go to the page.
    932         if (WebInputEvent::RawKeyDown == event.type)
    933             m_suppressNextKeypressEvent = true;
    934         return true;
    935     }
    936 
    937     // Give Autocomplete a chance to consume the key events it is interested in.
    938     if (autocompleteHandleKeyEvent(event))
    939         return true;
    940 
    941     RefPtr<Frame> frame = focusedWebCoreFrame();
    942     if (!frame)
    943         return false;
    944 
    945     EventHandler* handler = frame->eventHandler();
    946     if (!handler)
    947         return keyEventDefault(event);
    948 
    949 #if !OS(DARWIN)
    950     const WebInputEvent::Type contextMenuTriggeringEventType =
    951 #if OS(WINDOWS)
    952         WebInputEvent::KeyUp;
    953 #elif OS(UNIX)
    954         WebInputEvent::RawKeyDown;
    955 #endif
    956 
    957     bool isUnmodifiedMenuKey = !(event.modifiers & WebInputEvent::InputModifiers) && event.windowsKeyCode == VKEY_APPS;
    958     bool isShiftF10 = event.modifiers == WebInputEvent::ShiftKey && event.windowsKeyCode == VKEY_F10;
    959     if ((isUnmodifiedMenuKey || isShiftF10) && event.type == contextMenuTriggeringEventType) {
    960         sendContextMenuEvent(event);
    961         return true;
    962     }
    963 #endif // !OS(DARWIN)
    964 
    965     PlatformKeyboardEventBuilder evt(event);
    966 
    967     if (handler->keyEvent(evt)) {
    968         if (WebInputEvent::RawKeyDown == event.type) {
    969             // Suppress the next keypress event unless the focused node is a plug-in node.
    970             // (Flash needs these keypress events to handle non-US keyboards.)
    971             Element* element = focusedElement();
    972             if (!element || !element->renderer() || !element->renderer()->isEmbeddedObject())
    973                 m_suppressNextKeypressEvent = true;
    974         }
    975         return true;
    976     }
    977 
    978     return keyEventDefault(event);
    979 }
    980 
    981 bool WebViewImpl::autocompleteHandleKeyEvent(const WebKeyboardEvent& event)
    982 {
    983     if (!m_autofillPopupShowing
    984         // Home and End should be left to the text field to process.
    985         || event.windowsKeyCode == VKEY_HOME
    986         || event.windowsKeyCode == VKEY_END)
    987       return false;
    988 
    989     // Pressing delete triggers the removal of the selected suggestion from the DB.
    990     if (event.windowsKeyCode == VKEY_DELETE
    991         && m_autofillPopup->selectedIndex() != -1) {
    992         Element* element = focusedElement();
    993         if (!element) {
    994             ASSERT_NOT_REACHED();
    995             return false;
    996         }
    997         if (!element->hasTagName(HTMLNames::inputTag)) {
    998             ASSERT_NOT_REACHED();
    999             return false;
   1000         }
   1001 
   1002         int selectedIndex = m_autofillPopup->selectedIndex();
   1003 
   1004         if (!m_autofillPopupClient->canRemoveSuggestionAtIndex(selectedIndex))
   1005             return false;
   1006 
   1007         WebString name = WebInputElement(toHTMLInputElement(element)).nameForAutofill();
   1008         WebString value = m_autofillPopupClient->itemText(selectedIndex);
   1009         m_autofillClient->removeAutocompleteSuggestion(name, value);
   1010         // Update the entries in the currently showing popup to reflect the
   1011         // deletion.
   1012         m_autofillPopupClient->removeSuggestionAtIndex(selectedIndex);
   1013         refreshAutofillPopup();
   1014         return false;
   1015     }
   1016 
   1017     if (!m_autofillPopup->isInterestedInEventForKey(event.windowsKeyCode))
   1018         return false;
   1019 
   1020     if (m_autofillPopup->handleKeyEvent(PlatformKeyboardEventBuilder(event))) {
   1021         // We need to ignore the next Char event after this otherwise pressing
   1022         // enter when selecting an item in the menu will go to the page.
   1023         if (WebInputEvent::RawKeyDown == event.type)
   1024             m_suppressNextKeypressEvent = true;
   1025         return true;
   1026     }
   1027 
   1028     return false;
   1029 }
   1030 
   1031 bool WebViewImpl::handleCharEvent(const WebKeyboardEvent& event)
   1032 {
   1033     ASSERT(event.type == WebInputEvent::Char);
   1034 
   1035     // Please refer to the comments explaining the m_suppressNextKeypressEvent
   1036     // member.  The m_suppressNextKeypressEvent is set if the KeyDown is
   1037     // handled by Webkit. A keyDown event is typically associated with a
   1038     // keyPress(char) event and a keyUp event. We reset this flag here as it
   1039     // only applies to the current keyPress event.
   1040     bool suppress = m_suppressNextKeypressEvent;
   1041     m_suppressNextKeypressEvent = false;
   1042 
   1043     // If there is a select popup, it should be the one processing the event,
   1044     // not the page.
   1045     if (m_selectPopup)
   1046         return m_selectPopup->handleKeyEvent(PlatformKeyboardEventBuilder(event));
   1047     if (m_pagePopup)
   1048         return m_pagePopup->handleKeyEvent(PlatformKeyboardEventBuilder(event));
   1049 
   1050     Frame* frame = focusedWebCoreFrame();
   1051     if (!frame)
   1052         return suppress;
   1053 
   1054     EventHandler* handler = frame->eventHandler();
   1055     if (!handler)
   1056         return suppress || keyEventDefault(event);
   1057 
   1058     PlatformKeyboardEventBuilder evt(event);
   1059     if (!evt.isCharacterKey())
   1060         return true;
   1061 
   1062     // Accesskeys are triggered by char events and can't be suppressed.
   1063     if (handler->handleAccessKey(evt))
   1064         return true;
   1065 
   1066     // Safari 3.1 does not pass off windows system key messages (WM_SYSCHAR) to
   1067     // the eventHandler::keyEvent. We mimic this behavior on all platforms since
   1068     // for now we are converting other platform's key events to windows key
   1069     // events.
   1070     if (evt.isSystemKey())
   1071         return false;
   1072 
   1073     if (!suppress && !handler->keyEvent(evt))
   1074         return keyEventDefault(event);
   1075 
   1076     return true;
   1077 }
   1078 
   1079 WebRect WebViewImpl::computeBlockBounds(const WebRect& rect, bool ignoreClipping)
   1080 {
   1081     if (!mainFrameImpl())
   1082         return WebRect();
   1083 
   1084     // Use the rect-based hit test to find the node.
   1085     IntPoint point = mainFrameImpl()->frameView()->windowToContents(IntPoint(rect.x, rect.y));
   1086     HitTestRequest::HitTestRequestType hitType = HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::DisallowShadowContent | (ignoreClipping ? HitTestRequest::IgnoreClipping : 0);
   1087     HitTestResult result = mainFrameImpl()->frame()->eventHandler()->hitTestResultAtPoint(point, hitType, IntSize(rect.width, rect.height));
   1088 
   1089     Node* node = result.innerNonSharedNode();
   1090     if (!node)
   1091         return WebRect();
   1092 
   1093     // Find the block type node based on the hit node.
   1094     while (node && (!node->renderer() || node->renderer()->isInline()))
   1095         node = node->parentNode();
   1096 
   1097     // Return the bounding box in the window coordinate system.
   1098     if (node) {
   1099         IntRect rect = node->Node::pixelSnappedBoundingBox();
   1100         Frame* frame = node->document()->frame();
   1101         return frame->view()->contentsToWindow(rect);
   1102     }
   1103     return WebRect();
   1104 }
   1105 
   1106 WebRect WebViewImpl::widenRectWithinPageBounds(const WebRect& source, int targetMargin, int minimumMargin)
   1107 {
   1108     WebSize maxSize;
   1109     if (mainFrame())
   1110         maxSize = mainFrame()->contentsSize();
   1111     IntSize scrollOffset;
   1112     if (mainFrame())
   1113         scrollOffset = mainFrame()->scrollOffset();
   1114     int leftMargin = targetMargin;
   1115     int rightMargin = targetMargin;
   1116 
   1117     const int absoluteSourceX = source.x + scrollOffset.width();
   1118     if (leftMargin > absoluteSourceX) {
   1119         leftMargin = absoluteSourceX;
   1120         rightMargin = max(leftMargin, minimumMargin);
   1121     }
   1122 
   1123     const int maximumRightMargin = maxSize.width - (source.width + absoluteSourceX);
   1124     if (rightMargin > maximumRightMargin) {
   1125         rightMargin = maximumRightMargin;
   1126         leftMargin = min(leftMargin, max(rightMargin, minimumMargin));
   1127     }
   1128 
   1129     const int newWidth = source.width + leftMargin + rightMargin;
   1130     const int newX = source.x - leftMargin;
   1131 
   1132     ASSERT(newWidth >= 0);
   1133     ASSERT(scrollOffset.width() + newX + newWidth <= maxSize.width);
   1134 
   1135     return WebRect(newX, source.y, newWidth, source.height);
   1136 }
   1137 
   1138 void WebViewImpl::computeScaleAndScrollForBlockRect(const WebPoint& hitPoint, const WebRect& blockRect, float padding, float& scale, WebPoint& scroll, bool& doubleTapShouldZoomOut)
   1139 {
   1140     scale = pageScaleFactor();
   1141     scroll.x = scroll.y = 0;
   1142 
   1143     WebRect rect = blockRect;
   1144 
   1145     bool scaleUnchanged = true;
   1146     if (!rect.isEmpty()) {
   1147         // Pages should be as legible as on desktop when at dpi scale, so no
   1148         // need to zoom in further when automatically determining zoom level
   1149         // (after double tap, find in page, etc), though the user should still
   1150         // be allowed to manually pinch zoom in further if they desire.
   1151         const float defaultScaleWhenAlreadyLegible = minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio;
   1152         float legibleScale = 1;
   1153         if (page() && page()->settings())
   1154             legibleScale *= page()->settings()->textAutosizingFontScaleFactor();
   1155         if (legibleScale < defaultScaleWhenAlreadyLegible)
   1156             legibleScale = (scale == minimumPageScaleFactor()) ? defaultScaleWhenAlreadyLegible : minimumPageScaleFactor();
   1157 
   1158         float defaultMargin = doubleTapZoomContentDefaultMargin;
   1159         float minimumMargin = doubleTapZoomContentMinimumMargin;
   1160         // We want the margins to have the same physical size, which means we
   1161         // need to express them in post-scale size. To do that we'd need to know
   1162         // the scale we're scaling to, but that depends on the margins. Instead
   1163         // we express them as a fraction of the target rectangle: this will be
   1164         // correct if we end up fully zooming to it, and won't matter if we
   1165         // don't.
   1166         rect = widenRectWithinPageBounds(rect,
   1167                 static_cast<int>(defaultMargin * rect.width / m_size.width),
   1168                 static_cast<int>(minimumMargin * rect.width / m_size.width));
   1169         // Fit block to screen, respecting limits.
   1170         scale = static_cast<float>(m_size.width) / rect.width;
   1171         scale = min(scale, legibleScale);
   1172         scale = clampPageScaleFactorToLimits(scale);
   1173 
   1174         scaleUnchanged = fabs(pageScaleFactor() - scale) < minScaleDifference;
   1175     }
   1176 
   1177     bool stillAtPreviousDoubleTapScale = (pageScaleFactor() == m_doubleTapZoomPageScaleFactor
   1178         && m_doubleTapZoomPageScaleFactor != minimumPageScaleFactor())
   1179         || m_doubleTapZoomPending;
   1180 
   1181     doubleTapShouldZoomOut = rect.isEmpty() || scaleUnchanged || stillAtPreviousDoubleTapScale;
   1182 
   1183     // FIXME: If this is being called for auto zoom during find in page,
   1184     // then if the user manually zooms in it'd be nice to preserve the
   1185     // relative increase in zoom they caused (if they zoom out then it's ok
   1186     // to zoom them back in again). This isn't compatible with our current
   1187     // double-tap zoom strategy (fitting the containing block to the screen)
   1188     // though.
   1189 
   1190     float screenWidth = m_size.width / scale;
   1191     float screenHeight = m_size.height / scale;
   1192 
   1193     // Scroll to vertically align the block.
   1194     if (rect.height < screenHeight) {
   1195         // Vertically center short blocks.
   1196         rect.y -= 0.5 * (screenHeight - rect.height);
   1197     } else {
   1198         // Ensure position we're zooming to (+ padding) isn't off the bottom of
   1199         // the screen.
   1200         rect.y = max<float>(rect.y, hitPoint.y + padding - screenHeight);
   1201     } // Otherwise top align the block.
   1202 
   1203     // Do the same thing for horizontal alignment.
   1204     if (rect.width < screenWidth)
   1205         rect.x -= 0.5 * (screenWidth - rect.width);
   1206     else
   1207         rect.x = max<float>(rect.x, hitPoint.x + padding - screenWidth);
   1208     scroll.x = rect.x;
   1209     scroll.y = rect.y;
   1210 
   1211     scale = clampPageScaleFactorToLimits(scale);
   1212     scroll = mainFrameImpl()->frameView()->windowToContents(scroll);
   1213     scroll = clampOffsetAtScale(scroll, scale);
   1214 }
   1215 
   1216 static bool invokesHandCursor(Node* node, bool shiftKey, Frame* frame)
   1217 {
   1218     if (!node || !node->renderer())
   1219         return false;
   1220 
   1221     ECursor cursor = node->renderer()->style()->cursor();
   1222     return cursor == CURSOR_POINTER
   1223         || (cursor == CURSOR_AUTO && frame->eventHandler()->useHandCursor(node, node->isLink(), shiftKey));
   1224 }
   1225 
   1226 Node* WebViewImpl::bestTapNode(const PlatformGestureEvent& tapEvent)
   1227 {
   1228     if (!m_page || !m_page->mainFrame())
   1229         return 0;
   1230 
   1231     Node* bestTouchNode = 0;
   1232 
   1233     IntPoint touchEventLocation(tapEvent.position());
   1234     m_page->mainFrame()->eventHandler()->adjustGesturePosition(tapEvent, touchEventLocation);
   1235 
   1236     IntPoint hitTestPoint = m_page->mainFrame()->view()->windowToContents(touchEventLocation);
   1237     HitTestResult result = m_page->mainFrame()->eventHandler()->hitTestResultAtPoint(hitTestPoint, HitTestRequest::TouchEvent | HitTestRequest::DisallowShadowContent);
   1238     bestTouchNode = result.targetNode();
   1239 
   1240     Node* originalTouchNode = bestTouchNode;
   1241 
   1242     // Check if we're in the subtree of a node with a hand cursor, our heuristic to choose the appropriate target.
   1243     while (bestTouchNode && !invokesHandCursor(bestTouchNode, false, m_page->mainFrame()))
   1244         bestTouchNode = bestTouchNode->parentNode();
   1245 
   1246     if (!bestTouchNode)
   1247         return 0;
   1248 
   1249     // FIXME: http://crbug.com/289764 - Instead of stopping early on isContainedInParentBoundingBox, LinkHighlight
   1250     // should calculate the appropriate rects (currently it just uses the linebox)
   1251     // FIXME: Remove check for isLayerModelObject once LinkHighlight is fixed to use RenderObject
   1252 
   1253     // We now walk up the tree as before except we stop early if the node isn't contained in its parent's rect.
   1254     bestTouchNode = originalTouchNode;
   1255 
   1256     // FIXME: Refactor this to use renderer rather than node. All these loops can probably be merged into something cleaner
   1257     while (bestTouchNode && !invokesHandCursor(bestTouchNode, false, m_page->mainFrame())
   1258         && bestTouchNode->renderer() && (!bestTouchNode->renderer()->isLayerModelObject() || bestTouchNode->renderer()->isContainedInParentBoundingBox()))
   1259         bestTouchNode = bestTouchNode->parentNode();
   1260 
   1261     // We should pick the largest enclosing node with hand cursor set.
   1262     while (bestTouchNode && bestTouchNode->parentNode() && invokesHandCursor(bestTouchNode->parentNode(), false, m_page->mainFrame())
   1263         && bestTouchNode->renderer() && (!bestTouchNode->renderer()->isLayerModelObject() || bestTouchNode->renderer()->isContainedInParentBoundingBox()))
   1264         bestTouchNode = bestTouchNode->parentNode();
   1265 
   1266     // FIXME: Remove check for isLayerModelObject once LinkHighlight is fixed to use RenderObject
   1267     if (!bestTouchNode || !bestTouchNode->renderer() || !bestTouchNode->renderer()->isLayerModelObject())
   1268         return 0;
   1269 
   1270     return bestTouchNode;
   1271 }
   1272 
   1273 void WebViewImpl::enableTapHighlight(const PlatformGestureEvent& tapEvent)
   1274 {
   1275     // Always clear any existing highlight when this is invoked, even if we don't get a new target to highlight.
   1276     m_linkHighlight.clear();
   1277 
   1278     Node* touchNode = bestTapNode(tapEvent);
   1279 
   1280     if (!touchNode || !touchNode->renderer() || !touchNode->renderer()->enclosingLayer())
   1281         return;
   1282 
   1283     Color highlightColor = touchNode->renderer()->resolveColor(CSSPropertyWebkitTapHighlightColor);
   1284     // Safari documentation for -webkit-tap-highlight-color says if the specified color has 0 alpha,
   1285     // then tap highlighting is disabled.
   1286     // http://developer.apple.com/library/safari/#documentation/appleapplications/reference/safaricssref/articles/standardcssproperties.html
   1287     if (!highlightColor.alpha())
   1288         return;
   1289 
   1290     m_linkHighlight = LinkHighlight::create(touchNode, this);
   1291 }
   1292 
   1293 void WebViewImpl::animateDoubleTapZoom(const IntPoint& point)
   1294 {
   1295     if (!mainFrameImpl())
   1296         return;
   1297 
   1298     WebRect rect(point.x(), point.y(), touchPointPadding, touchPointPadding);
   1299     WebRect blockBounds = computeBlockBounds(rect, false);
   1300 
   1301     float scale;
   1302     WebPoint scroll;
   1303     bool doubleTapShouldZoomOut;
   1304 
   1305     computeScaleAndScrollForBlockRect(point, blockBounds, touchPointPadding, scale, scroll, doubleTapShouldZoomOut);
   1306 
   1307     bool isAnimating;
   1308 
   1309     if (doubleTapShouldZoomOut) {
   1310         scale = minimumPageScaleFactor();
   1311         isAnimating = startPageScaleAnimation(mainFrameImpl()->frameView()->windowToContents(point), true, scale, doubleTapZoomAnimationDurationInSeconds);
   1312     } else {
   1313         isAnimating = startPageScaleAnimation(scroll, false, scale, doubleTapZoomAnimationDurationInSeconds);
   1314     }
   1315 
   1316     if (isAnimating) {
   1317         m_doubleTapZoomPageScaleFactor = scale;
   1318         m_doubleTapZoomPending = true;
   1319     }
   1320 }
   1321 
   1322 void WebViewImpl::zoomToFindInPageRect(const WebRect& rect)
   1323 {
   1324     if (!mainFrameImpl())
   1325         return;
   1326 
   1327     WebRect blockBounds = computeBlockBounds(rect, true);
   1328 
   1329     if (blockBounds.isEmpty()) {
   1330         // Keep current scale (no need to scroll as x,y will normally already
   1331         // be visible). FIXME: Revisit this if it isn't always true.
   1332         return;
   1333     }
   1334 
   1335     float scale;
   1336     WebPoint scroll;
   1337     bool doubleTapShouldZoomOut;
   1338 
   1339     computeScaleAndScrollForBlockRect(WebPoint(rect.x, rect.y), blockBounds, nonUserInitiatedPointPadding, scale, scroll, doubleTapShouldZoomOut);
   1340 
   1341     startPageScaleAnimation(scroll, false, scale, findInPageAnimationDurationInSeconds);
   1342 }
   1343 
   1344 bool WebViewImpl::zoomToMultipleTargetsRect(const WebRect& rect)
   1345 {
   1346     if (!mainFrameImpl())
   1347         return false;
   1348 
   1349     float scale;
   1350     WebPoint scroll;
   1351     bool doubleTapShouldZoomOut;
   1352 
   1353     computeScaleAndScrollForBlockRect(WebPoint(rect.x, rect.y), rect, nonUserInitiatedPointPadding, scale, scroll, doubleTapShouldZoomOut);
   1354 
   1355     if (scale <= pageScaleFactor())
   1356         return false;
   1357 
   1358     startPageScaleAnimation(scroll, false, scale, multipleTargetsZoomAnimationDurationInSeconds);
   1359     return true;
   1360 }
   1361 
   1362 void WebViewImpl::numberOfWheelEventHandlersChanged(unsigned numberOfWheelHandlers)
   1363 {
   1364     if (m_client)
   1365         m_client->numberOfWheelEventHandlersChanged(numberOfWheelHandlers);
   1366 }
   1367 
   1368 void WebViewImpl::hasTouchEventHandlers(bool hasTouchHandlers)
   1369 {
   1370     if (m_client)
   1371         m_client->hasTouchEventHandlers(hasTouchHandlers);
   1372 }
   1373 
   1374 bool WebViewImpl::hasTouchEventHandlersAt(const WebPoint& point)
   1375 {
   1376     // FIXME: Implement this. Note that the point must be divided by pageScaleFactor.
   1377     return true;
   1378 }
   1379 
   1380 #if !OS(DARWIN)
   1381 // Mac has no way to open a context menu based on a keyboard event.
   1382 bool WebViewImpl::sendContextMenuEvent(const WebKeyboardEvent& event)
   1383 {
   1384     // The contextMenuController() holds onto the last context menu that was
   1385     // popped up on the page until a new one is created. We need to clear
   1386     // this menu before propagating the event through the DOM so that we can
   1387     // detect if we create a new menu for this event, since we won't create
   1388     // a new menu if the DOM swallows the event and the defaultEventHandler does
   1389     // not run.
   1390     page()->contextMenuController()->clearContextMenu();
   1391 
   1392     m_contextMenuAllowed = true;
   1393     Frame* focusedFrame = page()->focusController().focusedOrMainFrame();
   1394     bool handled = focusedFrame->eventHandler()->sendContextMenuEventForKey();
   1395     m_contextMenuAllowed = false;
   1396     return handled;
   1397 }
   1398 #endif
   1399 
   1400 bool WebViewImpl::keyEventDefault(const WebKeyboardEvent& event)
   1401 {
   1402     Frame* frame = focusedWebCoreFrame();
   1403     if (!frame)
   1404         return false;
   1405 
   1406     switch (event.type) {
   1407     case WebInputEvent::Char:
   1408         if (event.windowsKeyCode == VKEY_SPACE) {
   1409             int keyCode = ((event.modifiers & WebInputEvent::ShiftKey) ? VKEY_PRIOR : VKEY_NEXT);
   1410             return scrollViewWithKeyboard(keyCode, event.modifiers);
   1411         }
   1412         break;
   1413     case WebInputEvent::RawKeyDown:
   1414         if (event.modifiers == WebInputEvent::ControlKey) {
   1415             switch (event.windowsKeyCode) {
   1416 #if !OS(DARWIN)
   1417             case 'A':
   1418                 focusedFrame()->executeCommand(WebString::fromUTF8("SelectAll"));
   1419                 return true;
   1420             case VKEY_INSERT:
   1421             case 'C':
   1422                 focusedFrame()->executeCommand(WebString::fromUTF8("Copy"));
   1423                 return true;
   1424 #endif
   1425             // Match FF behavior in the sense that Ctrl+home/end are the only Ctrl
   1426             // key combinations which affect scrolling. Safari is buggy in the
   1427             // sense that it scrolls the page for all Ctrl+scrolling key
   1428             // combinations. For e.g. Ctrl+pgup/pgdn/up/down, etc.
   1429             case VKEY_HOME:
   1430             case VKEY_END:
   1431                 break;
   1432             default:
   1433                 return false;
   1434             }
   1435         }
   1436         if (!event.isSystemKey && !(event.modifiers & WebInputEvent::ShiftKey))
   1437             return scrollViewWithKeyboard(event.windowsKeyCode, event.modifiers);
   1438         break;
   1439     default:
   1440         break;
   1441     }
   1442     return false;
   1443 }
   1444 
   1445 bool WebViewImpl::scrollViewWithKeyboard(int keyCode, int modifiers)
   1446 {
   1447     ScrollDirection scrollDirection;
   1448     ScrollGranularity scrollGranularity;
   1449 #if OS(DARWIN)
   1450     // Control-Up/Down should be PageUp/Down on Mac.
   1451     if (modifiers & WebMouseEvent::ControlKey) {
   1452       if (keyCode == VKEY_UP)
   1453         keyCode = VKEY_PRIOR;
   1454       else if (keyCode == VKEY_DOWN)
   1455         keyCode = VKEY_NEXT;
   1456     }
   1457 #endif
   1458     if (!mapKeyCodeForScroll(keyCode, &scrollDirection, &scrollGranularity))
   1459         return false;
   1460     return propagateScroll(scrollDirection, scrollGranularity);
   1461 }
   1462 
   1463 bool WebViewImpl::mapKeyCodeForScroll(int keyCode,
   1464                                       WebCore::ScrollDirection* scrollDirection,
   1465                                       WebCore::ScrollGranularity* scrollGranularity)
   1466 {
   1467     switch (keyCode) {
   1468     case VKEY_LEFT:
   1469         *scrollDirection = ScrollLeft;
   1470         *scrollGranularity = ScrollByLine;
   1471         break;
   1472     case VKEY_RIGHT:
   1473         *scrollDirection = ScrollRight;
   1474         *scrollGranularity = ScrollByLine;
   1475         break;
   1476     case VKEY_UP:
   1477         *scrollDirection = ScrollUp;
   1478         *scrollGranularity = ScrollByLine;
   1479         break;
   1480     case VKEY_DOWN:
   1481         *scrollDirection = ScrollDown;
   1482         *scrollGranularity = ScrollByLine;
   1483         break;
   1484     case VKEY_HOME:
   1485         *scrollDirection = ScrollUp;
   1486         *scrollGranularity = ScrollByDocument;
   1487         break;
   1488     case VKEY_END:
   1489         *scrollDirection = ScrollDown;
   1490         *scrollGranularity = ScrollByDocument;
   1491         break;
   1492     case VKEY_PRIOR:  // page up
   1493         *scrollDirection = ScrollUp;
   1494         *scrollGranularity = ScrollByPage;
   1495         break;
   1496     case VKEY_NEXT:  // page down
   1497         *scrollDirection = ScrollDown;
   1498         *scrollGranularity = ScrollByPage;
   1499         break;
   1500     default:
   1501         return false;
   1502     }
   1503 
   1504     return true;
   1505 }
   1506 
   1507 void WebViewImpl::hideSelectPopup()
   1508 {
   1509     if (m_selectPopup)
   1510         m_selectPopup->hidePopup();
   1511 }
   1512 
   1513 bool WebViewImpl::propagateScroll(ScrollDirection scrollDirection,
   1514                                   ScrollGranularity scrollGranularity)
   1515 {
   1516     Frame* frame = focusedWebCoreFrame();
   1517     if (!frame)
   1518         return false;
   1519 
   1520     bool scrollHandled = frame->eventHandler()->scrollOverflow(scrollDirection, scrollGranularity);
   1521     Frame* currentFrame = frame;
   1522     while (!scrollHandled && currentFrame) {
   1523         scrollHandled = currentFrame->view()->scroll(scrollDirection, scrollGranularity);
   1524         currentFrame = currentFrame->tree()->parent();
   1525     }
   1526     return scrollHandled;
   1527 }
   1528 
   1529 void  WebViewImpl::popupOpened(WebCore::PopupContainer* popupContainer)
   1530 {
   1531     if (popupContainer->popupType() == WebCore::PopupContainer::Select) {
   1532         ASSERT(!m_selectPopup);
   1533         m_selectPopup = popupContainer;
   1534     }
   1535 }
   1536 
   1537 void  WebViewImpl::popupClosed(WebCore::PopupContainer* popupContainer)
   1538 {
   1539     if (popupContainer->popupType() == WebCore::PopupContainer::Select) {
   1540         ASSERT(m_selectPopup);
   1541         m_selectPopup = 0;
   1542     }
   1543 }
   1544 
   1545 PagePopup* WebViewImpl::openPagePopup(PagePopupClient* client, const IntRect& originBoundsInRootView)
   1546 {
   1547     ASSERT(client);
   1548     if (hasOpenedPopup())
   1549         hidePopups();
   1550     ASSERT(!m_pagePopup);
   1551 
   1552     WebWidget* popupWidget = m_client->createPopupMenu(WebPopupTypePage);
   1553     ASSERT(popupWidget);
   1554     m_pagePopup = static_cast<WebPagePopupImpl*>(popupWidget);
   1555     if (!m_pagePopup->initialize(this, client, originBoundsInRootView)) {
   1556         m_pagePopup->closePopup();
   1557         m_pagePopup = 0;
   1558     }
   1559     return m_pagePopup.get();
   1560 }
   1561 
   1562 void WebViewImpl::closePagePopup(PagePopup* popup)
   1563 {
   1564     ASSERT(popup);
   1565     WebPagePopupImpl* popupImpl = static_cast<WebPagePopupImpl*>(popup);
   1566     ASSERT(m_pagePopup.get() == popupImpl);
   1567     if (m_pagePopup.get() != popupImpl)
   1568         return;
   1569     m_pagePopup->closePopup();
   1570     m_pagePopup = 0;
   1571 }
   1572 
   1573 void WebViewImpl::hideAutofillPopup()
   1574 {
   1575     if (m_autofillPopupShowing) {
   1576         m_autofillPopup->hidePopup();
   1577         m_autofillPopupShowing = false;
   1578     }
   1579 }
   1580 
   1581 WebHelperPluginImpl* WebViewImpl::createHelperPlugin(const String& pluginType, const WebDocument& hostDocument)
   1582 {
   1583     WebWidget* popupWidget = m_client->createPopupMenu(WebPopupTypeHelperPlugin);
   1584     ASSERT(popupWidget);
   1585     WebHelperPluginImpl* helperPlugin = static_cast<WebHelperPluginImpl*>(popupWidget);
   1586 
   1587     if (!helperPlugin->initialize(pluginType, hostDocument, this)) {
   1588         helperPlugin->closeHelperPlugin();
   1589         helperPlugin = 0;
   1590     }
   1591     return helperPlugin;
   1592 }
   1593 
   1594 void WebViewImpl::closeHelperPluginSoon(PassRefPtr<WebHelperPluginImpl> helperPlugin)
   1595 {
   1596     m_helperPluginsPendingClose.append(helperPlugin);
   1597     if (!m_helperPluginCloseTimer.isActive())
   1598         m_helperPluginCloseTimer.startOneShot(0);
   1599 }
   1600 
   1601 void WebViewImpl::closePendingHelperPlugins(Timer<WebViewImpl>* timer)
   1602 {
   1603     ASSERT_UNUSED(timer, !timer || timer == &m_helperPluginCloseTimer);
   1604     ASSERT(!m_helperPluginsPendingClose.isEmpty());
   1605 
   1606     Vector<RefPtr<WebHelperPluginImpl> > helperPlugins;
   1607     helperPlugins.swap(m_helperPluginsPendingClose);
   1608     for (Vector<RefPtr<WebHelperPluginImpl> >::iterator it = helperPlugins.begin();
   1609         it != helperPlugins.end(); ++it) {
   1610         (*it)->closeHelperPlugin();
   1611     }
   1612     ASSERT(m_helperPluginsPendingClose.isEmpty());
   1613 }
   1614 
   1615 Frame* WebViewImpl::focusedWebCoreFrame() const
   1616 {
   1617     return m_page ? m_page->focusController().focusedOrMainFrame() : 0;
   1618 }
   1619 
   1620 WebViewImpl* WebViewImpl::fromPage(Page* page)
   1621 {
   1622     if (!page)
   1623         return 0;
   1624 
   1625     ChromeClientImpl* chromeClient = static_cast<ChromeClientImpl*>(page->chrome().client());
   1626     return static_cast<WebViewImpl*>(chromeClient->webView());
   1627 }
   1628 
   1629 // WebWidget ------------------------------------------------------------------
   1630 
   1631 void WebViewImpl::close()
   1632 {
   1633     if (m_page) {
   1634         // Initiate shutdown for the entire frameset.  This will cause a lot of
   1635         // notifications to be sent.
   1636         if (m_page->mainFrame())
   1637             m_page->mainFrame()->loader()->frameDetached();
   1638 
   1639         m_page.clear();
   1640     }
   1641 
   1642     // Should happen after m_page.clear().
   1643     if (m_devToolsAgent)
   1644         m_devToolsAgent.clear();
   1645 
   1646     // Helper Plugins must be closed now since doing so accesses RenderViewImpl,
   1647     // which will be destroyed after this function returns.
   1648     if (m_helperPluginCloseTimer.isActive()) {
   1649         m_helperPluginCloseTimer.stop();
   1650         closePendingHelperPlugins(0);
   1651     }
   1652 
   1653     // Reset the delegate to prevent notifications being sent as we're being
   1654     // deleted.
   1655     m_client = 0;
   1656 
   1657     deref();  // Balances ref() acquired in WebView::create
   1658 }
   1659 
   1660 void WebViewImpl::willStartLiveResize()
   1661 {
   1662     if (mainFrameImpl() && mainFrameImpl()->frameView())
   1663         mainFrameImpl()->frameView()->willStartLiveResize();
   1664 
   1665     Frame* frame = mainFrameImpl()->frame();
   1666     WebPluginContainerImpl* pluginContainer = WebFrameImpl::pluginContainerFromFrame(frame);
   1667     if (pluginContainer)
   1668         pluginContainer->willStartLiveResize();
   1669 }
   1670 
   1671 WebSize WebViewImpl::size()
   1672 {
   1673     return m_size;
   1674 }
   1675 
   1676 void WebViewImpl::resize(const WebSize& newSize)
   1677 {
   1678     if (m_shouldAutoResize || m_size == newSize)
   1679         return;
   1680 
   1681     FrameView* view = mainFrameImpl()->frameView();
   1682     if (!view)
   1683         return;
   1684 
   1685     WebSize oldSize = m_size;
   1686     float oldPageScaleFactor = pageScaleFactor();
   1687     int oldContentsWidth = contentsSize().width();
   1688 
   1689     m_size = newSize;
   1690 
   1691     bool shouldAnchorAndRescaleViewport = settings()->viewportEnabled() && oldSize.width && oldContentsWidth;
   1692     ViewportAnchor viewportAnchor(mainFrameImpl()->frame()->eventHandler());
   1693     if (shouldAnchorAndRescaleViewport) {
   1694         viewportAnchor.setAnchor(view->visibleContentRect(),
   1695                                  FloatSize(viewportAnchorXCoord, viewportAnchorYCoord));
   1696     }
   1697 
   1698     // Set the fixed layout size from the viewport constraints before resizing.
   1699     updatePageDefinedPageScaleConstraints(mainFrameImpl()->frame()->document()->viewportArguments());
   1700 
   1701     WebDevToolsAgentPrivate* agentPrivate = devToolsAgentPrivate();
   1702     if (agentPrivate)
   1703         agentPrivate->webViewResized(newSize);
   1704     if (!agentPrivate || !agentPrivate->metricsOverridden()) {
   1705         WebFrameImpl* webFrame = mainFrameImpl();
   1706         if (webFrame->frameView()) {
   1707             webFrame->frameView()->resize(m_size);
   1708             if (m_pinchViewports)
   1709                 m_pinchViewports->setViewportSize(m_size);
   1710         }
   1711     }
   1712 
   1713     if (settings()->viewportEnabled() && !m_fixedLayoutSizeLock) {
   1714         // Relayout immediately to recalculate the minimum scale limit.
   1715         if (view->needsLayout())
   1716             view->layout();
   1717 
   1718         if (shouldAnchorAndRescaleViewport) {
   1719             float viewportWidthRatio = static_cast<float>(newSize.width) / oldSize.width;
   1720             float contentsWidthRatio = static_cast<float>(contentsSize().width()) / oldContentsWidth;
   1721             float scaleMultiplier = viewportWidthRatio / contentsWidthRatio;
   1722 
   1723             IntSize viewportSize = view->visibleContentRect().size();
   1724             if (scaleMultiplier != 1) {
   1725                 float newPageScaleFactor = oldPageScaleFactor * scaleMultiplier;
   1726                 viewportSize.scale(pageScaleFactor() / newPageScaleFactor);
   1727                 IntPoint scrollOffsetAtNewScale = viewportAnchor.computeOrigin(viewportSize);
   1728                 setPageScaleFactor(newPageScaleFactor, scrollOffsetAtNewScale);
   1729             } else {
   1730                 IntPoint scrollOffsetAtNewScale = clampOffsetAtScale(viewportAnchor.computeOrigin(viewportSize), pageScaleFactor());
   1731                 updateMainFrameScrollPosition(scrollOffsetAtNewScale, false);
   1732             }
   1733         }
   1734     }
   1735 
   1736     sendResizeEventAndRepaint();
   1737 }
   1738 
   1739 void WebViewImpl::willEndLiveResize()
   1740 {
   1741     if (mainFrameImpl() && mainFrameImpl()->frameView())
   1742         mainFrameImpl()->frameView()->willEndLiveResize();
   1743 
   1744     Frame* frame = mainFrameImpl()->frame();
   1745     WebPluginContainerImpl* pluginContainer = WebFrameImpl::pluginContainerFromFrame(frame);
   1746     if (pluginContainer)
   1747         pluginContainer->willEndLiveResize();
   1748 }
   1749 
   1750 void WebViewImpl::willEnterFullScreen()
   1751 {
   1752     m_fullscreenController->willEnterFullScreen();
   1753 }
   1754 
   1755 void WebViewImpl::didEnterFullScreen()
   1756 {
   1757     m_fullscreenController->didEnterFullScreen();
   1758 }
   1759 
   1760 void WebViewImpl::willExitFullScreen()
   1761 {
   1762     m_fullscreenController->willExitFullScreen();
   1763 }
   1764 
   1765 void WebViewImpl::didExitFullScreen()
   1766 {
   1767     m_fullscreenController->didExitFullScreen();
   1768 }
   1769 
   1770 void WebViewImpl::animate(double monotonicFrameBeginTime)
   1771 {
   1772     TRACE_EVENT0("webkit", "WebViewImpl::animate");
   1773 
   1774     if (!monotonicFrameBeginTime)
   1775         monotonicFrameBeginTime = monotonicallyIncreasingTime();
   1776 
   1777     // Create synthetic wheel events as necessary for fling.
   1778     if (m_gestureAnimation) {
   1779         if (m_gestureAnimation->animate(monotonicFrameBeginTime))
   1780             scheduleAnimation();
   1781         else {
   1782             m_gestureAnimation.clear();
   1783             if (m_layerTreeView)
   1784                 m_layerTreeView->didStopFlinging();
   1785 
   1786             PlatformGestureEvent endScrollEvent(PlatformEvent::GestureScrollEnd,
   1787                 m_positionOnFlingStart, m_globalPositionOnFlingStart, 0, 0, 0,
   1788                 false, false, false, false);
   1789 
   1790             mainFrameImpl()->frame()->eventHandler()->handleGestureScrollEnd(endScrollEvent);
   1791         }
   1792     }
   1793 
   1794     if (!m_page)
   1795         return;
   1796 
   1797     PageWidgetDelegate::animate(m_page.get(), monotonicFrameBeginTime);
   1798 
   1799     if (m_continuousPaintingEnabled) {
   1800         ContinuousPainter::setNeedsDisplayRecursive(m_rootGraphicsLayer, m_pageOverlays.get());
   1801         m_client->scheduleAnimation();
   1802     }
   1803 }
   1804 
   1805 void WebViewImpl::layout()
   1806 {
   1807     TRACE_EVENT0("webkit", "WebViewImpl::layout");
   1808     PageWidgetDelegate::layout(m_page.get());
   1809     if (m_layerTreeView)
   1810         m_layerTreeView->setBackgroundColor(backgroundColor());
   1811 
   1812     if (m_linkHighlight)
   1813         m_linkHighlight->updateGeometry();
   1814 }
   1815 
   1816 void WebViewImpl::enterForceCompositingMode(bool enter)
   1817 {
   1818     if (page()->settings()->forceCompositingMode() == enter)
   1819         return;
   1820 
   1821     TRACE_EVENT1("webkit", "WebViewImpl::enterForceCompositingMode", "enter", enter);
   1822     settingsImpl()->setForceCompositingMode(enter);
   1823     if (enter) {
   1824         if (!m_page)
   1825             return;
   1826         Frame* mainFrame = m_page->mainFrame();
   1827         if (!mainFrame)
   1828             return;
   1829         mainFrame->view()->updateCompositingLayersAfterStyleChange();
   1830     }
   1831 }
   1832 
   1833 void WebViewImpl::doPixelReadbackToCanvas(WebCanvas* canvas, const IntRect& rect)
   1834 {
   1835     ASSERT(m_layerTreeView);
   1836 
   1837     SkBitmap target;
   1838     target.setConfig(SkBitmap::kARGB_8888_Config, rect.width(), rect.height(), rect.width() * 4);
   1839     target.allocPixels();
   1840     m_layerTreeView->compositeAndReadback(target.getPixels(), rect);
   1841 #if (!SK_R32_SHIFT && SK_B32_SHIFT == 16)
   1842     // The compositor readback always gives back pixels in BGRA order, but for
   1843     // example Android's Skia uses RGBA ordering so the red and blue channels
   1844     // need to be swapped.
   1845     uint8_t* pixels = reinterpret_cast<uint8_t*>(target.getPixels());
   1846     for (size_t i = 0; i < target.getSize(); i += 4)
   1847         std::swap(pixels[i], pixels[i + 2]);
   1848 #endif
   1849     canvas->writePixels(target, rect.x(), rect.y());
   1850 }
   1851 
   1852 void WebViewImpl::paint(WebCanvas* canvas, const WebRect& rect, PaintOptions option)
   1853 {
   1854 #if !OS(ANDROID)
   1855     // ReadbackFromCompositorIfAvailable is the only option available on non-Android.
   1856     // Ideally, Android would always use ReadbackFromCompositorIfAvailable as well.
   1857     ASSERT(option == ReadbackFromCompositorIfAvailable);
   1858 #endif
   1859 
   1860     if (option == ReadbackFromCompositorIfAvailable && isAcceleratedCompositingActive()) {
   1861         // If a canvas was passed in, we use it to grab a copy of the
   1862         // freshly-rendered pixels.
   1863         if (canvas) {
   1864             // Clip rect to the confines of the rootLayerTexture.
   1865             IntRect resizeRect(rect);
   1866             resizeRect.intersect(IntRect(IntPoint(0, 0), m_layerTreeView->deviceViewportSize()));
   1867             doPixelReadbackToCanvas(canvas, resizeRect);
   1868         }
   1869     } else {
   1870         FrameView* view = page()->mainFrame()->view();
   1871         PaintBehavior oldPaintBehavior = view->paintBehavior();
   1872         if (isAcceleratedCompositingActive()) {
   1873             ASSERT(option == ForceSoftwareRenderingAndIgnoreGPUResidentContent);
   1874             view->setPaintBehavior(oldPaintBehavior | PaintBehaviorFlattenCompositingLayers);
   1875         }
   1876 
   1877         double paintStart = currentTime();
   1878         PageWidgetDelegate::paint(m_page.get(), pageOverlays(), canvas, rect, isTransparent() ? PageWidgetDelegate::Translucent : PageWidgetDelegate::Opaque);
   1879         double paintEnd = currentTime();
   1880         double pixelsPerSec = (rect.width * rect.height) / (paintEnd - paintStart);
   1881         WebKit::Platform::current()->histogramCustomCounts("Renderer4.SoftwarePaintDurationMS", (paintEnd - paintStart) * 1000, 0, 120, 30);
   1882         WebKit::Platform::current()->histogramCustomCounts("Renderer4.SoftwarePaintMegapixPerSecond", pixelsPerSec / 1000000, 10, 210, 30);
   1883 
   1884         if (isAcceleratedCompositingActive()) {
   1885             ASSERT(option == ForceSoftwareRenderingAndIgnoreGPUResidentContent);
   1886             view->setPaintBehavior(oldPaintBehavior);
   1887         }
   1888     }
   1889 }
   1890 
   1891 bool WebViewImpl::isTrackingRepaints() const
   1892 {
   1893     if (!page())
   1894         return false;
   1895     FrameView* view = page()->mainFrame()->view();
   1896     return view->isTrackingRepaints();
   1897 }
   1898 
   1899 void WebViewImpl::themeChanged()
   1900 {
   1901     if (!page())
   1902         return;
   1903     FrameView* view = page()->mainFrame()->view();
   1904 
   1905     WebRect damagedRect(0, 0, m_size.width, m_size.height);
   1906     view->invalidateRect(damagedRect);
   1907 }
   1908 
   1909 void WebViewImpl::setNeedsRedraw()
   1910 {
   1911     if (m_layerTreeView && isAcceleratedCompositingActive())
   1912         m_layerTreeView->setNeedsRedraw();
   1913 }
   1914 
   1915 void WebViewImpl::enterFullScreenForElement(WebCore::Element* element)
   1916 {
   1917     m_fullscreenController->enterFullScreenForElement(element);
   1918 }
   1919 
   1920 void WebViewImpl::exitFullScreenForElement(WebCore::Element* element)
   1921 {
   1922     m_fullscreenController->exitFullScreenForElement(element);
   1923 }
   1924 
   1925 bool WebViewImpl::hasHorizontalScrollbar()
   1926 {
   1927     return mainFrameImpl()->frameView()->horizontalScrollbar();
   1928 }
   1929 
   1930 bool WebViewImpl::hasVerticalScrollbar()
   1931 {
   1932     return mainFrameImpl()->frameView()->verticalScrollbar();
   1933 }
   1934 
   1935 const WebInputEvent* WebViewImpl::m_currentInputEvent = 0;
   1936 
   1937 bool WebViewImpl::handleInputEvent(const WebInputEvent& inputEvent)
   1938 {
   1939     TRACE_EVENT0("input", "WebViewImpl::handleInputEvent");
   1940     // If we've started a drag and drop operation, ignore input events until
   1941     // we're done.
   1942     if (m_doingDragAndDrop)
   1943         return true;
   1944 
   1945     if (m_devToolsAgent && m_devToolsAgent->handleInputEvent(m_page.get(), inputEvent))
   1946         return true;
   1947 
   1948     // Report the event to be NOT processed by WebKit, so that the browser can handle it appropriately.
   1949     if (m_ignoreInputEvents)
   1950         return false;
   1951 
   1952     TemporaryChange<const WebInputEvent*> currentEventChange(m_currentInputEvent, &inputEvent);
   1953 
   1954     if (isPointerLocked() && WebInputEvent::isMouseEventType(inputEvent.type)) {
   1955       pointerLockMouseEvent(inputEvent);
   1956       return true;
   1957     }
   1958 
   1959     if (m_mouseCaptureNode && WebInputEvent::isMouseEventType(inputEvent.type)) {
   1960         TRACE_EVENT1("input", "captured mouse event", "type", inputEvent.type);
   1961         // Save m_mouseCaptureNode since mouseCaptureLost() will clear it.
   1962         RefPtr<Node> node = m_mouseCaptureNode;
   1963 
   1964         // Not all platforms call mouseCaptureLost() directly.
   1965         if (inputEvent.type == WebInputEvent::MouseUp)
   1966             mouseCaptureLost();
   1967 
   1968         AtomicString eventType;
   1969         switch (inputEvent.type) {
   1970         case WebInputEvent::MouseMove:
   1971             eventType = eventNames().mousemoveEvent;
   1972             break;
   1973         case WebInputEvent::MouseLeave:
   1974             eventType = eventNames().mouseoutEvent;
   1975             break;
   1976         case WebInputEvent::MouseDown:
   1977             eventType = eventNames().mousedownEvent;
   1978             break;
   1979         case WebInputEvent::MouseUp:
   1980             eventType = eventNames().mouseupEvent;
   1981             break;
   1982         default:
   1983             ASSERT_NOT_REACHED();
   1984         }
   1985 
   1986         node->dispatchMouseEvent(
   1987               PlatformMouseEventBuilder(mainFrameImpl()->frameView(), *static_cast<const WebMouseEvent*>(&inputEvent)),
   1988               eventType, static_cast<const WebMouseEvent*>(&inputEvent)->clickCount);
   1989         return true;
   1990     }
   1991 
   1992     return PageWidgetDelegate::handleInputEvent(m_page.get(), *this, inputEvent);
   1993 }
   1994 
   1995 void WebViewImpl::setCursorVisibilityState(bool isVisible)
   1996 {
   1997     if (m_page)
   1998         m_page->setIsCursorVisible(isVisible);
   1999 }
   2000 
   2001 void WebViewImpl::mouseCaptureLost()
   2002 {
   2003     TRACE_EVENT_ASYNC_END0("input", "capturing mouse", this);
   2004     m_mouseCaptureNode = 0;
   2005 }
   2006 
   2007 void WebViewImpl::setFocus(bool enable)
   2008 {
   2009     m_page->focusController().setFocused(enable);
   2010     if (enable) {
   2011         m_page->focusController().setActive(true);
   2012         RefPtr<Frame> focusedFrame = m_page->focusController().focusedFrame();
   2013         if (focusedFrame) {
   2014             Element* element = focusedFrame->document()->focusedElement();
   2015             if (element && focusedFrame->selection()->selection().isNone()) {
   2016                 // If the selection was cleared while the WebView was not
   2017                 // focused, then the focus element shows with a focus ring but
   2018                 // no caret and does respond to keyboard inputs.
   2019                 if (element->isTextFormControl()) {
   2020                     element->updateFocusAppearance(true);
   2021                 } else if (element->isContentEditable()) {
   2022                     // updateFocusAppearance() selects all the text of
   2023                     // contentseditable DIVs. So we set the selection explicitly
   2024                     // instead. Note that this has the side effect of moving the
   2025                     // caret back to the beginning of the text.
   2026                     Position position(element, 0, Position::PositionIsOffsetInAnchor);
   2027                     focusedFrame->selection()->setSelection(
   2028                         VisibleSelection(position, SEL_DEFAULT_AFFINITY));
   2029                 }
   2030             }
   2031         }
   2032         m_imeAcceptEvents = true;
   2033     } else {
   2034         hidePopups();
   2035 
   2036         // Clear focus on the currently focused frame if any.
   2037         if (!m_page)
   2038             return;
   2039 
   2040         Frame* frame = m_page->mainFrame();
   2041         if (!frame)
   2042             return;
   2043 
   2044         RefPtr<Frame> focusedFrame = m_page->focusController().focusedFrame();
   2045         if (focusedFrame) {
   2046             // Finish an ongoing composition to delete the composition node.
   2047             if (focusedFrame->inputMethodController().hasComposition()) {
   2048                 if (m_autofillClient)
   2049                     m_autofillClient->setIgnoreTextChanges(true);
   2050 
   2051                 focusedFrame->inputMethodController().confirmComposition();
   2052 
   2053                 if (m_autofillClient)
   2054                     m_autofillClient->setIgnoreTextChanges(false);
   2055             }
   2056             m_imeAcceptEvents = false;
   2057         }
   2058     }
   2059 }
   2060 
   2061 bool WebViewImpl::setComposition(
   2062     const WebString& text,
   2063     const WebVector<WebCompositionUnderline>& underlines,
   2064     int selectionStart,
   2065     int selectionEnd)
   2066 {
   2067     Frame* focused = focusedWebCoreFrame();
   2068     if (!focused || !m_imeAcceptEvents)
   2069         return false;
   2070     Editor* editor = focused->editor();
   2071     if (!editor)
   2072         return false;
   2073 
   2074     // The input focus has been moved to another WebWidget object.
   2075     // We should use this |editor| object only to complete the ongoing
   2076     // composition.
   2077     InputMethodController& inputMethodController = focused->inputMethodController();
   2078     if (!editor->canEdit() && !inputMethodController.hasComposition())
   2079         return false;
   2080 
   2081     // We should verify the parent node of this IME composition node are
   2082     // editable because JavaScript may delete a parent node of the composition
   2083     // node. In this case, WebKit crashes while deleting texts from the parent
   2084     // node, which doesn't exist any longer.
   2085     RefPtr<Range> range = inputMethodController.compositionRange();
   2086     if (range) {
   2087         Node* node = range->startContainer();
   2088         if (!node || !node->isContentEditable())
   2089             return false;
   2090     }
   2091 
   2092     // If we're not going to fire a keypress event, then the keydown event was
   2093     // canceled.  In that case, cancel any existing composition.
   2094     if (text.isEmpty() || m_suppressNextKeypressEvent) {
   2095         // A browser process sent an IPC message which does not contain a valid
   2096         // string, which means an ongoing composition has been canceled.
   2097         // If the ongoing composition has been canceled, replace the ongoing
   2098         // composition string with an empty string and complete it.
   2099         String emptyString;
   2100         Vector<CompositionUnderline> emptyUnderlines;
   2101         inputMethodController.setComposition(emptyString, emptyUnderlines, 0, 0);
   2102         return text.isEmpty();
   2103     }
   2104 
   2105     // When the range of composition underlines overlap with the range between
   2106     // selectionStart and selectionEnd, WebKit somehow won't paint the selection
   2107     // at all (see InlineTextBox::paint() function in InlineTextBox.cpp).
   2108     // But the selection range actually takes effect.
   2109     inputMethodController.setComposition(String(text),
   2110                            CompositionUnderlineVectorBuilder(underlines),
   2111                            selectionStart, selectionEnd);
   2112 
   2113     return inputMethodController.hasComposition();
   2114 }
   2115 
   2116 bool WebViewImpl::confirmComposition()
   2117 {
   2118     return confirmComposition(DoNotKeepSelection);
   2119 }
   2120 
   2121 bool WebViewImpl::confirmComposition(ConfirmCompositionBehavior selectionBehavior)
   2122 {
   2123     return confirmComposition(WebString(), selectionBehavior);
   2124 }
   2125 
   2126 bool WebViewImpl::confirmComposition(const WebString& text)
   2127 {
   2128     return confirmComposition(text, DoNotKeepSelection);
   2129 }
   2130 
   2131 bool WebViewImpl::confirmComposition(const WebString& text, ConfirmCompositionBehavior selectionBehavior)
   2132 {
   2133     Frame* focused = focusedWebCoreFrame();
   2134     if (!focused || !m_imeAcceptEvents)
   2135         return false;
   2136     Editor* editor = focused->editor();
   2137     InputMethodController& inputMethodController = focused->inputMethodController();
   2138     if (!editor || (!inputMethodController.hasComposition() && !text.length()))
   2139         return false;
   2140 
   2141     // We should verify the parent node of this IME composition node are
   2142     // editable because JavaScript may delete a parent node of the composition
   2143     // node. In this case, WebKit crashes while deleting texts from the parent
   2144     // node, which doesn't exist any longer.
   2145     RefPtr<Range> range = inputMethodController.compositionRange();
   2146     if (range) {
   2147         Node* node = range->startContainer();
   2148         if (!node || !node->isContentEditable())
   2149             return false;
   2150     }
   2151 
   2152     if (inputMethodController.hasComposition()) {
   2153         if (text.length()) {
   2154             inputMethodController.confirmComposition(String(text));
   2155         } else {
   2156             size_t location;
   2157             size_t length;
   2158             caretOrSelectionRange(&location, &length);
   2159 
   2160             inputMethodController.confirmComposition();
   2161             if (selectionBehavior == KeepSelection)
   2162                 editor->setSelectionOffsets(location, location + length);
   2163         }
   2164     } else
   2165         editor->insertText(String(text), 0);
   2166 
   2167     return true;
   2168 }
   2169 
   2170 bool WebViewImpl::compositionRange(size_t* location, size_t* length)
   2171 {
   2172     Frame* focused = focusedWebCoreFrame();
   2173     if (!focused || !focused->selection() || !m_imeAcceptEvents)
   2174         return false;
   2175 
   2176     RefPtr<Range> range = focused->inputMethodController().compositionRange();
   2177     if (!range)
   2178         return false;
   2179 
   2180     if (TextIterator::getLocationAndLengthFromRange(focused->selection()->rootEditableElementOrDocumentElement(), range.get(), *location, *length))
   2181         return true;
   2182     return false;
   2183 }
   2184 
   2185 WebTextInputInfo WebViewImpl::textInputInfo()
   2186 {
   2187     WebTextInputInfo info;
   2188 
   2189     Frame* focused = focusedWebCoreFrame();
   2190     if (!focused)
   2191         return info;
   2192 
   2193     FrameSelection* selection = focused->selection();
   2194     if (!selection)
   2195         return info;
   2196 
   2197     Node* node = selection->selection().rootEditableElement();
   2198     if (!node)
   2199         return info;
   2200 
   2201     info.inputMode = inputModeOfFocusedElement();
   2202 
   2203     info.type = textInputType();
   2204     if (info.type == WebTextInputTypeNone)
   2205         return info;
   2206 
   2207     Editor* editor = focused->editor();
   2208     if (!editor || !editor->canEdit())
   2209         return info;
   2210 
   2211     info.value = plainText(rangeOfContents(node).get());
   2212 
   2213     if (info.value.isEmpty())
   2214         return info;
   2215 
   2216     size_t location;
   2217     size_t length;
   2218     RefPtr<Range> range = selection->selection().firstRange();
   2219     if (range && TextIterator::getLocationAndLengthFromRange(selection->rootEditableElement(), range.get(), location, length)) {
   2220         info.selectionStart = location;
   2221         info.selectionEnd = location + length;
   2222     }
   2223     range = focused->inputMethodController().compositionRange();
   2224     if (range && TextIterator::getLocationAndLengthFromRange(selection->rootEditableElement(), range.get(), location, length)) {
   2225         info.compositionStart = location;
   2226         info.compositionEnd = location + length;
   2227     }
   2228 
   2229     return info;
   2230 }
   2231 
   2232 WebTextInputType WebViewImpl::textInputType()
   2233 {
   2234     Element* element = focusedElement();
   2235     if (!element)
   2236         return WebTextInputTypeNone;
   2237 
   2238     if (element->hasTagName(HTMLNames::inputTag)) {
   2239         HTMLInputElement* input = toHTMLInputElement(element);
   2240 
   2241         if (input->isDisabledOrReadOnly())
   2242             return WebTextInputTypeNone;
   2243 
   2244         if (input->isPasswordField())
   2245             return WebTextInputTypePassword;
   2246         if (input->isSearchField())
   2247             return WebTextInputTypeSearch;
   2248         if (input->isEmailField())
   2249             return WebTextInputTypeEmail;
   2250         if (input->isNumberField())
   2251             return WebTextInputTypeNumber;
   2252         if (input->isTelephoneField())
   2253             return WebTextInputTypeTelephone;
   2254         if (input->isURLField())
   2255             return WebTextInputTypeURL;
   2256         if (input->isDateField())
   2257             return WebTextInputTypeDate;
   2258         if (input->isDateTimeLocalField())
   2259             return WebTextInputTypeDateTimeLocal;
   2260         if (input->isMonthField())
   2261             return WebTextInputTypeMonth;
   2262         if (input->isTimeField())
   2263             return WebTextInputTypeTime;
   2264         if (input->isWeekField())
   2265             return WebTextInputTypeWeek;
   2266         if (input->isTextField())
   2267             return WebTextInputTypeText;
   2268 
   2269         return WebTextInputTypeNone;
   2270     }
   2271 
   2272     if (isHTMLTextAreaElement(element)) {
   2273         if (toHTMLTextAreaElement(element)->isDisabledOrReadOnly())
   2274             return WebTextInputTypeNone;
   2275         return WebTextInputTypeTextArea;
   2276     }
   2277 
   2278 #if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
   2279     if (element->isHTMLElement()) {
   2280         if (toHTMLElement(element)->isDateTimeFieldElement())
   2281             return WebTextInputTypeDateTimeField;
   2282     }
   2283 #endif
   2284 
   2285     if (element->shouldUseInputMethod())
   2286         return WebTextInputTypeContentEditable;
   2287 
   2288     return WebTextInputTypeNone;
   2289 }
   2290 
   2291 WebString WebViewImpl::inputModeOfFocusedElement()
   2292 {
   2293     if (!RuntimeEnabledFeatures::inputModeAttributeEnabled())
   2294         return WebString();
   2295 
   2296     Element* element = focusedElement();
   2297     if (!element)
   2298         return WebString();
   2299 
   2300     if (element->hasTagName(HTMLNames::inputTag)) {
   2301         const HTMLInputElement* input = toHTMLInputElement(element);
   2302         if (input->supportsInputModeAttribute())
   2303             return input->fastGetAttribute(HTMLNames::inputmodeAttr).lower();
   2304         return WebString();
   2305     }
   2306     if (isHTMLTextAreaElement(element)) {
   2307         const HTMLTextAreaElement* textarea = toHTMLTextAreaElement(element);
   2308         return textarea->fastGetAttribute(HTMLNames::inputmodeAttr).lower();
   2309     }
   2310 
   2311     return WebString();
   2312 }
   2313 
   2314 bool WebViewImpl::selectionBounds(WebRect& anchor, WebRect& focus) const
   2315 {
   2316     const Frame* frame = focusedWebCoreFrame();
   2317     if (!frame)
   2318         return false;
   2319     FrameSelection* selection = frame->selection();
   2320     if (!selection)
   2321         return false;
   2322 
   2323     if (selection->isCaret())
   2324         anchor = focus = selection->absoluteCaretBounds();
   2325     else {
   2326         RefPtr<Range> selectedRange = frame->selection()->toNormalizedRange();
   2327         if (!selectedRange)
   2328             return false;
   2329 
   2330         RefPtr<Range> range(Range::create(selectedRange->startContainer()->document(),
   2331             selectedRange->startContainer(),
   2332             selectedRange->startOffset(),
   2333             selectedRange->startContainer(),
   2334             selectedRange->startOffset()));
   2335         anchor = frame->editor()->firstRectForRange(range.get());
   2336 
   2337         range = Range::create(selectedRange->endContainer()->document(),
   2338             selectedRange->endContainer(),
   2339             selectedRange->endOffset(),
   2340             selectedRange->endContainer(),
   2341             selectedRange->endOffset());
   2342         focus = frame->editor()->firstRectForRange(range.get());
   2343     }
   2344 
   2345     IntRect scaledAnchor(frame->view()->contentsToWindow(anchor));
   2346     IntRect scaledFocus(frame->view()->contentsToWindow(focus));
   2347     scaledAnchor.scale(pageScaleFactor());
   2348     scaledFocus.scale(pageScaleFactor());
   2349     anchor = scaledAnchor;
   2350     focus = scaledFocus;
   2351 
   2352     if (!frame->selection()->selection().isBaseFirst())
   2353         std::swap(anchor, focus);
   2354     return true;
   2355 }
   2356 
   2357 bool WebViewImpl::selectionTextDirection(WebTextDirection& start, WebTextDirection& end) const
   2358 {
   2359     const Frame* frame = focusedWebCoreFrame();
   2360     if (!frame)
   2361         return false;
   2362     FrameSelection* selection = frame->selection();
   2363     if (!selection)
   2364         return false;
   2365     if (!selection->toNormalizedRange())
   2366         return false;
   2367     start = selection->start().primaryDirection() == RTL ? WebTextDirectionRightToLeft : WebTextDirectionLeftToRight;
   2368     end = selection->end().primaryDirection() == RTL ? WebTextDirectionRightToLeft : WebTextDirectionLeftToRight;
   2369     return true;
   2370 }
   2371 
   2372 bool WebViewImpl::isSelectionAnchorFirst() const
   2373 {
   2374     const Frame* frame = focusedWebCoreFrame();
   2375     if (!frame)
   2376         return false;
   2377     FrameSelection* selection = frame->selection();
   2378     if (!selection)
   2379         return false;
   2380     return selection->selection().isBaseFirst();
   2381 }
   2382 
   2383 bool WebViewImpl::setEditableSelectionOffsets(int start, int end)
   2384 {
   2385     const Frame* focused = focusedWebCoreFrame();
   2386     if (!focused)
   2387         return false;
   2388 
   2389     Editor* editor = focused->editor();
   2390     if (!editor || !editor->canEdit())
   2391         return false;
   2392 
   2393     return editor->setSelectionOffsets(start, end);
   2394 }
   2395 
   2396 bool WebViewImpl::setCompositionFromExistingText(int compositionStart, int compositionEnd, const WebVector<WebCompositionUnderline>& underlines)
   2397 {
   2398     const Frame* focused = focusedWebCoreFrame();
   2399     if (!focused)
   2400         return false;
   2401 
   2402     Editor* editor = focused->editor();
   2403     if (!editor || !editor->canEdit())
   2404         return false;
   2405 
   2406     InputMethodController& inputMethodController = focused->inputMethodController();
   2407     inputMethodController.cancelComposition();
   2408 
   2409     if (compositionStart == compositionEnd)
   2410         return true;
   2411 
   2412     inputMethodController.setCompositionFromExistingText(CompositionUnderlineVectorBuilder(underlines), compositionStart, compositionEnd);
   2413 
   2414     return true;
   2415 }
   2416 
   2417 WebVector<WebCompositionUnderline> WebViewImpl::compositionUnderlines() const
   2418 {
   2419     const Frame* focused = focusedWebCoreFrame();
   2420     if (!focused)
   2421         return WebVector<WebCompositionUnderline>();
   2422     const Vector<CompositionUnderline>& underlines = focused->inputMethodController().customCompositionUnderlines();
   2423     WebVector<WebCompositionUnderline> results(underlines.size());
   2424     for (size_t index = 0; index < underlines.size(); ++index) {
   2425         CompositionUnderline underline = underlines[index];
   2426         results[index] = WebCompositionUnderline(underline.startOffset, underline.endOffset, static_cast<WebColor>(underline.color.rgb()), underline.thick);
   2427     }
   2428     return results;
   2429 }
   2430 
   2431 void WebViewImpl::extendSelectionAndDelete(int before, int after)
   2432 {
   2433     const Frame* focused = focusedWebCoreFrame();
   2434     if (!focused)
   2435         return;
   2436 
   2437     Editor* editor = focused->editor();
   2438     if (!editor || !editor->canEdit())
   2439         return;
   2440 
   2441     FrameSelection* selection = focused->selection();
   2442     if (!selection)
   2443         return;
   2444 
   2445     size_t location;
   2446     size_t length;
   2447     RefPtr<Range> range = selection->selection().firstRange();
   2448     if (range && TextIterator::getLocationAndLengthFromRange(selection->rootEditableElement(), range.get(), location, length)) {
   2449         editor->setSelectionOffsets(max(static_cast<int>(location) - before, 0), location + length + after);
   2450         focused->document()->execCommand("delete", true);
   2451     }
   2452 }
   2453 
   2454 bool WebViewImpl::isSelectionEditable() const
   2455 {
   2456     const Frame* frame = focusedWebCoreFrame();
   2457     if (!frame)
   2458         return false;
   2459     return frame->selection()->isContentEditable();
   2460 }
   2461 
   2462 WebColor WebViewImpl::backgroundColor() const
   2463 {
   2464     if (isTransparent())
   2465         return Color::transparent;
   2466     if (!m_page)
   2467         return m_baseBackgroundColor;
   2468     FrameView* view = m_page->mainFrame()->view();
   2469     StyleColor backgroundColor = view->documentBackgroundColor();
   2470     if (!backgroundColor.isValid())
   2471         return m_baseBackgroundColor;
   2472     return backgroundColor.rgb();
   2473 }
   2474 
   2475 bool WebViewImpl::caretOrSelectionRange(size_t* location, size_t* length)
   2476 {
   2477     const Frame* focused = focusedWebCoreFrame();
   2478     if (!focused)
   2479         return false;
   2480 
   2481     FrameSelection* selection = focused->selection();
   2482     if (!selection)
   2483         return false;
   2484 
   2485     RefPtr<Range> range = selection->selection().firstRange();
   2486     if (!range)
   2487         return false;
   2488 
   2489     if (TextIterator::getLocationAndLengthFromRange(selection->rootEditableElementOrTreeScopeRootNode(), range.get(), *location, *length))
   2490         return true;
   2491     return false;
   2492 }
   2493 
   2494 void WebViewImpl::setTextDirection(WebTextDirection direction)
   2495 {
   2496     // The Editor::setBaseWritingDirection() function checks if we can change
   2497     // the text direction of the selected node and updates its DOM "dir"
   2498     // attribute and its CSS "direction" property.
   2499     // So, we just call the function as Safari does.
   2500     const Frame* focused = focusedWebCoreFrame();
   2501     if (!focused)
   2502         return;
   2503 
   2504     Editor* editor = focused->editor();
   2505     if (!editor || !editor->canEdit())
   2506         return;
   2507 
   2508     switch (direction) {
   2509     case WebTextDirectionDefault:
   2510         editor->setBaseWritingDirection(NaturalWritingDirection);
   2511         break;
   2512 
   2513     case WebTextDirectionLeftToRight:
   2514         editor->setBaseWritingDirection(LeftToRightWritingDirection);
   2515         break;
   2516 
   2517     case WebTextDirectionRightToLeft:
   2518         editor->setBaseWritingDirection(RightToLeftWritingDirection);
   2519         break;
   2520 
   2521     default:
   2522         notImplemented();
   2523         break;
   2524     }
   2525 }
   2526 
   2527 bool WebViewImpl::isAcceleratedCompositingActive() const
   2528 {
   2529     return m_isAcceleratedCompositingActive;
   2530 }
   2531 
   2532 void WebViewImpl::willCloseLayerTreeView()
   2533 {
   2534     setIsAcceleratedCompositingActive(false);
   2535     m_layerTreeView = 0;
   2536 }
   2537 
   2538 void WebViewImpl::didAcquirePointerLock()
   2539 {
   2540     if (page())
   2541         page()->pointerLockController()->didAcquirePointerLock();
   2542 }
   2543 
   2544 void WebViewImpl::didNotAcquirePointerLock()
   2545 {
   2546     if (page())
   2547         page()->pointerLockController()->didNotAcquirePointerLock();
   2548 }
   2549 
   2550 void WebViewImpl::didLosePointerLock()
   2551 {
   2552     if (page())
   2553         page()->pointerLockController()->didLosePointerLock();
   2554 }
   2555 
   2556 void WebViewImpl::didChangeWindowResizerRect()
   2557 {
   2558     if (mainFrameImpl()->frameView())
   2559         mainFrameImpl()->frameView()->windowResizerRectChanged();
   2560 }
   2561 
   2562 // WebView --------------------------------------------------------------------
   2563 
   2564 WebSettingsImpl* WebViewImpl::settingsImpl()
   2565 {
   2566     if (!m_webSettings)
   2567         m_webSettings = adoptPtr(new WebSettingsImpl(m_page->settings()));
   2568     ASSERT(m_webSettings);
   2569     return m_webSettings.get();
   2570 }
   2571 
   2572 WebSettings* WebViewImpl::settings()
   2573 {
   2574     return settingsImpl();
   2575 }
   2576 
   2577 WebString WebViewImpl::pageEncoding() const
   2578 {
   2579     if (!m_page)
   2580         return WebString();
   2581 
   2582     // FIXME: Is this check needed?
   2583     if (!m_page->mainFrame()->document()->loader())
   2584         return WebString();
   2585 
   2586     return m_page->mainFrame()->document()->encoding();
   2587 }
   2588 
   2589 void WebViewImpl::setPageEncoding(const WebString& encodingName)
   2590 {
   2591     if (!m_page)
   2592         return;
   2593 
   2594     // Only change override encoding, don't change default encoding.
   2595     // Note that the new encoding must be 0 if it isn't supposed to be set.
   2596     String newEncodingName;
   2597     if (!encodingName.isEmpty())
   2598         newEncodingName = encodingName;
   2599     m_page->mainFrame()->loader()->reload(NormalReload, KURL(), newEncodingName);
   2600 }
   2601 
   2602 bool WebViewImpl::dispatchBeforeUnloadEvent()
   2603 {
   2604     // FIXME: This should really cause a recursive depth-first walk of all
   2605     // frames in the tree, calling each frame's onbeforeunload.  At the moment,
   2606     // we're consistent with Safari 3.1, not IE/FF.
   2607     Frame* frame = m_page->mainFrame();
   2608     if (!frame)
   2609         return true;
   2610 
   2611     return frame->loader()->shouldClose();
   2612 }
   2613 
   2614 void WebViewImpl::dispatchUnloadEvent()
   2615 {
   2616     // Run unload handlers.
   2617     m_page->mainFrame()->loader()->closeURL();
   2618 }
   2619 
   2620 WebFrame* WebViewImpl::mainFrame()
   2621 {
   2622     return mainFrameImpl();
   2623 }
   2624 
   2625 WebFrame* WebViewImpl::findFrameByName(
   2626     const WebString& name, WebFrame* relativeToFrame)
   2627 {
   2628     if (!relativeToFrame)
   2629         relativeToFrame = mainFrame();
   2630     Frame* frame = static_cast<WebFrameImpl*>(relativeToFrame)->frame();
   2631     frame = frame->tree()->find(name);
   2632     return WebFrameImpl::fromFrame(frame);
   2633 }
   2634 
   2635 WebFrame* WebViewImpl::focusedFrame()
   2636 {
   2637     return WebFrameImpl::fromFrame(focusedWebCoreFrame());
   2638 }
   2639 
   2640 void WebViewImpl::setFocusedFrame(WebFrame* frame)
   2641 {
   2642     if (!frame) {
   2643         // Clears the focused frame if any.
   2644         Frame* frame = focusedWebCoreFrame();
   2645         if (frame)
   2646             frame->selection()->setFocused(false);
   2647         return;
   2648     }
   2649     WebFrameImpl* frameImpl = static_cast<WebFrameImpl*>(frame);
   2650     Frame* webcoreFrame = frameImpl->frame();
   2651     webcoreFrame->page()->focusController().setFocusedFrame(webcoreFrame);
   2652 }
   2653 
   2654 void WebViewImpl::setInitialFocus(bool reverse)
   2655 {
   2656     if (!m_page)
   2657         return;
   2658     Frame* frame = page()->focusController().focusedOrMainFrame();
   2659     if (Document* document = frame->document())
   2660         document->setFocusedElement(0);
   2661     page()->focusController().setInitialFocus(reverse ? FocusDirectionBackward : FocusDirectionForward);
   2662 }
   2663 
   2664 void WebViewImpl::clearFocusedNode()
   2665 {
   2666     RefPtr<Frame> frame = focusedWebCoreFrame();
   2667     if (!frame)
   2668         return;
   2669 
   2670     RefPtr<Document> document = frame->document();
   2671     if (!document)
   2672         return;
   2673 
   2674     RefPtr<Element> oldFocusedElement = document->focusedElement();
   2675 
   2676     // Clear the focused node.
   2677     document->setFocusedElement(0);
   2678 
   2679     if (!oldFocusedElement)
   2680         return;
   2681 
   2682     // If a text field has focus, we need to make sure the selection controller
   2683     // knows to remove selection from it. Otherwise, the text field is still
   2684     // processing keyboard events even though focus has been moved to the page and
   2685     // keystrokes get eaten as a result.
   2686     if (oldFocusedElement->isContentEditable() || oldFocusedElement->isTextFormControl())
   2687         frame->selection()->clear();
   2688 }
   2689 
   2690 void WebViewImpl::scrollFocusedNodeIntoView()
   2691 {
   2692     if (Element* element = focusedElement())
   2693         element->scrollIntoViewIfNeeded(true);
   2694 }
   2695 
   2696 void WebViewImpl::scrollFocusedNodeIntoRect(const WebRect& rect)
   2697 {
   2698     Frame* frame = page()->mainFrame();
   2699     Element* element = focusedElement();
   2700     if (!frame || !frame->view() || !element)
   2701         return;
   2702 
   2703     if (!m_webSettings->autoZoomFocusedNodeToLegibleScale()) {
   2704         frame->view()->scrollElementToRect(element, IntRect(rect.x, rect.y, rect.width, rect.height));
   2705         return;
   2706     }
   2707 
   2708     float scale;
   2709     IntPoint scroll;
   2710     bool needAnimation;
   2711     computeScaleAndScrollForFocusedNode(element, scale, scroll, needAnimation);
   2712     if (needAnimation)
   2713         startPageScaleAnimation(scroll, false, scale, scrollAndScaleAnimationDurationInSeconds);
   2714 }
   2715 
   2716 void WebViewImpl::computeScaleAndScrollForFocusedNode(Node* focusedNode, float& newScale, IntPoint& newScroll, bool& needAnimation)
   2717 {
   2718     focusedNode->document()->updateLayoutIgnorePendingStylesheets();
   2719 
   2720     // 'caret' is rect encompassing the blinking cursor.
   2721     IntRect textboxRect = focusedNode->document()->view()->contentsToWindow(pixelSnappedIntRect(focusedNode->Node::boundingBox()));
   2722     WebRect caret, unusedEnd;
   2723     selectionBounds(caret, unusedEnd);
   2724     IntRect unscaledCaret = caret;
   2725     unscaledCaret.scale(1 / pageScaleFactor());
   2726     caret = unscaledCaret;
   2727 
   2728     // Pick a scale which is reasonably readable. This is the scale at which
   2729     // the caret height will become minReadableCaretHeight (adjusted for dpi
   2730     // and font scale factor).
   2731     float targetScale = 1;
   2732     if (page() && page()->settings())
   2733         targetScale *= page()->settings()->textAutosizingFontScaleFactor();
   2734 
   2735     newScale = clampPageScaleFactorToLimits(minReadableCaretHeight * targetScale / caret.height);
   2736     const float deltaScale = newScale / pageScaleFactor();
   2737 
   2738     // Convert the rects to absolute space in the new scale.
   2739     IntRect textboxRectInDocumentCoordinates = textboxRect;
   2740     textboxRectInDocumentCoordinates.move(mainFrame()->scrollOffset());
   2741     IntRect caretInDocumentCoordinates = caret;
   2742     caretInDocumentCoordinates.move(mainFrame()->scrollOffset());
   2743 
   2744     int viewWidth = m_size.width / newScale;
   2745     int viewHeight = m_size.height / newScale;
   2746 
   2747     if (textboxRectInDocumentCoordinates.width() <= viewWidth) {
   2748         // Field is narrower than screen. Try to leave padding on left so field's
   2749         // label is visible, but it's more important to ensure entire field is
   2750         // onscreen.
   2751         int idealLeftPadding = viewWidth * leftBoxRatio;
   2752         int maxLeftPaddingKeepingBoxOnscreen = viewWidth - textboxRectInDocumentCoordinates.width();
   2753         newScroll.setX(textboxRectInDocumentCoordinates.x() - min<int>(idealLeftPadding, maxLeftPaddingKeepingBoxOnscreen));
   2754     } else {
   2755         // Field is wider than screen. Try to left-align field, unless caret would
   2756         // be offscreen, in which case right-align the caret.
   2757         newScroll.setX(max<int>(textboxRectInDocumentCoordinates.x(), caretInDocumentCoordinates.x() + caretInDocumentCoordinates.width() + caretPadding - viewWidth));
   2758     }
   2759     if (textboxRectInDocumentCoordinates.height() <= viewHeight) {
   2760         // Field is shorter than screen. Vertically center it.
   2761         newScroll.setY(textboxRectInDocumentCoordinates.y() - (viewHeight - textboxRectInDocumentCoordinates.height()) / 2);
   2762     } else {
   2763         // Field is taller than screen. Try to top align field, unless caret would
   2764         // be offscreen, in which case bottom-align the caret.
   2765         newScroll.setY(max<int>(textboxRectInDocumentCoordinates.y(), caretInDocumentCoordinates.y() + caretInDocumentCoordinates.height() + caretPadding - viewHeight));
   2766     }
   2767 
   2768     needAnimation = false;
   2769     // If we are at less than the target zoom level, zoom in.
   2770     if (deltaScale > minScaleChangeToTriggerZoom)
   2771         needAnimation = true;
   2772     // If the caret is offscreen, then animate.
   2773     IntRect sizeRect(0, 0, viewWidth, viewHeight);
   2774     if (!sizeRect.contains(caret))
   2775         needAnimation = true;
   2776     // If the box is partially offscreen and it's possible to bring it fully
   2777     // onscreen, then animate.
   2778     if (sizeRect.contains(textboxRectInDocumentCoordinates.width(), textboxRectInDocumentCoordinates.height()) && !sizeRect.contains(textboxRect))
   2779         needAnimation = true;
   2780 }
   2781 
   2782 void WebViewImpl::advanceFocus(bool reverse)
   2783 {
   2784     page()->focusController().advanceFocus(reverse ? FocusDirectionBackward : FocusDirectionForward);
   2785 }
   2786 
   2787 double WebViewImpl::zoomLevel()
   2788 {
   2789     return m_zoomLevel;
   2790 }
   2791 
   2792 double WebViewImpl::setZoomLevel(double zoomLevel)
   2793 {
   2794     if (zoomLevel < m_minimumZoomLevel)
   2795         m_zoomLevel = m_minimumZoomLevel;
   2796     else if (zoomLevel > m_maximumZoomLevel)
   2797         m_zoomLevel = m_maximumZoomLevel;
   2798     else
   2799         m_zoomLevel = zoomLevel;
   2800 
   2801     Frame* frame = mainFrameImpl()->frame();
   2802     WebPluginContainerImpl* pluginContainer = WebFrameImpl::pluginContainerFromFrame(frame);
   2803     if (pluginContainer)
   2804         pluginContainer->plugin()->setZoomLevel(m_zoomLevel, false);
   2805     else {
   2806         float zoomFactor = static_cast<float>(zoomLevelToZoomFactor(m_zoomLevel));
   2807         frame->setPageZoomFactor(zoomFactor);
   2808     }
   2809 
   2810     return m_zoomLevel;
   2811 }
   2812 
   2813 double WebViewImpl::setZoomLevel(bool textOnly, double zoomLevel)
   2814 {
   2815     if (textOnly) {
   2816         setZoomLevel(0.0f);
   2817         return setTextZoomFactor(static_cast<float>(zoomLevelToZoomFactor(zoomLevel)));
   2818     }
   2819     setTextZoomFactor(1.0f);
   2820     return setZoomLevel(zoomLevel);
   2821 }
   2822 
   2823 void WebViewImpl::zoomLimitsChanged(double minimumZoomLevel,
   2824                                     double maximumZoomLevel)
   2825 {
   2826     m_minimumZoomLevel = minimumZoomLevel;
   2827     m_maximumZoomLevel = maximumZoomLevel;
   2828     m_client->zoomLimitsChanged(m_minimumZoomLevel, m_maximumZoomLevel);
   2829 }
   2830 
   2831 float WebViewImpl::textZoomFactor()
   2832 {
   2833     return mainFrameImpl()->frame()->textZoomFactor();
   2834 }
   2835 
   2836 float WebViewImpl::setTextZoomFactor(float textZoomFactor)
   2837 {
   2838     Frame* frame = mainFrameImpl()->frame();
   2839     if (WebFrameImpl::pluginContainerFromFrame(frame))
   2840         return 1;
   2841 
   2842     frame->setTextZoomFactor(textZoomFactor);
   2843 
   2844     return textZoomFactor;
   2845 }
   2846 
   2847 void WebViewImpl::fullFramePluginZoomLevelChanged(double zoomLevel)
   2848 {
   2849     if (zoomLevel == m_zoomLevel)
   2850         return;
   2851 
   2852     m_zoomLevel = max(min(zoomLevel, m_maximumZoomLevel), m_minimumZoomLevel);
   2853     m_client->zoomLevelChanged();
   2854 }
   2855 
   2856 double WebView::zoomLevelToZoomFactor(double zoomLevel)
   2857 {
   2858     return pow(textSizeMultiplierRatio, zoomLevel);
   2859 }
   2860 
   2861 double WebView::zoomFactorToZoomLevel(double factor)
   2862 {
   2863     // Since factor = 1.2^level, level = log(factor) / log(1.2)
   2864     return log(factor) / log(textSizeMultiplierRatio);
   2865 }
   2866 
   2867 float WebViewImpl::pageScaleFactor() const
   2868 {
   2869     if (!page())
   2870         return 1;
   2871 
   2872     return page()->pageScaleFactor();
   2873 }
   2874 
   2875 float WebViewImpl::clampPageScaleFactorToLimits(float scaleFactor) const
   2876 {
   2877     return m_pageScaleConstraintsSet.finalConstraints().clampToConstraints(scaleFactor);
   2878 }
   2879 
   2880 IntPoint WebViewImpl::clampOffsetAtScale(const IntPoint& offset, float scale)
   2881 {
   2882     FrameView* view = mainFrameImpl()->frameView();
   2883     if (!view)
   2884         return offset;
   2885 
   2886     IntPoint maxScrollExtent(contentsSize().width() - view->scrollOrigin().x(), contentsSize().height() - view->scrollOrigin().y());
   2887     FloatSize scaledSize = view->unscaledVisibleContentSize();
   2888     scaledSize.scale(1 / scale);
   2889 
   2890     IntPoint clampedOffset = offset;
   2891     clampedOffset = clampedOffset.shrunkTo(maxScrollExtent - expandedIntSize(scaledSize));
   2892     clampedOffset = clampedOffset.expandedTo(-view->scrollOrigin());
   2893 
   2894     return clampedOffset;
   2895 }
   2896 
   2897 void WebViewImpl::setPageScaleFactor(float scaleFactor, const WebPoint& origin)
   2898 {
   2899     if (!page())
   2900         return;
   2901 
   2902     IntPoint newScrollOffset = origin;
   2903     scaleFactor = clampPageScaleFactorToLimits(scaleFactor);
   2904     newScrollOffset = clampOffsetAtScale(newScrollOffset, scaleFactor);
   2905 
   2906     page()->setPageScaleFactor(scaleFactor, newScrollOffset);
   2907 }
   2908 
   2909 void WebViewImpl::setPageScaleFactorPreservingScrollOffset(float scaleFactor)
   2910 {
   2911     if (clampPageScaleFactorToLimits(scaleFactor) == pageScaleFactor())
   2912         return;
   2913 
   2914     IntPoint scrollOffset(mainFrame()->scrollOffset().width, mainFrame()->scrollOffset().height);
   2915     setPageScaleFactor(scaleFactor, scrollOffset);
   2916 }
   2917 
   2918 float WebViewImpl::deviceScaleFactor() const
   2919 {
   2920     if (!page())
   2921         return 1;
   2922 
   2923     return page()->deviceScaleFactor();
   2924 }
   2925 
   2926 void WebViewImpl::setDeviceScaleFactor(float scaleFactor)
   2927 {
   2928     if (!page())
   2929         return;
   2930 
   2931     page()->setDeviceScaleFactor(scaleFactor);
   2932 
   2933     if (m_layerTreeView)
   2934         m_layerTreeView->setDeviceScaleFactor(scaleFactor);
   2935 }
   2936 
   2937 bool WebViewImpl::isFixedLayoutModeEnabled() const
   2938 {
   2939     if (!page())
   2940         return false;
   2941 
   2942     Frame* frame = page()->mainFrame();
   2943     if (!frame || !frame->view())
   2944         return false;
   2945 
   2946     return frame->view()->useFixedLayout();
   2947 }
   2948 
   2949 void WebViewImpl::enableFixedLayoutMode(bool enable)
   2950 {
   2951     if (!page())
   2952         return;
   2953 
   2954     Frame* frame = page()->mainFrame();
   2955     if (!frame || !frame->view())
   2956         return;
   2957 
   2958     frame->view()->setUseFixedLayout(enable);
   2959 
   2960     if (m_isAcceleratedCompositingActive)
   2961         updateLayerTreeViewport();
   2962 }
   2963 
   2964 
   2965 void WebViewImpl::enableAutoResizeMode(const WebSize& minSize, const WebSize& maxSize)
   2966 {
   2967     m_shouldAutoResize = true;
   2968     m_minAutoSize = minSize;
   2969     m_maxAutoSize = maxSize;
   2970     configureAutoResizeMode();
   2971 }
   2972 
   2973 void WebViewImpl::disableAutoResizeMode()
   2974 {
   2975     m_shouldAutoResize = false;
   2976     configureAutoResizeMode();
   2977 }
   2978 
   2979 void WebViewImpl::setUserAgentPageScaleConstraints(PageScaleConstraints newConstraints)
   2980 {
   2981     if (newConstraints == m_pageScaleConstraintsSet.userAgentConstraints())
   2982         return;
   2983 
   2984     m_pageScaleConstraintsSet.setUserAgentConstraints(newConstraints);
   2985 
   2986     if (!mainFrameImpl() || !mainFrameImpl()->frameView())
   2987         return;
   2988 
   2989     mainFrameImpl()->frameView()->setNeedsLayout();
   2990 }
   2991 
   2992 void WebViewImpl::setInitialPageScaleOverride(float initialPageScaleFactorOverride)
   2993 {
   2994     PageScaleConstraints constraints = m_pageScaleConstraintsSet.userAgentConstraints();
   2995     constraints.initialScale = initialPageScaleFactorOverride;
   2996 
   2997     if (constraints == m_pageScaleConstraintsSet.userAgentConstraints())
   2998         return;
   2999 
   3000     m_pageScaleConstraintsSet.setNeedsReset(true);
   3001     setUserAgentPageScaleConstraints(constraints);
   3002 }
   3003 
   3004 void WebViewImpl::setPageScaleFactorLimits(float minPageScale, float maxPageScale)
   3005 {
   3006     PageScaleConstraints constraints = m_pageScaleConstraintsSet.userAgentConstraints();
   3007     constraints.minimumScale = minPageScale;
   3008     constraints.maximumScale = maxPageScale;
   3009     setUserAgentPageScaleConstraints(constraints);
   3010 }
   3011 
   3012 void WebViewImpl::setIgnoreViewportTagScaleLimits(bool ignore)
   3013 {
   3014     PageScaleConstraints constraints = m_pageScaleConstraintsSet.userAgentConstraints();
   3015     if (ignore) {
   3016         constraints.minimumScale = m_pageScaleConstraintsSet.defaultConstraints().minimumScale;
   3017         constraints.maximumScale = m_pageScaleConstraintsSet.defaultConstraints().maximumScale;
   3018     } else {
   3019         constraints.minimumScale = -1;
   3020         constraints.maximumScale = -1;
   3021     }
   3022     setUserAgentPageScaleConstraints(constraints);
   3023 }
   3024 
   3025 void WebViewImpl::refreshPageScaleFactorAfterLayout()
   3026 {
   3027     if (!mainFrame() || !page() || !page()->mainFrame() || !page()->mainFrame()->view())
   3028         return;
   3029     FrameView* view = page()->mainFrame()->view();
   3030 
   3031     updatePageDefinedPageScaleConstraints(mainFrameImpl()->frame()->document()->viewportArguments());
   3032     m_pageScaleConstraintsSet.computeFinalConstraints();
   3033 
   3034     if (settings()->viewportEnabled() && !m_fixedLayoutSizeLock) {
   3035         int verticalScrollbarWidth = 0;
   3036         if (view->verticalScrollbar() && !view->verticalScrollbar()->isOverlayScrollbar())
   3037             verticalScrollbarWidth = view->verticalScrollbar()->width();
   3038         m_pageScaleConstraintsSet.adjustFinalConstraintsToContentsSize(m_size, contentsSize(), verticalScrollbarWidth);
   3039     }
   3040 
   3041     float newPageScaleFactor = pageScaleFactor();
   3042     if (m_pageScaleConstraintsSet.needsReset() && m_pageScaleConstraintsSet.finalConstraints().initialScale != -1) {
   3043         newPageScaleFactor = m_pageScaleConstraintsSet.finalConstraints().initialScale;
   3044         m_pageScaleConstraintsSet.setNeedsReset(false);
   3045     }
   3046     setPageScaleFactorPreservingScrollOffset(newPageScaleFactor);
   3047 
   3048     updateLayerTreeViewport();
   3049 
   3050     // Relayout immediately to avoid violating the rule that needsLayout()
   3051     // isn't set at the end of a layout.
   3052     if (view->needsLayout())
   3053         view->layout();
   3054 }
   3055 
   3056 void WebViewImpl::updatePageDefinedPageScaleConstraints(const ViewportArguments& arguments)
   3057 {
   3058     if (!settings()->viewportEnabled() || !isFixedLayoutModeEnabled() || !page() || !m_size.width || !m_size.height)
   3059         return;
   3060 
   3061     ViewportArguments adjustedArguments = arguments;
   3062     if (settingsImpl()->viewportMetaLayoutSizeQuirk() && adjustedArguments.type == ViewportArguments::ViewportMeta) {
   3063         adjustedArguments.type = ViewportArguments::ViewportMetaLayoutSizeQuirk;
   3064         if (adjustedArguments.width >= 0 && adjustedArguments.width <= 320)
   3065             adjustedArguments.width = ViewportArguments::ValueDeviceWidth;
   3066         if (adjustedArguments.height >= 0 && adjustedArguments.width <= m_size.height)
   3067             adjustedArguments.height = ViewportArguments::ValueDeviceHeight;
   3068     }
   3069 
   3070     float oldInitialScale = m_pageScaleConstraintsSet.pageDefinedConstraints().initialScale;
   3071     m_pageScaleConstraintsSet.updatePageDefinedConstraints(adjustedArguments, m_size, page()->settings()->layoutFallbackWidth());
   3072 
   3073     if (settingsImpl()->supportDeprecatedTargetDensityDPI()
   3074         && m_pageScaleConstraintsSet.userAgentConstraints().initialScale != -1
   3075         && m_pageScaleConstraintsSet.userAgentConstraints().initialScale * deviceScaleFactor() <= 1.0f) {
   3076         // In the following cases, a bug in the Classic WebView would mean that the viewport meta tag would take
   3077         // precedence over the app specified setInitialScale value. We keep bugward compatibility with the old
   3078         // WebView for legacy apps (the supportTargetDensityDPI case). New apps will see that setInitialScale()
   3079         // overrides what is specified in the viewport tag.
   3080         if (adjustedArguments.width == ViewportArguments::ValueDeviceWidth
   3081             || (adjustedArguments.width == ViewportArguments::ValueAuto && m_pageScaleConstraintsSet.pageDefinedConstraints().initialScale == 1.0f)) {
   3082             setInitialPageScaleOverride(-1);
   3083         }
   3084     }
   3085     m_pageScaleConstraintsSet.adjustForAndroidWebViewQuirks(adjustedArguments, m_size, page()->settings()->layoutFallbackWidth(), deviceScaleFactor(), settingsImpl()->supportDeprecatedTargetDensityDPI(), page()->settings()->wideViewportQuirkEnabled(), page()->settings()->useWideViewport(), page()->settings()->loadWithOverviewMode());
   3086     float newInitialScale = m_pageScaleConstraintsSet.pageDefinedConstraints().initialScale;
   3087     if (oldInitialScale != newInitialScale && newInitialScale != -1)
   3088         m_pageScaleConstraintsSet.setNeedsReset(true);
   3089 
   3090     WebSize layoutSize = flooredIntSize(m_pageScaleConstraintsSet.pageDefinedConstraints().layoutSize);
   3091 
   3092     if (page()->settings() && page()->settings()->textAutosizingEnabled() && page()->mainFrame()
   3093         && layoutSize.width != fixedLayoutSize().width)
   3094             page()->mainFrame()->document()->textAutosizer()->recalculateMultipliers();
   3095 
   3096     if (page()->mainFrame() && page()->mainFrame()->view() && !m_fixedLayoutSizeLock)
   3097         page()->mainFrame()->view()->setFixedLayoutSize(layoutSize);
   3098 }
   3099 
   3100 IntSize WebViewImpl::contentsSize() const
   3101 {
   3102     RenderView* root = page()->mainFrame()->contentRenderer();
   3103     if (!root)
   3104         return IntSize();
   3105     return root->documentRect().size();
   3106 }
   3107 
   3108 WebSize WebViewImpl::contentsPreferredMinimumSize()
   3109 {
   3110     Document* document = m_page->mainFrame()->document();
   3111     if (!document || !document->renderView() || !document->documentElement())
   3112         return WebSize();
   3113 
   3114     layout();
   3115     FontCachePurgePreventer fontCachePurgePreventer; // Required by minPreferredLogicalWidth().
   3116     IntSize preferredMinimumSize(document->renderView()->minPreferredLogicalWidth(), document->documentElement()->scrollHeight());
   3117     preferredMinimumSize.scale(zoomLevelToZoomFactor(zoomLevel()));
   3118     return preferredMinimumSize;
   3119 }
   3120 
   3121 float WebViewImpl::minimumPageScaleFactor() const
   3122 {
   3123     return m_pageScaleConstraintsSet.finalConstraints().minimumScale;
   3124 }
   3125 
   3126 float WebViewImpl::maximumPageScaleFactor() const
   3127 {
   3128     return m_pageScaleConstraintsSet.finalConstraints().maximumScale;
   3129 }
   3130 
   3131 void WebViewImpl::saveScrollAndScaleState()
   3132 {
   3133     m_savedPageScaleFactor = pageScaleFactor();
   3134     m_savedScrollOffset = mainFrame()->scrollOffset();
   3135 }
   3136 
   3137 void WebViewImpl::restoreScrollAndScaleState()
   3138 {
   3139     if (!m_savedPageScaleFactor)
   3140         return;
   3141 
   3142     startPageScaleAnimation(IntPoint(m_savedScrollOffset), false, m_savedPageScaleFactor, scrollAndScaleAnimationDurationInSeconds);
   3143     resetSavedScrollAndScaleState();
   3144 }
   3145 
   3146 void WebViewImpl::resetSavedScrollAndScaleState()
   3147 {
   3148     m_savedPageScaleFactor = 0;
   3149     m_savedScrollOffset = IntSize();
   3150 }
   3151 
   3152 void WebViewImpl::resetScrollAndScaleState()
   3153 {
   3154     page()->setPageScaleFactor(1, IntPoint());
   3155 
   3156     // Clear out the values for the current history item. This will prevent the history item from clobbering the
   3157     // value determined during page scale initialization, which may be less than 1.
   3158     page()->mainFrame()->loader()->history()->saveDocumentAndScrollState();
   3159     page()->mainFrame()->loader()->history()->clearScrollPositionAndViewState();
   3160     m_pageScaleConstraintsSet.setNeedsReset(true);
   3161 
   3162     // Clobber saved scales and scroll offsets.
   3163     if (FrameView* view = page()->mainFrame()->document()->view())
   3164         view->cacheCurrentScrollPosition();
   3165     resetSavedScrollAndScaleState();
   3166 }
   3167 
   3168 WebSize WebViewImpl::fixedLayoutSize() const
   3169 {
   3170     if (!page())
   3171         return WebSize();
   3172 
   3173     Frame* frame = page()->mainFrame();
   3174     if (!frame || !frame->view())
   3175         return WebSize();
   3176 
   3177     return frame->view()->fixedLayoutSize();
   3178 }
   3179 
   3180 void WebViewImpl::setFixedLayoutSize(const WebSize& layoutSize)
   3181 {
   3182     if (!page())
   3183         return;
   3184 
   3185     Frame* frame = page()->mainFrame();
   3186     if (!frame)
   3187         return;
   3188 
   3189     FrameView* view = frame->view();
   3190     if (!view)
   3191         return;
   3192 
   3193     m_fixedLayoutSizeLock = layoutSize.width || layoutSize.height;
   3194 
   3195     if (m_fixedLayoutSizeLock)
   3196         view->setFixedLayoutSize(layoutSize);
   3197     else
   3198         view->setFixedLayoutSize(flooredIntSize(m_pageScaleConstraintsSet.pageDefinedConstraints().layoutSize));
   3199 }
   3200 
   3201 void WebViewImpl::performMediaPlayerAction(const WebMediaPlayerAction& action,
   3202                                            const WebPoint& location)
   3203 {
   3204     HitTestResult result = hitTestResultForWindowPos(location);
   3205     RefPtr<Node> node = result.innerNonSharedNode();
   3206     if (!isHTMLVideoElement(node.get()) && !node->hasTagName(HTMLNames::audioTag))
   3207         return;
   3208 
   3209     RefPtr<HTMLMediaElement> mediaElement =
   3210         static_pointer_cast<HTMLMediaElement>(node);
   3211     switch (action.type) {
   3212     case WebMediaPlayerAction::Play:
   3213         if (action.enable)
   3214             mediaElement->play();
   3215         else
   3216             mediaElement->pause();
   3217         break;
   3218     case WebMediaPlayerAction::Mute:
   3219         mediaElement->setMuted(action.enable);
   3220         break;
   3221     case WebMediaPlayerAction::Loop:
   3222         mediaElement->setLoop(action.enable);
   3223         break;
   3224     case WebMediaPlayerAction::Controls:
   3225         mediaElement->setControls(action.enable);
   3226         break;
   3227     default:
   3228         ASSERT_NOT_REACHED();
   3229     }
   3230 }
   3231 
   3232 void WebViewImpl::performPluginAction(const WebPluginAction& action,
   3233                                       const WebPoint& location)
   3234 {
   3235     HitTestResult result = hitTestResultForWindowPos(location);
   3236     RefPtr<Node> node = result.innerNonSharedNode();
   3237     if (!node->hasTagName(HTMLNames::objectTag) && !node->hasTagName(HTMLNames::embedTag))
   3238         return;
   3239 
   3240     RenderObject* object = node->renderer();
   3241     if (object && object->isWidget()) {
   3242         Widget* widget = toRenderWidget(object)->widget();
   3243         if (widget && widget->isPluginContainer()) {
   3244             WebPluginContainerImpl* plugin = static_cast<WebPluginContainerImpl*>(widget);
   3245             switch (action.type) {
   3246             case WebPluginAction::Rotate90Clockwise:
   3247                 plugin->plugin()->rotateView(WebPlugin::RotationType90Clockwise);
   3248                 break;
   3249             case WebPluginAction::Rotate90Counterclockwise:
   3250                 plugin->plugin()->rotateView(WebPlugin::RotationType90Counterclockwise);
   3251                 break;
   3252             default:
   3253                 ASSERT_NOT_REACHED();
   3254             }
   3255         }
   3256     }
   3257 }
   3258 
   3259 WebHitTestResult WebViewImpl::hitTestResultAt(const WebPoint& point)
   3260 {
   3261     IntPoint scaledPoint = point;
   3262     scaledPoint.scale(1 / pageScaleFactor(), 1 / pageScaleFactor());
   3263     return hitTestResultForWindowPos(scaledPoint);
   3264 }
   3265 
   3266 void WebViewImpl::copyImageAt(const WebPoint& point)
   3267 {
   3268     if (!m_page)
   3269         return;
   3270 
   3271     HitTestResult result = hitTestResultForWindowPos(point);
   3272 
   3273     if (result.absoluteImageURL().isEmpty()) {
   3274         // There isn't actually an image at these coordinates.  Might be because
   3275         // the window scrolled while the context menu was open or because the page
   3276         // changed itself between when we thought there was an image here and when
   3277         // we actually tried to retreive the image.
   3278         //
   3279         // FIXME: implement a cache of the most recent HitTestResult to avoid having
   3280         //        to do two hit tests.
   3281         return;
   3282     }
   3283 
   3284     m_page->mainFrame()->editor()->copyImage(result);
   3285 }
   3286 
   3287 void WebViewImpl::dragSourceEndedAt(
   3288     const WebPoint& clientPoint,
   3289     const WebPoint& screenPoint,
   3290     WebDragOperation operation)
   3291 {
   3292     PlatformMouseEvent pme(clientPoint,
   3293                            screenPoint,
   3294                            LeftButton, PlatformEvent::MouseMoved, 0, false, false, false,
   3295                            false, 0);
   3296     m_page->mainFrame()->eventHandler()->dragSourceEndedAt(pme,
   3297         static_cast<DragOperation>(operation));
   3298 }
   3299 
   3300 void WebViewImpl::dragSourceMovedTo(
   3301     const WebPoint& clientPoint,
   3302     const WebPoint& screenPoint,
   3303     WebDragOperation operation)
   3304 {
   3305 }
   3306 
   3307 void WebViewImpl::dragSourceSystemDragEnded()
   3308 {
   3309     // It's possible for us to get this callback while not doing a drag if
   3310     // it's from a previous page that got unloaded.
   3311     if (m_doingDragAndDrop) {
   3312         m_page->dragController().dragEnded();
   3313         m_doingDragAndDrop = false;
   3314     }
   3315 }
   3316 
   3317 WebDragOperation WebViewImpl::dragTargetDragEnter(
   3318     const WebDragData& webDragData,
   3319     const WebPoint& clientPoint,
   3320     const WebPoint& screenPoint,
   3321     WebDragOperationsMask operationsAllowed,
   3322     int keyModifiers)
   3323 {
   3324     ASSERT(!m_currentDragData);
   3325 
   3326     m_currentDragData = webDragData;
   3327     m_operationsAllowed = operationsAllowed;
   3328 
   3329     return dragTargetDragEnterOrOver(clientPoint, screenPoint, DragEnter, keyModifiers);
   3330 }
   3331 
   3332 WebDragOperation WebViewImpl::dragTargetDragOver(
   3333     const WebPoint& clientPoint,
   3334     const WebPoint& screenPoint,
   3335     WebDragOperationsMask operationsAllowed,
   3336     int keyModifiers)
   3337 {
   3338     m_operationsAllowed = operationsAllowed;
   3339 
   3340     return dragTargetDragEnterOrOver(clientPoint, screenPoint, DragOver, keyModifiers);
   3341 }
   3342 
   3343 void WebViewImpl::dragTargetDragLeave()
   3344 {
   3345     ASSERT(m_currentDragData);
   3346 
   3347     DragData dragData(
   3348         m_currentDragData.get(),
   3349         IntPoint(),
   3350         IntPoint(),
   3351         static_cast<DragOperation>(m_operationsAllowed));
   3352 
   3353     m_page->dragController().dragExited(&dragData);
   3354 
   3355     // FIXME: why is the drag scroll timer not stopped here?
   3356 
   3357     m_dragOperation = WebDragOperationNone;
   3358     m_currentDragData = 0;
   3359 }
   3360 
   3361 void WebViewImpl::dragTargetDrop(const WebPoint& clientPoint,
   3362                                  const WebPoint& screenPoint,
   3363                                  int keyModifiers)
   3364 {
   3365     ASSERT(m_currentDragData);
   3366 
   3367     // If this webview transitions from the "drop accepting" state to the "not
   3368     // accepting" state, then our IPC message reply indicating that may be in-
   3369     // flight, or else delayed by javascript processing in this webview.  If a
   3370     // drop happens before our IPC reply has reached the browser process, then
   3371     // the browser forwards the drop to this webview.  So only allow a drop to
   3372     // proceed if our webview m_dragOperation state is not DragOperationNone.
   3373 
   3374     if (m_dragOperation == WebDragOperationNone) { // IPC RACE CONDITION: do not allow this drop.
   3375         dragTargetDragLeave();
   3376         return;
   3377     }
   3378 
   3379     m_currentDragData->setModifierKeyState(webInputEventKeyStateToPlatformEventKeyState(keyModifiers));
   3380     DragData dragData(
   3381         m_currentDragData.get(),
   3382         clientPoint,
   3383         screenPoint,
   3384         static_cast<DragOperation>(m_operationsAllowed));
   3385 
   3386     m_page->dragController().performDrag(&dragData);
   3387 
   3388     m_dragOperation = WebDragOperationNone;
   3389     m_currentDragData = 0;
   3390 }
   3391 
   3392 void WebViewImpl::spellingMarkers(WebVector<uint32_t>* markers)
   3393 {
   3394     Vector<uint32_t> result;
   3395     for (Frame* frame = m_page->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
   3396         const Vector<DocumentMarker*>& documentMarkers = frame->document()->markers()->markers();
   3397         for (size_t i = 0; i < documentMarkers.size(); ++i)
   3398             result.append(documentMarkers[i]->hash());
   3399     }
   3400     markers->assign(result);
   3401 }
   3402 
   3403 WebDragOperation WebViewImpl::dragTargetDragEnterOrOver(const WebPoint& clientPoint, const WebPoint& screenPoint, DragAction dragAction, int keyModifiers)
   3404 {
   3405     ASSERT(m_currentDragData);
   3406 
   3407     m_currentDragData->setModifierKeyState(webInputEventKeyStateToPlatformEventKeyState(keyModifiers));
   3408     DragData dragData(
   3409         m_currentDragData.get(),
   3410         clientPoint,
   3411         screenPoint,
   3412         static_cast<DragOperation>(m_operationsAllowed));
   3413 
   3414     DragSession dragSession;
   3415     if (dragAction == DragEnter)
   3416         dragSession = m_page->dragController().dragEntered(&dragData);
   3417     else
   3418         dragSession = m_page->dragController().dragUpdated(&dragData);
   3419 
   3420     DragOperation dropEffect = dragSession.operation;
   3421 
   3422     // Mask the drop effect operation against the drag source's allowed operations.
   3423     if (!(dropEffect & dragData.draggingSourceOperationMask()))
   3424         dropEffect = DragOperationNone;
   3425 
   3426      m_dragOperation = static_cast<WebDragOperation>(dropEffect);
   3427 
   3428     return m_dragOperation;
   3429 }
   3430 
   3431 void WebViewImpl::sendResizeEventAndRepaint()
   3432 {
   3433     // FIXME: This is wrong. The FrameView is responsible sending a resizeEvent
   3434     // as part of layout. Layout is also responsible for sending invalidations
   3435     // to the embedder. This method and all callers may be wrong. -- eseidel.
   3436     if (mainFrameImpl()->frameView()) {
   3437         // Enqueues the resize event.
   3438         mainFrameImpl()->frame()->eventHandler()->sendResizeEvent();
   3439     }
   3440 
   3441     if (m_client) {
   3442         if (isAcceleratedCompositingActive()) {
   3443             updateLayerTreeViewport();
   3444         } else {
   3445             WebRect damagedRect(0, 0, m_size.width, m_size.height);
   3446             m_client->didInvalidateRect(damagedRect);
   3447         }
   3448     }
   3449     if (m_pageOverlays)
   3450         m_pageOverlays->update();
   3451 }
   3452 
   3453 void WebViewImpl::configureAutoResizeMode()
   3454 {
   3455     if (!mainFrameImpl() || !mainFrameImpl()->frame() || !mainFrameImpl()->frame()->view())
   3456         return;
   3457 
   3458     mainFrameImpl()->frame()->view()->enableAutoSizeMode(m_shouldAutoResize, m_minAutoSize, m_maxAutoSize);
   3459 }
   3460 
   3461 unsigned long WebViewImpl::createUniqueIdentifierForRequest()
   3462 {
   3463     return createUniqueIdentifier();
   3464 }
   3465 
   3466 void WebViewImpl::inspectElementAt(const WebPoint& point)
   3467 {
   3468     if (!m_page)
   3469         return;
   3470 
   3471     if (point.x == -1 || point.y == -1)
   3472         m_page->inspectorController()->inspect(0);
   3473     else {
   3474         HitTestRequest::HitTestRequestType hitType = HitTestRequest::Move | HitTestRequest::ReadOnly | HitTestRequest::AllowChildFrameContent | HitTestRequest::IgnorePointerEventsNone;
   3475         HitTestRequest request(hitType);
   3476 
   3477         HitTestResult result(m_page->mainFrame()->view()->windowToContents(point));
   3478         m_page->mainFrame()->contentRenderer()->hitTest(request, result);
   3479         Node* node = result.innerNode();
   3480         if (!node && m_page->mainFrame()->document())
   3481             node = m_page->mainFrame()->document()->documentElement();
   3482         m_page->inspectorController()->inspect(node);
   3483     }
   3484 }
   3485 
   3486 WebString WebViewImpl::inspectorSettings() const
   3487 {
   3488     return m_inspectorSettings;
   3489 }
   3490 
   3491 void WebViewImpl::setInspectorSettings(const WebString& settings)
   3492 {
   3493     m_inspectorSettings = settings;
   3494 }
   3495 
   3496 bool WebViewImpl::inspectorSetting(const WebString& key, WebString* value) const
   3497 {
   3498     if (!m_inspectorSettingsMap->contains(key))
   3499         return false;
   3500     *value = m_inspectorSettingsMap->get(key);
   3501     return true;
   3502 }
   3503 
   3504 void WebViewImpl::setInspectorSetting(const WebString& key,
   3505                                       const WebString& value)
   3506 {
   3507     m_inspectorSettingsMap->set(key, value);
   3508     client()->didUpdateInspectorSetting(key, value);
   3509 }
   3510 
   3511 WebDevToolsAgent* WebViewImpl::devToolsAgent()
   3512 {
   3513     return m_devToolsAgent.get();
   3514 }
   3515 
   3516 WebAccessibilityObject WebViewImpl::accessibilityObject()
   3517 {
   3518     if (!mainFrameImpl())
   3519         return WebAccessibilityObject();
   3520 
   3521     Document* document = mainFrameImpl()->frame()->document();
   3522     return WebAccessibilityObject(
   3523         document->axObjectCache()->getOrCreate(document->renderer()));
   3524 }
   3525 
   3526 void WebViewImpl::applyAutofillSuggestions(
   3527     const WebNode& node,
   3528     const WebVector<WebString>& names,
   3529     const WebVector<WebString>& labels,
   3530     const WebVector<WebString>& icons,
   3531     const WebVector<int>& itemIDs,
   3532     int separatorIndex)
   3533 {
   3534     ASSERT(names.size() == labels.size());
   3535     ASSERT(names.size() == itemIDs.size());
   3536 
   3537     if (names.isEmpty()) {
   3538         hideAutofillPopup();
   3539         return;
   3540     }
   3541 
   3542     RefPtr<Element> element = focusedElement();
   3543     // If the node for which we queried the Autofill suggestions is not the
   3544     // focused node, then we have nothing to do.  FIXME: also check the
   3545     // caret is at the end and that the text has not changed.
   3546     if (!element || element != PassRefPtr<Node>(node)) {
   3547         hideAutofillPopup();
   3548         return;
   3549     }
   3550 
   3551     HTMLInputElement* inputElem = toHTMLInputElement(element.get());
   3552 
   3553     // The first time the Autofill popup is shown we'll create the client and
   3554     // the popup.
   3555     if (!m_autofillPopupClient)
   3556         m_autofillPopupClient = adoptPtr(new AutofillPopupMenuClient);
   3557 
   3558     m_autofillPopupClient->initialize(
   3559         inputElem, names, labels, icons, itemIDs, separatorIndex);
   3560 
   3561     if (!m_autofillPopup) {
   3562         PopupContainerSettings popupSettings = autofillPopupSettings;
   3563         popupSettings.deviceSupportsTouch = settingsImpl()->deviceSupportsTouch();
   3564         m_autofillPopup = PopupContainer::create(m_autofillPopupClient.get(),
   3565                                                  PopupContainer::Suggestion,
   3566                                                  popupSettings);
   3567     }
   3568 
   3569     if (m_autofillPopupShowing) {
   3570         refreshAutofillPopup();
   3571     } else {
   3572         m_autofillPopupShowing = true;
   3573         IntRect rect = element->pixelSnappedBoundingBox();
   3574         m_autofillPopup->showInRect(FloatQuad(rect), rect.size(), element->ownerDocument()->view(), 0);
   3575     }
   3576 }
   3577 
   3578 void WebViewImpl::hidePopups()
   3579 {
   3580     hideSelectPopup();
   3581     hideAutofillPopup();
   3582     if (m_pagePopup)
   3583         closePagePopup(m_pagePopup.get());
   3584 }
   3585 
   3586 void WebViewImpl::performCustomContextMenuAction(unsigned action)
   3587 {
   3588     if (!m_page)
   3589         return;
   3590     ContextMenu* menu = m_page->contextMenuController()->contextMenu();
   3591     if (!menu)
   3592         return;
   3593     const ContextMenuItem* item = menu->itemWithAction(static_cast<ContextMenuAction>(ContextMenuItemBaseCustomTag + action));
   3594     if (item)
   3595         m_page->contextMenuController()->contextMenuItemSelected(item);
   3596     m_page->contextMenuController()->clearContextMenu();
   3597 }
   3598 
   3599 void WebViewImpl::showContextMenu()
   3600 {
   3601     if (!page())
   3602         return;
   3603 
   3604     page()->contextMenuController()->clearContextMenu();
   3605     m_contextMenuAllowed = true;
   3606     if (Frame* focusedFrame = page()->focusController().focusedOrMainFrame())
   3607         focusedFrame->eventHandler()->sendContextMenuEventForKey();
   3608     m_contextMenuAllowed = false;
   3609 }
   3610 
   3611 // WebView --------------------------------------------------------------------
   3612 
   3613 void WebViewImpl::setIsTransparent(bool isTransparent)
   3614 {
   3615     // Set any existing frames to be transparent.
   3616     Frame* frame = m_page->mainFrame();
   3617     while (frame) {
   3618         frame->view()->setTransparent(isTransparent);
   3619         frame = frame->tree()->traverseNext();
   3620     }
   3621 
   3622     // Future frames check this to know whether to be transparent.
   3623     m_isTransparent = isTransparent;
   3624 }
   3625 
   3626 bool WebViewImpl::isTransparent() const
   3627 {
   3628     return m_isTransparent;
   3629 }
   3630 
   3631 void WebViewImpl::setBaseBackgroundColor(WebColor color)
   3632 {
   3633     if (m_baseBackgroundColor == color)
   3634         return;
   3635 
   3636     m_baseBackgroundColor = color;
   3637 
   3638     m_page->mainFrame()->view()->setBaseBackgroundColor(color);
   3639 
   3640     if (m_layerTreeView)
   3641         m_layerTreeView->setBackgroundColor(backgroundColor());
   3642 }
   3643 
   3644 void WebViewImpl::setIsActive(bool active)
   3645 {
   3646     if (page())
   3647         page()->focusController().setActive(active);
   3648 }
   3649 
   3650 bool WebViewImpl::isActive() const
   3651 {
   3652     return page() ? page()->focusController().isActive() : false;
   3653 }
   3654 
   3655 void WebViewImpl::setDomainRelaxationForbidden(bool forbidden, const WebString& scheme)
   3656 {
   3657     SchemeRegistry::setDomainRelaxationForbiddenForURLScheme(forbidden, String(scheme));
   3658 }
   3659 
   3660 void WebViewImpl::setWindowFeatures(const WebWindowFeatures& features)
   3661 {
   3662     m_page->chrome().setWindowFeatures(features);
   3663 }
   3664 
   3665 void WebViewImpl::setScrollbarColors(unsigned inactiveColor,
   3666                                      unsigned activeColor,
   3667                                      unsigned trackColor) {
   3668 #if ENABLE(DEFAULT_RENDER_THEME)
   3669     PlatformThemeChromiumDefault::setScrollbarColors(inactiveColor, activeColor, trackColor);
   3670 #endif
   3671 }
   3672 
   3673 void WebViewImpl::setSelectionColors(unsigned activeBackgroundColor,
   3674                                      unsigned activeForegroundColor,
   3675                                      unsigned inactiveBackgroundColor,
   3676                                      unsigned inactiveForegroundColor) {
   3677 #if ENABLE(DEFAULT_RENDER_THEME)
   3678     RenderThemeChromiumDefault::setSelectionColors(activeBackgroundColor, activeForegroundColor, inactiveBackgroundColor, inactiveForegroundColor);
   3679     theme()->platformColorsDidChange();
   3680 #endif
   3681 }
   3682 
   3683 void WebView::addUserStyleSheet(const WebString& sourceCode,
   3684                                 const WebVector<WebString>& patternsIn,
   3685                                 WebView::UserContentInjectIn injectIn,
   3686                                 WebView::UserStyleInjectionTime injectionTime)
   3687 {
   3688     Vector<String> patterns;
   3689     for (size_t i = 0; i < patternsIn.size(); ++i)
   3690         patterns.append(patternsIn[i]);
   3691 
   3692     PageGroup* pageGroup = PageGroup::sharedGroup();
   3693 
   3694     // FIXME: Current callers always want the level to be "author". It probably makes sense to let
   3695     // callers specify this though, since in other cases the caller will probably want "user" level.
   3696     //
   3697     // FIXME: It would be nice to populate the URL correctly, instead of passing an empty URL.
   3698     pageGroup->addUserStyleSheet(sourceCode, WebURL(), patterns, Vector<String>(),
   3699                                  static_cast<UserContentInjectedFrames>(injectIn),
   3700                                  UserStyleAuthorLevel,
   3701                                  static_cast<WebCore::UserStyleInjectionTime>(injectionTime));
   3702 }
   3703 
   3704 void WebView::removeAllUserContent()
   3705 {
   3706     PageGroup::sharedGroup()->removeAllUserContent();
   3707 }
   3708 
   3709 void WebViewImpl::didCommitLoad(bool* isNewNavigation, bool isNavigationWithinPage)
   3710 {
   3711     if (isNewNavigation)
   3712         *isNewNavigation = m_observedNewNavigation;
   3713 
   3714 #ifndef NDEBUG
   3715     ASSERT(!m_observedNewNavigation
   3716         || m_page->mainFrame()->loader()->documentLoader() == m_newNavigationLoader);
   3717     m_newNavigationLoader = 0;
   3718 #endif
   3719     m_observedNewNavigation = false;
   3720     if (*isNewNavigation && !isNavigationWithinPage)
   3721         m_pageScaleConstraintsSet.setNeedsReset(true);
   3722 
   3723     // Make sure link highlight from previous page is cleared.
   3724     m_linkHighlight.clear();
   3725     m_gestureAnimation.clear();
   3726     if (m_layerTreeView)
   3727         m_layerTreeView->didStopFlinging();
   3728     resetSavedScrollAndScaleState();
   3729 }
   3730 
   3731 void WebViewImpl::layoutUpdated(WebFrameImpl* webframe)
   3732 {
   3733     if (!m_client || webframe != mainFrameImpl())
   3734         return;
   3735 
   3736     if (m_layerTreeViewCommitsDeferred) {
   3737         // If we finished a layout while in deferred commit mode,
   3738         // that means it's time to start producing frames again so un-defer.
   3739         if (m_layerTreeView)
   3740             m_layerTreeView->setDeferCommits(false);
   3741         m_layerTreeViewCommitsDeferred = false;
   3742     }
   3743 
   3744     if (m_shouldAutoResize && mainFrameImpl()->frame() && mainFrameImpl()->frame()->view()) {
   3745         WebSize frameSize = mainFrameImpl()->frame()->view()->frameRect().size();
   3746         if (frameSize != m_size) {
   3747             m_size = frameSize;
   3748             m_client->didAutoResize(m_size);
   3749             sendResizeEventAndRepaint();
   3750         }
   3751     }
   3752 
   3753     if (m_pageScaleConstraintsSet.constraintsDirty())
   3754         refreshPageScaleFactorAfterLayout();
   3755 
   3756     m_client->didUpdateLayout();
   3757 }
   3758 
   3759 void WebViewImpl::didChangeContentsSize()
   3760 {
   3761     m_pageScaleConstraintsSet.didChangeContentsSize(contentsSize(), pageScaleFactor());
   3762 }
   3763 
   3764 void WebViewImpl::deviceOrPageScaleFactorChanged()
   3765 {
   3766     if (pageScaleFactor() && pageScaleFactor() != 1)
   3767         enterForceCompositingMode(true);
   3768     m_pageScaleConstraintsSet.setNeedsReset(false);
   3769     updateLayerTreeViewport();
   3770 }
   3771 
   3772 bool WebViewImpl::useExternalPopupMenus()
   3773 {
   3774     return shouldUseExternalPopupMenus;
   3775 }
   3776 
   3777 void WebViewImpl::startDragging(Frame* frame,
   3778                                 const WebDragData& dragData,
   3779                                 WebDragOperationsMask mask,
   3780                                 const WebImage& dragImage,
   3781                                 const WebPoint& dragImageOffset)
   3782 {
   3783     if (!m_client)
   3784         return;
   3785     ASSERT(!m_doingDragAndDrop);
   3786     m_doingDragAndDrop = true;
   3787     m_client->startDragging(WebFrameImpl::fromFrame(frame), dragData, mask, dragImage, dragImageOffset);
   3788 }
   3789 
   3790 void WebViewImpl::observeNewNavigation()
   3791 {
   3792     m_observedNewNavigation = true;
   3793 #ifndef NDEBUG
   3794     m_newNavigationLoader = m_page->mainFrame()->loader()->documentLoader();
   3795 #endif
   3796 }
   3797 
   3798 void WebViewImpl::setIgnoreInputEvents(bool newValue)
   3799 {
   3800     ASSERT(m_ignoreInputEvents != newValue);
   3801     m_ignoreInputEvents = newValue;
   3802 }
   3803 
   3804 void WebViewImpl::addPageOverlay(WebPageOverlay* overlay, int zOrder)
   3805 {
   3806     if (!m_pageOverlays)
   3807         m_pageOverlays = PageOverlayList::create(this);
   3808 
   3809     m_pageOverlays->add(overlay, zOrder);
   3810 }
   3811 
   3812 void WebViewImpl::removePageOverlay(WebPageOverlay* overlay)
   3813 {
   3814     if (m_pageOverlays && m_pageOverlays->remove(overlay) && m_pageOverlays->empty())
   3815         m_pageOverlays = nullptr;
   3816 }
   3817 
   3818 void WebViewImpl::setOverlayLayer(WebCore::GraphicsLayer* layer)
   3819 {
   3820     if (m_rootGraphicsLayer) {
   3821         if (layer->parent() != m_rootGraphicsLayer)
   3822             m_rootGraphicsLayer->addChild(layer);
   3823     }
   3824 }
   3825 
   3826 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
   3827 NotificationPresenterImpl* WebViewImpl::notificationPresenterImpl()
   3828 {
   3829     if (!m_notificationPresenter.isInitialized() && m_client)
   3830         m_notificationPresenter.initialize(m_client->notificationPresenter());
   3831     return &m_notificationPresenter;
   3832 }
   3833 #endif
   3834 
   3835 void WebViewImpl::refreshAutofillPopup()
   3836 {
   3837     ASSERT(m_autofillPopupShowing);
   3838 
   3839     // Hide the popup if it has become empty.
   3840     if (!m_autofillPopupClient->listSize()) {
   3841         hideAutofillPopup();
   3842         return;
   3843     }
   3844 
   3845     WebRect newWidgetRect = m_autofillPopup->refresh(focusedElement()->pixelSnappedBoundingBox());
   3846     // Let's resize the backing window if necessary.
   3847     WebPopupMenuImpl* popupMenu = static_cast<WebPopupMenuImpl*>(m_autofillPopup->client());
   3848     if (popupMenu && popupMenu->client()->windowRect() != newWidgetRect)
   3849         popupMenu->client()->setWindowRect(newWidgetRect);
   3850 }
   3851 
   3852 Element* WebViewImpl::focusedElement()
   3853 {
   3854     Frame* frame = m_page->focusController().focusedFrame();
   3855     if (!frame)
   3856         return 0;
   3857 
   3858     Document* document = frame->document();
   3859     if (!document)
   3860         return 0;
   3861 
   3862     return document->focusedElement();
   3863 }
   3864 
   3865 HitTestResult WebViewImpl::hitTestResultForWindowPos(const IntPoint& pos)
   3866 {
   3867     IntPoint docPoint(m_page->mainFrame()->view()->windowToContents(pos));
   3868     return m_page->mainFrame()->eventHandler()->hitTestResultAtPoint(docPoint, HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::DisallowShadowContent);
   3869 }
   3870 
   3871 void WebViewImpl::setTabsToLinks(bool enable)
   3872 {
   3873     m_tabsToLinks = enable;
   3874 }
   3875 
   3876 bool WebViewImpl::tabsToLinks() const
   3877 {
   3878     return m_tabsToLinks;
   3879 }
   3880 
   3881 void WebViewImpl::suppressInvalidations(bool enable)
   3882 {
   3883     if (m_client)
   3884         m_client->suppressCompositorScheduling(enable);
   3885 }
   3886 
   3887 bool WebViewImpl::allowsAcceleratedCompositing()
   3888 {
   3889     return !m_compositorCreationFailed;
   3890 }
   3891 
   3892 void WebViewImpl::setRootGraphicsLayer(GraphicsLayer* layer)
   3893 {
   3894     suppressInvalidations(true);
   3895 
   3896     if (page()->settings()->pinchVirtualViewportEnabled()) {
   3897         if (!m_pinchViewports)
   3898             m_pinchViewports = PinchViewports::create(this);
   3899 
   3900         m_pinchViewports->setOverflowControlsHostLayer(layer);
   3901         m_pinchViewports->setViewportSize(mainFrameImpl()->frame()->view()->frameRect().size());
   3902         if (layer) {
   3903             m_rootGraphicsLayer = m_pinchViewports->rootGraphicsLayer();
   3904             m_rootLayer = m_pinchViewports->rootGraphicsLayer()->platformLayer();
   3905             m_pinchViewports->registerViewportLayersWithTreeView(m_layerTreeView);
   3906         } else {
   3907             m_rootGraphicsLayer = 0;
   3908             m_rootLayer = 0;
   3909             m_pinchViewports->clearViewportLayersForTreeView(m_layerTreeView);
   3910         }
   3911     } else {
   3912         m_rootGraphicsLayer = layer;
   3913         m_rootLayer = layer ? layer->platformLayer() : 0;
   3914     }
   3915 
   3916     setIsAcceleratedCompositingActive(layer);
   3917 
   3918     if (m_layerTreeView) {
   3919         if (m_rootLayer)
   3920             m_layerTreeView->setRootLayer(*m_rootLayer);
   3921         else
   3922             m_layerTreeView->clearRootLayer();
   3923     }
   3924 
   3925     suppressInvalidations(false);
   3926 }
   3927 
   3928 void WebViewImpl::scheduleCompositingLayerSync()
   3929 {
   3930     m_layerTreeView->setNeedsRedraw();
   3931 }
   3932 
   3933 void WebViewImpl::scrollRootLayerRect(const IntSize&, const IntRect&)
   3934 {
   3935     updateLayerTreeViewport();
   3936 }
   3937 
   3938 void WebViewImpl::invalidateRect(const IntRect& rect)
   3939 {
   3940     if (m_isAcceleratedCompositingActive) {
   3941         ASSERT(m_layerTreeView);
   3942         updateLayerTreeViewport();
   3943     } else if (m_client)
   3944         m_client->didInvalidateRect(rect);
   3945 }
   3946 
   3947 WebCore::GraphicsLayerFactory* WebViewImpl::graphicsLayerFactory() const
   3948 {
   3949     return m_graphicsLayerFactory.get();
   3950 }
   3951 
   3952 WebCore::RenderLayerCompositor* WebViewImpl::compositor() const
   3953 {
   3954     if (!page()
   3955         || !page()->mainFrame()
   3956         || !page()->mainFrame()->document()
   3957         || !page()->mainFrame()->document()->renderView())
   3958         return 0;
   3959     return page()->mainFrame()->document()->renderView()->compositor();
   3960 }
   3961 
   3962 void WebViewImpl::registerForAnimations(WebLayer* layer)
   3963 {
   3964     if (m_layerTreeView)
   3965         m_layerTreeView->registerForAnimations(layer);
   3966 }
   3967 
   3968 WebCore::GraphicsLayer* WebViewImpl::rootGraphicsLayer()
   3969 {
   3970     return m_rootGraphicsLayer;
   3971 }
   3972 
   3973 void WebViewImpl::scheduleAnimation()
   3974 {
   3975     if (isAcceleratedCompositingActive() && Platform::current()->isThreadedCompositingEnabled()) {
   3976         ASSERT(m_layerTreeView);
   3977         m_layerTreeView->setNeedsAnimate();
   3978         return;
   3979     }
   3980     if (m_client)
   3981         m_client->scheduleAnimation();
   3982 }
   3983 
   3984 void WebViewImpl::setIsAcceleratedCompositingActive(bool active)
   3985 {
   3986     WebKit::Platform::current()->histogramEnumeration("GPU.setIsAcceleratedCompositingActive", active * 2 + m_isAcceleratedCompositingActive, 4);
   3987 
   3988     if (m_isAcceleratedCompositingActive == active)
   3989         return;
   3990 
   3991     if (!active) {
   3992         m_isAcceleratedCompositingActive = false;
   3993         // We need to finish all GL rendering before sending didDeactivateCompositor() to prevent
   3994         // flickering when compositing turns off. This is only necessary if we're not in
   3995         // force-compositing-mode.
   3996         if (m_layerTreeView && !page()->settings()->forceCompositingMode())
   3997             m_layerTreeView->finishAllRendering();
   3998         m_client->didDeactivateCompositor();
   3999         if (!m_layerTreeViewCommitsDeferred
   4000             && WebKit::Platform::current()->isThreadedCompositingEnabled()) {
   4001             ASSERT(m_layerTreeView);
   4002             // In threaded compositing mode, force compositing mode is always on so setIsAcceleratedCompositingActive(false)
   4003             // means that we're transitioning to a new page. Suppress commits until WebKit generates invalidations so
   4004             // we don't attempt to paint too early in the next page load.
   4005             m_layerTreeView->setDeferCommits(true);
   4006             m_layerTreeViewCommitsDeferred = true;
   4007         }
   4008     } else if (m_layerTreeView) {
   4009         m_isAcceleratedCompositingActive = true;
   4010         updateLayerTreeViewport();
   4011         if (m_pageOverlays)
   4012             m_pageOverlays->update();
   4013 
   4014         m_client->didActivateCompositor(0);
   4015     } else {
   4016         TRACE_EVENT0("webkit", "WebViewImpl::setIsAcceleratedCompositingActive(true)");
   4017 
   4018         m_client->initializeLayerTreeView();
   4019         m_layerTreeView = m_client->layerTreeView();
   4020         if (m_layerTreeView) {
   4021             m_layerTreeView->setRootLayer(*m_rootLayer);
   4022 
   4023             bool visible = page()->visibilityState() == PageVisibilityStateVisible;
   4024             m_layerTreeView->setVisible(visible);
   4025             m_layerTreeView->setDeviceScaleFactor(page()->deviceScaleFactor());
   4026             m_layerTreeView->setPageScaleFactorAndLimits(pageScaleFactor(), minimumPageScaleFactor(), maximumPageScaleFactor());
   4027             m_layerTreeView->setBackgroundColor(backgroundColor());
   4028             m_layerTreeView->setHasTransparentBackground(isTransparent());
   4029             updateLayerTreeViewport();
   4030             m_client->didActivateCompositor(0);
   4031             m_isAcceleratedCompositingActive = true;
   4032             m_compositorCreationFailed = false;
   4033             if (m_pageOverlays)
   4034                 m_pageOverlays->update();
   4035             m_layerTreeView->setShowFPSCounter(m_showFPSCounter);
   4036             m_layerTreeView->setShowPaintRects(m_showPaintRects);
   4037             m_layerTreeView->setShowDebugBorders(m_showDebugBorders);
   4038             m_layerTreeView->setContinuousPaintingEnabled(m_continuousPaintingEnabled);
   4039             m_layerTreeView->setShowScrollBottleneckRects(m_showScrollBottleneckRects);
   4040         } else {
   4041             m_isAcceleratedCompositingActive = false;
   4042             m_client->didDeactivateCompositor();
   4043             m_compositorCreationFailed = true;
   4044         }
   4045     }
   4046     if (page())
   4047         page()->mainFrame()->view()->setClipsRepaints(!m_isAcceleratedCompositingActive);
   4048 }
   4049 
   4050 void WebViewImpl::updateMainFrameScrollPosition(const IntPoint& scrollPosition, bool programmaticScroll)
   4051 {
   4052     FrameView* frameView = page()->mainFrame()->view();
   4053     if (!frameView)
   4054         return;
   4055 
   4056     if (frameView->scrollPosition() == scrollPosition)
   4057         return;
   4058 
   4059     bool oldProgrammaticScroll = frameView->inProgrammaticScroll();
   4060     frameView->setInProgrammaticScroll(programmaticScroll);
   4061     frameView->notifyScrollPositionChanged(scrollPosition);
   4062     frameView->setInProgrammaticScroll(oldProgrammaticScroll);
   4063 }
   4064 
   4065 void WebViewImpl::applyScrollAndScale(const WebSize& scrollDelta, float pageScaleDelta)
   4066 {
   4067     if (!mainFrameImpl() || !mainFrameImpl()->frameView())
   4068         return;
   4069 
   4070     if (pageScaleDelta == 1) {
   4071         TRACE_EVENT_INSTANT2("webkit", "WebViewImpl::applyScrollAndScale::scrollBy", "x", scrollDelta.width, "y", scrollDelta.height);
   4072         WebSize webScrollOffset = mainFrame()->scrollOffset();
   4073         IntPoint scrollOffset(webScrollOffset.width + scrollDelta.width, webScrollOffset.height + scrollDelta.height);
   4074         updateMainFrameScrollPosition(scrollOffset, false);
   4075     } else {
   4076         // The page scale changed, so apply a scale and scroll in a single
   4077         // operation.
   4078         WebSize scrollOffset = mainFrame()->scrollOffset();
   4079         scrollOffset.width += scrollDelta.width;
   4080         scrollOffset.height += scrollDelta.height;
   4081 
   4082         WebPoint scrollPoint(scrollOffset.width, scrollOffset.height);
   4083         setPageScaleFactor(pageScaleFactor() * pageScaleDelta, scrollPoint);
   4084         m_doubleTapZoomPending = false;
   4085     }
   4086 }
   4087 
   4088 void WebViewImpl::didExitCompositingMode()
   4089 {
   4090     ASSERT(m_isAcceleratedCompositingActive);
   4091     setIsAcceleratedCompositingActive(false);
   4092     m_compositorCreationFailed = true;
   4093     m_client->didInvalidateRect(IntRect(0, 0, m_size.width, m_size.height));
   4094 
   4095     // Force a style recalc to remove all the composited layers.
   4096     m_page->mainFrame()->document()->setNeedsStyleRecalc();
   4097 
   4098     if (m_pageOverlays)
   4099         m_pageOverlays->update();
   4100 }
   4101 
   4102 void WebViewImpl::updateLayerTreeViewport()
   4103 {
   4104     if (!page() || !m_layerTreeView)
   4105         return;
   4106 
   4107     m_layerTreeView->setPageScaleFactorAndLimits(pageScaleFactor(), minimumPageScaleFactor(), maximumPageScaleFactor());
   4108 }
   4109 
   4110 void WebViewImpl::selectAutofillSuggestionAtIndex(unsigned listIndex)
   4111 {
   4112     if (m_autofillPopupClient && listIndex < m_autofillPopupClient->getSuggestionsCount())
   4113         m_autofillPopupClient->valueChanged(listIndex);
   4114 }
   4115 
   4116 bool WebViewImpl::detectContentOnTouch(const WebPoint& position)
   4117 {
   4118     HitTestResult touchHit = hitTestResultForWindowPos(position);
   4119 
   4120     if (touchHit.isContentEditable())
   4121         return false;
   4122 
   4123     Node* node = touchHit.innerNode();
   4124     if (!node || !node->isTextNode())
   4125         return false;
   4126 
   4127     // Ignore when tapping on links or nodes listening to click events, unless the click event is on the
   4128     // body element, in which case it's unlikely that the original node itself was intended to be clickable.
   4129     for (; node && !node->hasTagName(HTMLNames::bodyTag); node = node->parentNode()) {
   4130         if (node->isLink() || node->willRespondToTouchEvents() || node->willRespondToMouseClickEvents())
   4131             return false;
   4132     }
   4133 
   4134     WebContentDetectionResult content = m_client->detectContentAround(touchHit);
   4135     if (!content.isValid())
   4136         return false;
   4137 
   4138     m_client->scheduleContentIntent(content.intent());
   4139     return true;
   4140 }
   4141 
   4142 void WebViewImpl::didProgrammaticallyScroll(const WebCore::IntPoint& scrollPoint)
   4143 {
   4144     m_client->didProgrammaticallyScroll(scrollPoint);
   4145 }
   4146 
   4147 void WebViewImpl::setVisibilityState(WebPageVisibilityState visibilityState,
   4148                                      bool isInitialState) {
   4149     if (!page())
   4150         return;
   4151 
   4152     ASSERT(visibilityState == WebPageVisibilityStateVisible
   4153            || visibilityState == WebPageVisibilityStateHidden
   4154            || visibilityState == WebPageVisibilityStatePrerender
   4155            || visibilityState == WebPageVisibilityStatePreview);
   4156     m_page->setVisibilityState(static_cast<PageVisibilityState>(static_cast<int>(visibilityState)), isInitialState);
   4157 
   4158     if (m_layerTreeView) {
   4159         bool visible = visibilityState == WebPageVisibilityStateVisible;
   4160         m_layerTreeView->setVisible(visible);
   4161     }
   4162 }
   4163 
   4164 bool WebViewImpl::requestPointerLock()
   4165 {
   4166     return m_client && m_client->requestPointerLock();
   4167 }
   4168 
   4169 void WebViewImpl::requestPointerUnlock()
   4170 {
   4171     if (m_client)
   4172         m_client->requestPointerUnlock();
   4173 }
   4174 
   4175 bool WebViewImpl::isPointerLocked()
   4176 {
   4177     return m_client && m_client->isPointerLocked();
   4178 }
   4179 
   4180 void WebViewImpl::pointerLockMouseEvent(const WebInputEvent& event)
   4181 {
   4182     AtomicString eventType;
   4183     switch (event.type) {
   4184     case WebInputEvent::MouseDown:
   4185         eventType = eventNames().mousedownEvent;
   4186         break;
   4187     case WebInputEvent::MouseUp:
   4188         eventType = eventNames().mouseupEvent;
   4189         break;
   4190     case WebInputEvent::MouseMove:
   4191         eventType = eventNames().mousemoveEvent;
   4192         break;
   4193     default:
   4194         ASSERT_NOT_REACHED();
   4195     }
   4196 
   4197     const WebMouseEvent& mouseEvent = static_cast<const WebMouseEvent&>(event);
   4198 
   4199     if (page())
   4200         page()->pointerLockController()->dispatchLockedMouseEvent(
   4201             PlatformMouseEventBuilder(mainFrameImpl()->frameView(), mouseEvent),
   4202             eventType);
   4203 }
   4204 
   4205 bool WebViewImpl::shouldDisableDesktopWorkarounds()
   4206 {
   4207     ViewportArguments arguments = mainFrameImpl()->frame()->document()->viewportArguments();
   4208     return arguments.width == ViewportArguments::ValueDeviceWidth || !arguments.userZoom
   4209         || (arguments.minZoom == arguments.maxZoom && arguments.minZoom != ViewportArguments::ValueAuto);
   4210 }
   4211 
   4212 } // namespace WebKit
   4213