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