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