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