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