Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / third_party / WebKit / Source / web / WebViewImpl.cpp
blobd8969fa87f73f403da2a3acbbaee6b143a00293c
1 /*
2 * Copyright (C) 2011, 2012 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
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.
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.
31 #include "config.h"
32 #include "web/WebViewImpl.h"
34 #include "core/CSSValueKeywords.h"
35 #include "core/HTMLNames.h"
36 #include "core/InputTypeNames.h"
37 #include "core/clipboard/DataObject.h"
38 #include "core/dom/Document.h"
39 #include "core/dom/Fullscreen.h"
40 #include "core/dom/LayoutTreeBuilderTraversal.h"
41 #include "core/dom/Text.h"
42 #include "core/editing/EditingUtilities.h"
43 #include "core/editing/Editor.h"
44 #include "core/editing/FrameSelection.h"
45 #include "core/editing/InputMethodController.h"
46 #include "core/editing/iterators/TextIterator.h"
47 #include "core/editing/markers/DocumentMarkerController.h"
48 #include "core/editing/serializers/HTMLInterchange.h"
49 #include "core/editing/serializers/Serialization.h"
50 #include "core/events/KeyboardEvent.h"
51 #include "core/events/UIEventWithKeyState.h"
52 #include "core/events/WheelEvent.h"
53 #include "core/fetch/UniqueIdentifier.h"
54 #include "core/frame/EventHandlerRegistry.h"
55 #include "core/frame/FrameHost.h"
56 #include "core/frame/FrameView.h"
57 #include "core/frame/LocalFrame.h"
58 #include "core/frame/PageScaleConstraintsSet.h"
59 #include "core/frame/RemoteFrame.h"
60 #include "core/frame/Settings.h"
61 #include "core/frame/SmartClip.h"
62 #include "core/frame/TopControls.h"
63 #include "core/frame/VisualViewport.h"
64 #include "core/html/HTMLInputElement.h"
65 #include "core/html/HTMLMediaElement.h"
66 #include "core/html/HTMLPlugInElement.h"
67 #include "core/html/HTMLTextAreaElement.h"
68 #include "core/input/EventHandler.h"
69 #include "core/input/TouchActionUtil.h"
70 #include "core/layout/LayoutPart.h"
71 #include "core/layout/LayoutView.h"
72 #include "core/layout/TextAutosizer.h"
73 #include "core/layout/compositing/DeprecatedPaintLayerCompositor.h"
74 #include "core/loader/DocumentLoader.h"
75 #include "core/loader/FrameLoadRequest.h"
76 #include "core/loader/FrameLoader.h"
77 #include "core/loader/FrameLoaderClient.h"
78 #include "core/loader/FrameLoaderStateMachine.h"
79 #include "core/page/ContextMenuController.h"
80 #include "core/page/ContextMenuProvider.h"
81 #include "core/page/DragController.h"
82 #include "core/page/DragData.h"
83 #include "core/page/DragSession.h"
84 #include "core/page/FocusController.h"
85 #include "core/page/FrameTree.h"
86 #include "core/page/Page.h"
87 #include "core/page/PagePopupClient.h"
88 #include "core/page/PointerLockController.h"
89 #include "core/page/ScopedPageLoadDeferrer.h"
90 #include "core/page/TouchDisambiguation.h"
91 #include "core/paint/DeprecatedPaintLayer.h"
92 #include "core/timing/DOMWindowPerformance.h"
93 #include "core/timing/Performance.h"
94 #include "modules/accessibility/AXObject.h"
95 #include "modules/accessibility/AXObjectCacheImpl.h"
96 #include "modules/credentialmanager/CredentialManagerClient.h"
97 #include "modules/encryptedmedia/MediaKeysController.h"
98 #include "modules/storage/StorageNamespaceController.h"
99 #include "modules/webgl/WebGLRenderingContext.h"
100 #include "platform/ContextMenu.h"
101 #include "platform/ContextMenuItem.h"
102 #include "platform/Cursor.h"
103 #include "platform/KeyboardCodes.h"
104 #include "platform/Logging.h"
105 #include "platform/NotImplemented.h"
106 #include "platform/PlatformGestureEvent.h"
107 #include "platform/PlatformKeyboardEvent.h"
108 #include "platform/PlatformMouseEvent.h"
109 #include "platform/PlatformWheelEvent.h"
110 #include "platform/RuntimeEnabledFeatures.h"
111 #include "platform/TraceEvent.h"
112 #include "platform/UserGestureIndicator.h"
113 #include "platform/exported/WebActiveGestureAnimation.h"
114 #include "platform/fonts/FontCache.h"
115 #include "platform/graphics/Color.h"
116 #include "platform/graphics/FirstPaintInvalidationTracking.h"
117 #include "platform/graphics/Image.h"
118 #include "platform/graphics/ImageBuffer.h"
119 #include "platform/graphics/gpu/DrawingBuffer.h"
120 #include "platform/scroll/ScrollbarTheme.h"
121 #include "platform/weborigin/SchemeRegistry.h"
122 #include "public/platform/Platform.h"
123 #include "public/platform/WebCompositeAndReadbackAsyncCallback.h"
124 #include "public/platform/WebCompositorSupport.h"
125 #include "public/platform/WebDragData.h"
126 #include "public/platform/WebFloatPoint.h"
127 #include "public/platform/WebGestureCurve.h"
128 #include "public/platform/WebImage.h"
129 #include "public/platform/WebLayerTreeView.h"
130 #include "public/platform/WebURLRequest.h"
131 #include "public/platform/WebVector.h"
132 #include "public/web/WebAXObject.h"
133 #include "public/web/WebActiveWheelFlingParameters.h"
134 #include "public/web/WebAutofillClient.h"
135 #include "public/web/WebBeginFrameArgs.h"
136 #include "public/web/WebElement.h"
137 #include "public/web/WebFrame.h"
138 #include "public/web/WebFrameClient.h"
139 #include "public/web/WebGraphicsContext.h"
140 #include "public/web/WebHitTestResult.h"
141 #include "public/web/WebInputElement.h"
142 #include "public/web/WebMediaPlayerAction.h"
143 #include "public/web/WebNode.h"
144 #include "public/web/WebPlugin.h"
145 #include "public/web/WebPluginAction.h"
146 #include "public/web/WebRange.h"
147 #include "public/web/WebSelection.h"
148 #include "public/web/WebTextInputInfo.h"
149 #include "public/web/WebViewClient.h"
150 #include "public/web/WebWindowFeatures.h"
151 #include "web/CompositionUnderlineVectorBuilder.h"
152 #include "web/ContextFeaturesClientImpl.h"
153 #include "web/ContextMenuAllowedScope.h"
154 #include "web/DatabaseClientImpl.h"
155 #include "web/DevToolsEmulator.h"
156 #include "web/FullscreenController.h"
157 #include "web/GraphicsLayerFactoryChromium.h"
158 #include "web/InspectorOverlayImpl.h"
159 #include "web/LinkHighlightImpl.h"
160 #include "web/PageOverlay.h"
161 #include "web/PrerendererClientImpl.h"
162 #include "web/ResizeViewportAnchor.h"
163 #include "web/RotationViewportAnchor.h"
164 #include "web/SpeechRecognitionClientProxy.h"
165 #include "web/StorageQuotaClientImpl.h"
166 #include "web/ValidationMessageClientImpl.h"
167 #include "web/ViewportAnchor.h"
168 #include "web/WebDevToolsAgentImpl.h"
169 #include "web/WebInputEventConversion.h"
170 #include "web/WebLocalFrameImpl.h"
171 #include "web/WebPagePopupImpl.h"
172 #include "web/WebPluginContainerImpl.h"
173 #include "web/WebRemoteFrameImpl.h"
174 #include "web/WebSettingsImpl.h"
175 #include "web/WorkerGlobalScopeProxyProviderImpl.h"
176 #include "wtf/CurrentTime.h"
177 #include "wtf/RefPtr.h"
178 #include "wtf/TemporaryChange.h"
180 #if USE(DEFAULT_RENDER_THEME)
181 #include "core/layout/LayoutThemeDefault.h"
182 #endif
184 // Get rid of WTF's pow define so we can use std::pow.
185 #undef pow
186 #include <cmath> // for std::pow
188 // The following constants control parameters for automated scaling of webpages
189 // (such as due to a double tap gesture or find in page etc.). These are
190 // experimentally determined.
191 static const int touchPointPadding = 32;
192 static const int nonUserInitiatedPointPadding = 11;
193 static const float minScaleDifference = 0.01f;
194 static const float doubleTapZoomContentDefaultMargin = 5;
195 static const float doubleTapZoomContentMinimumMargin = 2;
196 static const double doubleTapZoomAnimationDurationInSeconds = 0.25;
197 static const float doubleTapZoomAlreadyLegibleRatio = 1.2f;
199 static const double multipleTargetsZoomAnimationDurationInSeconds = 0.25;
200 static const double findInPageAnimationDurationInSeconds = 0;
202 // Constants for viewport anchoring on resize.
203 static const float viewportAnchorCoordX = 0.5f;
204 static const float viewportAnchorCoordY = 0;
206 // Constants for zooming in on a focused text field.
207 static const double scrollAndScaleAnimationDurationInSeconds = 0.2;
208 static const int minReadableCaretHeight = 16;
209 static const int minReadableCaretHeightForTextArea = 13;
210 static const float minScaleChangeToTriggerZoom = 1.5f;
211 static const float leftBoxRatio = 0.3f;
212 static const int caretPadding = 10;
214 namespace blink {
216 // Change the text zoom level by kTextSizeMultiplierRatio each time the user
217 // zooms text in or out (ie., change by 20%). The min and max values limit
218 // text zoom to half and 3x the original text size. These three values match
219 // those in Apple's port in WebKit/WebKit/WebView/WebView.mm
220 const double WebView::textSizeMultiplierRatio = 1.2;
221 const double WebView::minTextSizeMultiplier = 0.5;
222 const double WebView::maxTextSizeMultiplier = 3.0;
224 // Used to defer all page activity in cases where the embedder wishes to run
225 // a nested event loop. Using a stack enables nesting of message loop invocations.
226 static Vector<OwnPtr<ScopedPageLoadDeferrer>>& pageLoadDeferrerStack()
228 DEFINE_STATIC_LOCAL(Vector<OwnPtr<ScopedPageLoadDeferrer>>, deferrerStack, ());
229 return deferrerStack;
232 // Ensure that the WebDragOperation enum values stay in sync with the original
233 // DragOperation constants.
234 #define STATIC_ASSERT_MATCHING_ENUM(coreName) \
235 static_assert(int(coreName) == int(Web##coreName), "DragOperation and WebDragOperation enum mismatch: " #coreName)
236 STATIC_ASSERT_MATCHING_ENUM(DragOperationNone);
237 STATIC_ASSERT_MATCHING_ENUM(DragOperationCopy);
238 STATIC_ASSERT_MATCHING_ENUM(DragOperationLink);
239 STATIC_ASSERT_MATCHING_ENUM(DragOperationGeneric);
240 STATIC_ASSERT_MATCHING_ENUM(DragOperationPrivate);
241 STATIC_ASSERT_MATCHING_ENUM(DragOperationMove);
242 STATIC_ASSERT_MATCHING_ENUM(DragOperationDelete);
243 STATIC_ASSERT_MATCHING_ENUM(DragOperationEvery);
245 static bool shouldUseExternalPopupMenus = false;
247 namespace {
249 class UserGestureNotifier {
250 public:
251 // If a UserGestureIndicator is created for a user gesture since the last
252 // page load and *userGestureObserved is false, the UserGestureNotifier
253 // will notify the client and set *userGestureObserved to true.
254 UserGestureNotifier(WebAutofillClient*, bool* userGestureObserved);
255 ~UserGestureNotifier();
257 private:
258 WebAutofillClient* const m_client;
259 bool* const m_userGestureObserved;
262 UserGestureNotifier::UserGestureNotifier(WebAutofillClient* client, bool* userGestureObserved)
263 : m_client(client)
264 , m_userGestureObserved(userGestureObserved)
266 ASSERT(m_userGestureObserved);
269 UserGestureNotifier::~UserGestureNotifier()
271 if (!*m_userGestureObserved && UserGestureIndicator::processedUserGestureSinceLoad()) {
272 *m_userGestureObserved = true;
273 if (m_client)
274 m_client->firstUserGestureObserved();
278 class EmptyEventListener final : public EventListener {
279 public:
280 static PassRefPtrWillBeRawPtr<EmptyEventListener> create()
282 return adoptRefWillBeNoop(new EmptyEventListener());
285 bool operator==(const EventListener& other) override
287 return this == &other;
290 private:
291 EmptyEventListener()
292 : EventListener(CPPEventListenerType)
296 void handleEvent(ExecutionContext* executionContext, Event*) override
301 class ColorOverlay final : public PageOverlay::Delegate {
302 public:
303 explicit ColorOverlay(WebColor color)
304 : m_color(color)
308 virtual ~ColorOverlay()
312 private:
313 void paintPageOverlay(WebGraphicsContext* context, const WebSize& size)
315 WebFloatRect rect(0, 0, size.width, size.height);
316 WebCanvas* canvas = context->beginDrawing(rect);
317 SkPaint paint;
318 paint.setColor(m_color);
319 paint.setStyle(SkPaint::kFill_Style);
320 canvas->drawRectCoords(0, 0, size.width, size.height, paint);
321 context->endDrawing();
324 WebColor m_color;
327 } // namespace
329 // WebView ----------------------------------------------------------------
331 WebView* WebView::create(WebViewClient* client)
333 // Pass the WebViewImpl's self-reference to the caller.
334 return WebViewImpl::create(client);
337 WebViewImpl* WebViewImpl::create(WebViewClient* client)
339 // Pass the WebViewImpl's self-reference to the caller.
340 return adoptRef(new WebViewImpl(client)).leakRef();
343 void WebView::setUseExternalPopupMenus(bool useExternalPopupMenus)
345 shouldUseExternalPopupMenus = useExternalPopupMenus;
348 void WebView::updateVisitedLinkState(unsigned long long linkHash)
350 Page::visitedStateChanged(linkHash);
353 void WebView::resetVisitedLinkState()
355 Page::allVisitedStateChanged();
358 void WebView::willEnterModalLoop()
360 pageLoadDeferrerStack().append(adoptPtr(new ScopedPageLoadDeferrer()));
363 void WebView::didExitModalLoop()
365 ASSERT(pageLoadDeferrerStack().size());
366 pageLoadDeferrerStack().removeLast();
369 void WebViewImpl::setMainFrame(WebFrame* frame)
371 if (frame->isWebLocalFrame()) {
372 WebLocalFrameImpl* localFrame = toWebLocalFrameImpl(frame);
373 localFrame->initializeCoreFrame(&page()->frameHost(), 0, nullAtom, nullAtom);
374 // Composited WebViews want repaints outside the frame visible rect.
375 localFrame->frame()->view()->setClipsRepaints(!m_layerTreeView);
376 } else {
377 toWebRemoteFrameImpl(frame)->initializeCoreFrame(&page()->frameHost(), 0, nullAtom);
381 void WebViewImpl::setCredentialManagerClient(WebCredentialManagerClient* webCredentialManagerClient)
383 ASSERT(m_page);
384 provideCredentialManagerClientTo(*m_page, new CredentialManagerClient(webCredentialManagerClient));
387 void WebViewImpl::setPrerendererClient(WebPrerendererClient* prerendererClient)
389 ASSERT(m_page);
390 providePrerendererClientTo(*m_page, new PrerendererClientImpl(prerendererClient));
393 void WebViewImpl::setSpellCheckClient(WebSpellCheckClient* spellCheckClient)
395 m_spellCheckClient = spellCheckClient;
398 // static
399 HashSet<WebViewImpl*>& WebViewImpl::allInstances()
401 DEFINE_STATIC_LOCAL(HashSet<WebViewImpl*>, allInstances, ());
402 return allInstances;
405 WebViewImpl::WebViewImpl(WebViewClient* client)
406 : m_client(client)
407 , m_spellCheckClient(0)
408 , m_chromeClientImpl(ChromeClientImpl::create(this))
409 , m_contextMenuClientImpl(this)
410 , m_dragClientImpl(this)
411 , m_editorClientImpl(this)
412 , m_spellCheckerClientImpl(this)
413 , m_storageClientImpl(this)
414 , m_shouldAutoResize(false)
415 , m_zoomLevel(0)
416 , m_minimumZoomLevel(zoomFactorToZoomLevel(minTextSizeMultiplier))
417 , m_maximumZoomLevel(zoomFactorToZoomLevel(maxTextSizeMultiplier))
418 , m_maximumLegibleScale(1)
419 , m_doubleTapZoomPageScaleFactor(0)
420 , m_doubleTapZoomPending(false)
421 , m_enableFakePageScaleAnimationForTesting(false)
422 , m_fakePageScaleAnimationPageScaleFactor(0)
423 , m_fakePageScaleAnimationUseAnchor(false)
424 , m_doingDragAndDrop(false)
425 , m_ignoreInputEvents(false)
426 , m_compositorDeviceScaleFactorOverride(0)
427 , m_rootLayerScale(1)
428 , m_suppressNextKeypressEvent(false)
429 , m_imeAcceptEvents(true)
430 , m_operationsAllowed(WebDragOperationNone)
431 , m_dragOperation(WebDragOperationNone)
432 , m_devToolsEmulator(nullptr)
433 , m_isTransparent(false)
434 , m_tabsToLinks(false)
435 , m_layerTreeView(0)
436 , m_rootLayer(0)
437 , m_rootGraphicsLayer(0)
438 , m_rootTransformLayer(0)
439 , m_graphicsLayerFactory(adoptPtr(new GraphicsLayerFactoryChromium(this)))
440 , m_matchesHeuristicsForGpuRasterization(false)
441 , m_recreatingGraphicsContext(false)
442 , m_flingModifier(0)
443 , m_flingSourceDevice(false)
444 , m_fullscreenController(FullscreenController::create(this))
445 , m_showFPSCounter(false)
446 , m_baseBackgroundColor(Color::white)
447 , m_backgroundColorOverride(Color::transparent)
448 , m_zoomFactorOverride(0)
449 , m_userGestureObserved(false)
450 , m_shouldDispatchFirstVisuallyNonEmptyLayout(false)
451 , m_shouldDispatchFirstLayoutAfterFinishedParsing(false)
452 , m_displayMode(WebDisplayModeBrowser)
453 , m_elasticOverscroll(FloatSize())
455 Page::PageClients pageClients;
456 pageClients.chromeClient = m_chromeClientImpl.get();
457 pageClients.contextMenuClient = &m_contextMenuClientImpl;
458 pageClients.editorClient = &m_editorClientImpl;
459 pageClients.dragClient = &m_dragClientImpl;
460 pageClients.spellCheckerClient = &m_spellCheckerClientImpl;
462 m_page = adoptPtrWillBeNoop(new Page(pageClients));
463 MediaKeysController::provideMediaKeysTo(*m_page, &m_mediaKeysClientImpl);
464 provideSpeechRecognitionTo(*m_page, SpeechRecognitionClientProxy::create(client ? client->speechRecognizer() : 0));
465 provideContextFeaturesTo(*m_page, ContextFeaturesClientImpl::create());
466 provideDatabaseClientTo(*m_page, DatabaseClientImpl::create());
468 provideStorageQuotaClientTo(*m_page, StorageQuotaClientImpl::create());
469 m_page->setValidationMessageClient(ValidationMessageClientImpl::create(*this));
470 provideWorkerGlobalScopeProxyProviderTo(*m_page, WorkerGlobalScopeProxyProviderImpl::create());
471 StorageNamespaceController::provideStorageNamespaceTo(*m_page, &m_storageClientImpl);
473 m_page->makeOrdinary();
475 if (m_client) {
476 setDeviceScaleFactor(m_client->screenInfo().deviceScaleFactor);
477 setVisibilityState(m_client->visibilityState(), true);
480 initializeLayerTreeView();
482 m_devToolsEmulator = DevToolsEmulator::create(this);
484 allInstances().add(this);
486 m_pageImportanceSignals.setObserver(client);
489 WebViewImpl::~WebViewImpl()
491 ASSERT(!m_page);
494 WebDevToolsAgentImpl* WebViewImpl::mainFrameDevToolsAgentImpl()
496 WebLocalFrameImpl* mainFrame = mainFrameImpl();
497 return mainFrame ? mainFrame->devToolsAgentImpl() : nullptr;
500 InspectorOverlayImpl* WebViewImpl::inspectorOverlay()
502 if (WebDevToolsAgentImpl* devtools = mainFrameDevToolsAgentImpl())
503 return static_cast<InspectorOverlayImpl*>(devtools->overlay());
504 return nullptr;
507 WebLocalFrameImpl* WebViewImpl::mainFrameImpl()
509 return m_page && m_page->mainFrame() && m_page->mainFrame()->isLocalFrame() ? WebLocalFrameImpl::fromFrame(m_page->deprecatedLocalMainFrame()) : 0;
512 bool WebViewImpl::tabKeyCyclesThroughElements() const
514 ASSERT(m_page);
515 return m_page->tabKeyCyclesThroughElements();
518 void WebViewImpl::setTabKeyCyclesThroughElements(bool value)
520 if (m_page)
521 m_page->setTabKeyCyclesThroughElements(value);
524 void WebViewImpl::handleMouseLeave(LocalFrame& mainFrame, const WebMouseEvent& event)
526 m_client->setMouseOverURL(WebURL());
527 PageWidgetEventHandler::handleMouseLeave(mainFrame, event);
530 void WebViewImpl::handleMouseDown(LocalFrame& mainFrame, const WebMouseEvent& event)
532 // If there is a popup open, close it as the user is clicking on the page
533 // (outside of the popup). We also save it so we can prevent a click on an
534 // element from immediately reopening the same popup.
535 RefPtr<WebPagePopupImpl> pagePopup;
536 if (event.button == WebMouseEvent::ButtonLeft) {
537 pagePopup = m_pagePopup;
538 hidePopups();
539 ASSERT(!m_pagePopup);
542 m_lastMouseDownPoint = WebPoint(event.x, event.y);
544 // Take capture on a mouse down on a plugin so we can send it mouse events.
545 // If the hit node is a plugin but a scrollbar is over it don't start mouse
546 // capture because it will interfere with the scrollbar receiving events.
547 IntPoint point(event.x, event.y);
548 if (event.button == WebMouseEvent::ButtonLeft && m_page->mainFrame()->isLocalFrame()) {
549 point = m_page->deprecatedLocalMainFrame()->view()->rootFrameToContents(point);
550 HitTestResult result(m_page->deprecatedLocalMainFrame()->eventHandler().hitTestResultAtPoint(point));
551 result.setToShadowHostIfInUserAgentShadowRoot();
552 Node* hitNode = result.innerNodeOrImageMapImage();
554 if (!result.scrollbar() && hitNode && hitNode->layoutObject() && hitNode->layoutObject()->isEmbeddedObject()) {
555 m_mouseCaptureNode = hitNode;
556 TRACE_EVENT_ASYNC_BEGIN0("input", "capturing mouse", this);
560 PageWidgetEventHandler::handleMouseDown(mainFrame, event);
562 if (event.button == WebMouseEvent::ButtonLeft && m_mouseCaptureNode)
563 m_mouseCaptureGestureToken = mainFrame.eventHandler().takeLastMouseDownGestureToken();
565 if (m_pagePopup && pagePopup && m_pagePopup->hasSamePopupClient(pagePopup.get())) {
566 // That click triggered a page popup that is the same as the one we just closed.
567 // It needs to be closed.
568 cancelPagePopup();
571 // Dispatch the contextmenu event regardless of if the click was swallowed.
572 if (!page()->settings().showContextMenuOnMouseUp()) {
573 #if OS(MACOSX)
574 if (event.button == WebMouseEvent::ButtonRight
575 || (event.button == WebMouseEvent::ButtonLeft
576 && event.modifiers & WebMouseEvent::ControlKey))
577 mouseContextMenu(event);
578 #else
579 if (event.button == WebMouseEvent::ButtonRight)
580 mouseContextMenu(event);
581 #endif
585 void WebViewImpl::setDisplayMode(WebDisplayMode mode)
587 m_displayMode = mode;
588 if (!mainFrameImpl() || !mainFrameImpl()->frameView())
589 return;
591 mainFrameImpl()->frameView()->setDisplayMode(mode);
594 void WebViewImpl::mouseContextMenu(const WebMouseEvent& event)
596 if (!mainFrameImpl() || !mainFrameImpl()->frameView())
597 return;
599 m_page->contextMenuController().clearContextMenu();
601 PlatformMouseEventBuilder pme(mainFrameImpl()->frameView(), event);
603 // Find the right target frame. See issue 1186900.
604 HitTestResult result = hitTestResultForRootFramePos(pme.position());
605 Frame* targetFrame;
606 if (result.innerNodeOrImageMapImage())
607 targetFrame = result.innerNodeOrImageMapImage()->document().frame();
608 else
609 targetFrame = m_page->focusController().focusedOrMainFrame();
611 if (!targetFrame->isLocalFrame())
612 return;
614 LocalFrame* targetLocalFrame = toLocalFrame(targetFrame);
616 #if OS(WIN)
617 targetLocalFrame->view()->setCursor(pointerCursor());
618 #endif
621 ContextMenuAllowedScope scope;
622 targetLocalFrame->eventHandler().sendContextMenuEvent(pme, nullptr);
624 // Actually showing the context menu is handled by the ContextMenuClient
625 // implementation...
628 void WebViewImpl::handleMouseUp(LocalFrame& mainFrame, const WebMouseEvent& event)
630 PageWidgetEventHandler::handleMouseUp(mainFrame, event);
632 if (page()->settings().showContextMenuOnMouseUp()) {
633 // Dispatch the contextmenu event regardless of if the click was swallowed.
634 // On Mac/Linux, we handle it on mouse down, not up.
635 if (event.button == WebMouseEvent::ButtonRight)
636 mouseContextMenu(event);
640 bool WebViewImpl::handleMouseWheel(LocalFrame& mainFrame, const WebMouseWheelEvent& event)
642 hidePopups();
643 return PageWidgetEventHandler::handleMouseWheel(mainFrame, event);
646 bool WebViewImpl::scrollBy(const WebFloatSize& delta, const WebFloatSize& velocity)
648 if (m_flingSourceDevice == WebGestureDeviceTouchpad) {
649 WebMouseWheelEvent syntheticWheel;
650 const float tickDivisor = WheelEvent::TickMultiplier;
652 syntheticWheel.deltaX = delta.width;
653 syntheticWheel.deltaY = delta.height;
654 syntheticWheel.wheelTicksX = delta.width / tickDivisor;
655 syntheticWheel.wheelTicksY = delta.height / tickDivisor;
656 syntheticWheel.hasPreciseScrollingDeltas = true;
657 syntheticWheel.x = m_positionOnFlingStart.x;
658 syntheticWheel.y = m_positionOnFlingStart.y;
659 syntheticWheel.globalX = m_globalPositionOnFlingStart.x;
660 syntheticWheel.globalY = m_globalPositionOnFlingStart.y;
661 syntheticWheel.modifiers = m_flingModifier;
663 if (m_page && m_page->mainFrame() && m_page->mainFrame()->isLocalFrame() && m_page->deprecatedLocalMainFrame()->view())
664 return handleMouseWheel(*m_page->deprecatedLocalMainFrame(), syntheticWheel);
665 } else {
666 WebGestureEvent syntheticGestureEvent;
668 syntheticGestureEvent.type = WebInputEvent::GestureScrollUpdate;
669 syntheticGestureEvent.data.scrollUpdate.preventPropagation = true;
670 syntheticGestureEvent.data.scrollUpdate.deltaX = delta.width;
671 syntheticGestureEvent.data.scrollUpdate.deltaY = delta.height;
672 syntheticGestureEvent.data.scrollUpdate.velocityX = velocity.width;
673 syntheticGestureEvent.data.scrollUpdate.velocityY = velocity.height;
674 syntheticGestureEvent.x = m_positionOnFlingStart.x;
675 syntheticGestureEvent.y = m_positionOnFlingStart.y;
676 syntheticGestureEvent.globalX = m_globalPositionOnFlingStart.x;
677 syntheticGestureEvent.globalY = m_globalPositionOnFlingStart.y;
678 syntheticGestureEvent.modifiers = m_flingModifier;
679 syntheticGestureEvent.sourceDevice = WebGestureDeviceTouchscreen;
680 syntheticGestureEvent.data.scrollUpdate.inertial = true;
682 if (m_page && m_page->mainFrame() && m_page->mainFrame()->isLocalFrame() && m_page->deprecatedLocalMainFrame()->view())
683 return handleGestureEvent(syntheticGestureEvent);
685 return false;
688 bool WebViewImpl::handleGestureEvent(const WebGestureEvent& event)
690 if (!m_client)
691 return false;
693 bool eventSwallowed = false;
694 bool eventCancelled = false; // for disambiguation
696 // Special handling for slow-path fling gestures.
697 switch (event.type) {
698 case WebInputEvent::GestureFlingStart: {
699 if (mainFrameImpl()->frame()->eventHandler().isScrollbarHandlingGestures())
700 break;
701 endActiveFlingAnimation();
702 m_client->cancelScheduledContentIntents();
703 m_positionOnFlingStart = WebPoint(event.x, event.y);
704 m_globalPositionOnFlingStart = WebPoint(event.globalX, event.globalY);
705 m_flingModifier = event.modifiers;
706 m_flingSourceDevice = event.sourceDevice;
707 OwnPtr<WebGestureCurve> flingCurve = adoptPtr(Platform::current()->createFlingAnimationCurve(event.sourceDevice, WebFloatPoint(event.data.flingStart.velocityX, event.data.flingStart.velocityY), WebSize()));
708 ASSERT(flingCurve);
709 m_gestureAnimation = WebActiveGestureAnimation::createAtAnimationStart(flingCurve.release(), this);
710 scheduleAnimation();
711 eventSwallowed = true;
713 // Plugins may need to see GestureFlingStart to balance
714 // GestureScrollBegin (since the former replaces GestureScrollEnd when
715 // transitioning to a fling).
716 PlatformGestureEventBuilder platformEvent(mainFrameImpl()->frameView(), event);
717 mainFrameImpl()->frame()->eventHandler().handleGestureScrollEvent(platformEvent);
719 m_client->didHandleGestureEvent(event, eventCancelled);
720 return eventSwallowed;
722 case WebInputEvent::GestureFlingCancel:
723 if (endActiveFlingAnimation())
724 eventSwallowed = true;
726 m_client->didHandleGestureEvent(event, eventCancelled);
727 return eventSwallowed;
728 default:
729 break;
732 PlatformGestureEventBuilder platformEvent(mainFrameImpl()->frameView(), event);
734 // Special handling for double tap and scroll events as we don't want to
735 // hit test for them.
736 switch (event.type) {
737 case WebInputEvent::GestureDoubleTap:
738 if (m_webSettings->doubleTapToZoomEnabled() && minimumPageScaleFactor() != maximumPageScaleFactor()) {
739 m_client->cancelScheduledContentIntents();
740 animateDoubleTapZoom(platformEvent.position());
742 // GestureDoubleTap is currently only used by Android for zooming. For WebCore,
743 // GestureTap with tap count = 2 is used instead. So we drop GestureDoubleTap here.
744 eventSwallowed = true;
745 m_client->didHandleGestureEvent(event, eventCancelled);
746 return eventSwallowed;
747 case WebInputEvent::GestureScrollBegin:
748 m_client->cancelScheduledContentIntents();
749 case WebInputEvent::GestureScrollEnd:
750 case WebInputEvent::GestureScrollUpdate:
751 case WebInputEvent::GestureFlingStart:
752 // Scrolling-related gesture events invoke EventHandler recursively for each frame down
753 // the chain, doing a single-frame hit-test per frame. This matches handleWheelEvent.
754 // Perhaps we could simplify things by rewriting scroll handling to work inner frame
755 // out, and then unify with other gesture events.
756 eventSwallowed = mainFrameImpl()->frame()->eventHandler().handleGestureScrollEvent(platformEvent);
757 m_client->didHandleGestureEvent(event, eventCancelled);
758 return eventSwallowed;
759 case WebInputEvent::GesturePinchBegin:
760 case WebInputEvent::GesturePinchEnd:
761 case WebInputEvent::GesturePinchUpdate:
762 return false;
763 default:
764 break;
767 // Hit test across all frames and do touch adjustment as necessary for the event type.
768 GestureEventWithHitTestResults targetedEvent =
769 m_page->deprecatedLocalMainFrame()->eventHandler().targetGestureEvent(platformEvent);
771 // Handle link highlighting outside the main switch to avoid getting lost in the
772 // complicated set of cases handled below.
773 switch (event.type) {
774 case WebInputEvent::GestureShowPress:
775 // Queue a highlight animation, then hand off to regular handler.
776 enableTapHighlightAtPoint(targetedEvent);
777 break;
778 case WebInputEvent::GestureTapCancel:
779 case WebInputEvent::GestureTap:
780 case WebInputEvent::GestureLongPress:
781 for (size_t i = 0; i < m_linkHighlights.size(); ++i)
782 m_linkHighlights[i]->startHighlightAnimationIfNeeded();
783 break;
784 default:
785 break;
788 switch (event.type) {
789 case WebInputEvent::GestureTap: {
790 hidePopups();
791 m_client->cancelScheduledContentIntents();
792 if (detectContentOnTouch(targetedEvent)) {
793 eventSwallowed = true;
794 break;
797 // Don't trigger a disambiguation popup on sites designed for mobile devices.
798 // Instead, assume that the page has been designed with big enough buttons and links.
799 // Don't trigger a disambiguation popup when screencasting, since it's implemented outside of
800 // compositor pipeline and is not being screencasted itself. This leads to bad user experience.
801 WebDevToolsAgentImpl* devTools = mainFrameDevToolsAgentImpl();
802 bool screencastEnabled = devTools && devTools->screencastEnabled();
803 if (event.data.tap.width > 0 && !shouldDisableDesktopWorkarounds() && !screencastEnabled) {
804 IntRect boundingBox(page()->frameHost().visualViewport().viewportToRootFrame(IntRect(
805 event.x - event.data.tap.width / 2,
806 event.y - event.data.tap.height / 2,
807 event.data.tap.width,
808 event.data.tap.height)));
810 // FIXME: We shouldn't pass details of the VisualViewport offset to render_view_impl.
811 WebSize visualViewportOffset = flooredIntSize(page()->frameHost().visualViewport().location());
813 if (m_webSettings->multiTargetTapNotificationEnabled()) {
814 Vector<IntRect> goodTargets;
815 WillBeHeapVector<RawPtrWillBeMember<Node>> highlightNodes;
816 findGoodTouchTargets(boundingBox, mainFrameImpl()->frame(), goodTargets, highlightNodes);
817 // FIXME: replace touch adjustment code when numberOfGoodTargets == 1?
818 // Single candidate case is currently handled by: https://bugs.webkit.org/show_bug.cgi?id=85101
819 if (goodTargets.size() >= 2 && m_client
820 && m_client->didTapMultipleTargets(visualViewportOffset, boundingBox, goodTargets)) {
822 enableTapHighlights(highlightNodes);
823 for (size_t i = 0; i < m_linkHighlights.size(); ++i)
824 m_linkHighlights[i]->startHighlightAnimationIfNeeded();
825 eventSwallowed = true;
826 eventCancelled = true;
827 break;
832 eventSwallowed = mainFrameImpl()->frame()->eventHandler().handleGestureEvent(targetedEvent);
833 break;
835 case WebInputEvent::GestureTwoFingerTap:
836 case WebInputEvent::GestureLongPress:
837 case WebInputEvent::GestureLongTap: {
838 if (!mainFrameImpl() || !mainFrameImpl()->frameView())
839 break;
841 m_client->cancelScheduledContentIntents();
842 m_page->contextMenuController().clearContextMenu();
844 ContextMenuAllowedScope scope;
845 eventSwallowed = mainFrameImpl()->frame()->eventHandler().handleGestureEvent(targetedEvent);
848 break;
850 case WebInputEvent::GestureShowPress:
851 m_client->cancelScheduledContentIntents();
852 case WebInputEvent::GestureTapDown:
853 case WebInputEvent::GestureTapCancel:
854 case WebInputEvent::GestureTapUnconfirmed: {
855 eventSwallowed = mainFrameImpl()->frame()->eventHandler().handleGestureEvent(targetedEvent);
856 break;
858 default:
859 ASSERT_NOT_REACHED();
861 m_client->didHandleGestureEvent(event, eventCancelled);
862 return eventSwallowed;
865 bool WebViewImpl::handleSyntheticWheelFromTouchpadPinchEvent(const WebGestureEvent& pinchEvent)
867 ASSERT(pinchEvent.type == WebInputEvent::GesturePinchUpdate);
869 // Touchscreen pinch events should not reach Blink.
870 ASSERT(pinchEvent.sourceDevice == WebGestureDeviceTouchpad);
872 // For pinch gesture events, match typical trackpad behavior on Windows by sending fake
873 // wheel events with the ctrl modifier set when we see trackpad pinch gestures. Ideally
874 // we'd someday get a platform 'pinch' event and send that instead.
875 WebMouseWheelEvent wheelEvent;
876 wheelEvent.type = WebInputEvent::MouseWheel;
877 wheelEvent.timeStampSeconds = pinchEvent.timeStampSeconds;
878 wheelEvent.windowX = wheelEvent.x = pinchEvent.x;
879 wheelEvent.windowY = wheelEvent.y = pinchEvent.y;
880 wheelEvent.globalX = pinchEvent.globalX;
881 wheelEvent.globalY = pinchEvent.globalY;
882 wheelEvent.modifiers =
883 pinchEvent.modifiers | WebInputEvent::ControlKey;
884 wheelEvent.deltaX = 0;
886 // The function to convert scales to deltaY values is designed to be
887 // compatible with websites existing use of wheel events, and with existing
888 // Windows trackpad behavior. In particular, we want:
889 // - deltas should accumulate via addition: f(s1*s2)==f(s1)+f(s2)
890 // - deltas should invert via negation: f(1/s) == -f(s)
891 // - zoom in should be positive: f(s) > 0 iff s > 1
892 // - magnitude roughly matches wheels: f(2) > 25 && f(2) < 100
893 // - a formula that's relatively easy to use from JavaScript
894 // Note that 'wheel' event deltaY values have their sign inverted. So to
895 // convert a wheel deltaY back to a scale use Math.exp(-deltaY/100).
896 ASSERT(pinchEvent.data.pinchUpdate.scale > 0);
897 wheelEvent.deltaY = 100.0f * log(pinchEvent.data.pinchUpdate.scale);
898 wheelEvent.hasPreciseScrollingDeltas = true;
899 wheelEvent.wheelTicksX = 0;
900 wheelEvent.wheelTicksY =
901 pinchEvent.data.pinchUpdate.scale > 1 ? 1 : -1;
902 wheelEvent.canScroll = false;
904 return handleInputEvent(wheelEvent);
907 void WebViewImpl::transferActiveWheelFlingAnimation(const WebActiveWheelFlingParameters& parameters)
909 TRACE_EVENT0("blink", "WebViewImpl::transferActiveWheelFlingAnimation");
910 ASSERT(!m_gestureAnimation);
911 m_positionOnFlingStart = parameters.point;
912 m_globalPositionOnFlingStart = parameters.globalPoint;
913 m_flingModifier = parameters.modifiers;
914 OwnPtr<WebGestureCurve> curve = adoptPtr(Platform::current()->createFlingAnimationCurve(parameters.sourceDevice, WebFloatPoint(parameters.delta), parameters.cumulativeScroll));
915 ASSERT(curve);
916 m_gestureAnimation = WebActiveGestureAnimation::createWithTimeOffset(curve.release(), this, parameters.startTime);
917 scheduleAnimation();
920 bool WebViewImpl::endActiveFlingAnimation()
922 if (m_gestureAnimation) {
923 m_gestureAnimation.clear();
924 if (m_layerTreeView)
925 m_layerTreeView->didStopFlinging();
926 return true;
928 return false;
931 bool WebViewImpl::startPageScaleAnimation(const IntPoint& targetPosition, bool useAnchor, float newScale, double durationInSeconds)
933 VisualViewport& visualViewport = page()->frameHost().visualViewport();
934 WebPoint clampedPoint = targetPosition;
935 if (!useAnchor) {
936 clampedPoint = visualViewport.clampDocumentOffsetAtScale(targetPosition, newScale);
937 if (!durationInSeconds) {
938 setPageScaleFactor(newScale);
940 FrameView* view = mainFrameImpl()->frameView();
941 if (view && view->scrollableArea())
942 view->scrollableArea()->setScrollPosition(DoublePoint(clampedPoint.x, clampedPoint.y), ProgrammaticScroll);
944 return false;
947 if (useAnchor && newScale == pageScaleFactor())
948 return false;
950 if (m_enableFakePageScaleAnimationForTesting) {
951 m_fakePageScaleAnimationTargetPosition = targetPosition;
952 m_fakePageScaleAnimationUseAnchor = useAnchor;
953 m_fakePageScaleAnimationPageScaleFactor = newScale;
954 } else {
955 if (!m_layerTreeView)
956 return false;
957 m_layerTreeView->startPageScaleAnimation(targetPosition, useAnchor, newScale, durationInSeconds);
959 return true;
962 void WebViewImpl::enableFakePageScaleAnimationForTesting(bool enable)
964 m_enableFakePageScaleAnimationForTesting = enable;
967 void WebViewImpl::setShowFPSCounter(bool show)
969 if (m_layerTreeView) {
970 TRACE_EVENT0("blink", "WebViewImpl::setShowFPSCounter");
971 m_layerTreeView->setShowFPSCounter(show && !m_devToolsEmulator->deviceEmulationEnabled());
973 m_showFPSCounter = show;
976 void WebViewImpl::setShowPaintRects(bool show)
978 if (m_layerTreeView) {
979 TRACE_EVENT0("blink", "WebViewImpl::setShowPaintRects");
980 m_layerTreeView->setShowPaintRects(show);
982 setFirstPaintInvalidationTrackingEnabledForShowPaintRects(show);
985 void WebViewImpl::setShowDebugBorders(bool show)
987 if (m_layerTreeView)
988 m_layerTreeView->setShowDebugBorders(show);
991 void WebViewImpl::updateShowFPSCounter()
993 if (m_layerTreeView)
994 m_layerTreeView->setShowFPSCounter(m_showFPSCounter && !m_devToolsEmulator->deviceEmulationEnabled());
997 void WebViewImpl::setShowScrollBottleneckRects(bool show)
999 if (m_layerTreeView)
1000 m_layerTreeView->setShowScrollBottleneckRects(show);
1003 void WebViewImpl::acceptLanguagesChanged()
1005 if (!page())
1006 return;
1008 page()->acceptLanguagesChanged();
1011 bool WebViewImpl::handleKeyEvent(const WebKeyboardEvent& event)
1013 ASSERT((event.type == WebInputEvent::RawKeyDown)
1014 || (event.type == WebInputEvent::KeyDown)
1015 || (event.type == WebInputEvent::KeyUp));
1017 // Halt an in-progress fling on a key event.
1018 endActiveFlingAnimation();
1020 // Please refer to the comments explaining the m_suppressNextKeypressEvent
1021 // member.
1022 // The m_suppressNextKeypressEvent is set if the KeyDown is handled by
1023 // Webkit. A keyDown event is typically associated with a keyPress(char)
1024 // event and a keyUp event. We reset this flag here as this is a new keyDown
1025 // event.
1026 m_suppressNextKeypressEvent = false;
1028 // If there is a popup, it should be the one processing the event, not the
1029 // page.
1030 if (m_pagePopup) {
1031 m_pagePopup->handleKeyEvent(PlatformKeyboardEventBuilder(event));
1032 // We need to ignore the next Char event after this otherwise pressing
1033 // enter when selecting an item in the popup will go to the page.
1034 if (WebInputEvent::RawKeyDown == event.type)
1035 m_suppressNextKeypressEvent = true;
1036 return true;
1039 RefPtrWillBeRawPtr<Frame> focusedFrame = focusedCoreFrame();
1040 if (focusedFrame && focusedFrame->isRemoteFrame()) {
1041 WebRemoteFrameImpl* webFrame = WebRemoteFrameImpl::fromFrame(*toRemoteFrame(focusedFrame.get()));
1042 webFrame->client()->forwardInputEvent(&event);
1043 return true;
1046 if (!focusedFrame || !focusedFrame->isLocalFrame())
1047 return false;
1049 LocalFrame* frame = toLocalFrame(focusedFrame.get());
1051 PlatformKeyboardEventBuilder evt(event);
1053 if (frame->eventHandler().keyEvent(evt)) {
1054 if (WebInputEvent::RawKeyDown == event.type) {
1055 // Suppress the next keypress event unless the focused node is a plugin node.
1056 // (Flash needs these keypress events to handle non-US keyboards.)
1057 Element* element = focusedElement();
1058 if (element && element->layoutObject() && element->layoutObject()->isEmbeddedObject()) {
1059 if (event.windowsKeyCode == VKEY_TAB) {
1060 // If the plugin supports keyboard focus then we should not send a tab keypress event.
1061 Widget* widget = toLayoutPart(element->layoutObject())->widget();
1062 if (widget && widget->isPluginContainer()) {
1063 WebPluginContainerImpl* plugin = toWebPluginContainerImpl(widget);
1064 if (plugin && plugin->supportsKeyboardFocus())
1065 m_suppressNextKeypressEvent = true;
1068 } else {
1069 m_suppressNextKeypressEvent = true;
1072 return true;
1075 #if !OS(MACOSX)
1076 const WebInputEvent::Type contextMenuTriggeringEventType =
1077 #if OS(WIN)
1078 WebInputEvent::KeyUp;
1079 #else
1080 WebInputEvent::RawKeyDown;
1081 #endif
1083 bool isUnmodifiedMenuKey = !(event.modifiers & WebInputEvent::InputModifiers) && event.windowsKeyCode == VKEY_APPS;
1084 bool isShiftF10 = event.modifiers == WebInputEvent::ShiftKey && event.windowsKeyCode == VKEY_F10;
1085 if ((isUnmodifiedMenuKey || isShiftF10) && event.type == contextMenuTriggeringEventType) {
1086 sendContextMenuEvent(event);
1087 return true;
1089 #endif // !OS(MACOSX)
1091 return keyEventDefault(event);
1094 bool WebViewImpl::handleCharEvent(const WebKeyboardEvent& event)
1096 ASSERT(event.type == WebInputEvent::Char);
1098 // Please refer to the comments explaining the m_suppressNextKeypressEvent
1099 // member. The m_suppressNextKeypressEvent is set if the KeyDown is
1100 // handled by Webkit. A keyDown event is typically associated with a
1101 // keyPress(char) event and a keyUp event. We reset this flag here as it
1102 // only applies to the current keyPress event.
1103 bool suppress = m_suppressNextKeypressEvent;
1104 m_suppressNextKeypressEvent = false;
1106 // If there is a popup, it should be the one processing the event, not the
1107 // page.
1108 if (m_pagePopup)
1109 return m_pagePopup->handleKeyEvent(PlatformKeyboardEventBuilder(event));
1111 LocalFrame* frame = toLocalFrame(focusedCoreFrame());
1112 if (!frame)
1113 return suppress;
1115 EventHandler& handler = frame->eventHandler();
1117 PlatformKeyboardEventBuilder evt(event);
1118 if (!evt.isCharacterKey())
1119 return true;
1121 // Accesskeys are triggered by char events and can't be suppressed.
1122 if (handler.handleAccessKey(evt))
1123 return true;
1125 // Safari 3.1 does not pass off windows system key messages (WM_SYSCHAR) to
1126 // the eventHandler::keyEvent. We mimic this behavior on all platforms since
1127 // for now we are converting other platform's key events to windows key
1128 // events.
1129 if (evt.isSystemKey())
1130 return false;
1132 if (!suppress && !handler.keyEvent(evt))
1133 return keyEventDefault(event);
1135 return true;
1138 WebRect WebViewImpl::computeBlockBound(const WebPoint& pointInRootFrame, bool ignoreClipping)
1140 if (!mainFrameImpl())
1141 return WebRect();
1143 // Use the point-based hit test to find the node.
1144 IntPoint point = mainFrameImpl()->frameView()->rootFrameToContents(IntPoint(pointInRootFrame.x, pointInRootFrame.y));
1145 HitTestRequest::HitTestRequestType hitType = HitTestRequest::ReadOnly | HitTestRequest::Active | (ignoreClipping ? HitTestRequest::IgnoreClipping : 0);
1146 HitTestResult result = mainFrameImpl()->frame()->eventHandler().hitTestResultAtPoint(point, hitType);
1147 result.setToShadowHostIfInUserAgentShadowRoot();
1149 Node* node = result.innerNodeOrImageMapImage();
1150 if (!node)
1151 return WebRect();
1153 // Find the block type node based on the hit node.
1154 // FIXME: This wants to walk composed tree with LayoutTreeBuilderTraversal::parent().
1155 while (node && (!node->layoutObject() || node->layoutObject()->isInline()))
1156 node = LayoutTreeBuilderTraversal::parent(*node);
1158 // Return the bounding box in the root frame's coordinate space.
1159 if (node) {
1160 IntRect pointInRootFrame = node->Node::pixelSnappedBoundingBox();
1161 LocalFrame* frame = node->document().frame();
1162 return frame->view()->contentsToRootFrame(pointInRootFrame);
1164 return WebRect();
1167 WebRect WebViewImpl::widenRectWithinPageBounds(const WebRect& source, int targetMargin, int minimumMargin)
1169 WebSize maxSize;
1170 if (mainFrame())
1171 maxSize = mainFrame()->contentsSize();
1172 IntSize scrollOffset;
1173 if (mainFrame())
1174 scrollOffset = mainFrame()->scrollOffset();
1175 int leftMargin = targetMargin;
1176 int rightMargin = targetMargin;
1178 const int absoluteSourceX = source.x + scrollOffset.width();
1179 if (leftMargin > absoluteSourceX) {
1180 leftMargin = absoluteSourceX;
1181 rightMargin = std::max(leftMargin, minimumMargin);
1184 const int maximumRightMargin = maxSize.width - (source.width + absoluteSourceX);
1185 if (rightMargin > maximumRightMargin) {
1186 rightMargin = maximumRightMargin;
1187 leftMargin = std::min(leftMargin, std::max(rightMargin, minimumMargin));
1190 const int newWidth = source.width + leftMargin + rightMargin;
1191 const int newX = source.x - leftMargin;
1193 ASSERT(newWidth >= 0);
1194 ASSERT(scrollOffset.width() + newX + newWidth <= maxSize.width);
1196 return WebRect(newX, source.y, newWidth, source.height);
1199 float WebViewImpl::maximumLegiblePageScale() const
1201 // Pages should be as legible as on desktop when at dpi scale, so no
1202 // need to zoom in further when automatically determining zoom level
1203 // (after double tap, find in page, etc), though the user should still
1204 // be allowed to manually pinch zoom in further if they desire.
1205 if (page())
1206 return m_maximumLegibleScale * page()->settings().accessibilityFontScaleFactor();
1207 return m_maximumLegibleScale;
1210 void WebViewImpl::computeScaleAndScrollForBlockRect(const WebPoint& hitPointInRootFrame, const WebRect& blockRectInRootFrame, float padding, float defaultScaleWhenAlreadyLegible, float& scale, WebPoint& scroll)
1212 scale = pageScaleFactor();
1213 scroll.x = scroll.y = 0;
1215 WebRect rect = blockRectInRootFrame;
1217 if (!rect.isEmpty()) {
1218 float defaultMargin = doubleTapZoomContentDefaultMargin;
1219 float minimumMargin = doubleTapZoomContentMinimumMargin;
1220 // We want the margins to have the same physical size, which means we
1221 // need to express them in post-scale size. To do that we'd need to know
1222 // the scale we're scaling to, but that depends on the margins. Instead
1223 // we express them as a fraction of the target rectangle: this will be
1224 // correct if we end up fully zooming to it, and won't matter if we
1225 // don't.
1226 rect = widenRectWithinPageBounds(rect,
1227 static_cast<int>(defaultMargin * rect.width / m_size.width),
1228 static_cast<int>(minimumMargin * rect.width / m_size.width));
1229 // Fit block to screen, respecting limits.
1230 scale = static_cast<float>(m_size.width) / rect.width;
1231 scale = std::min(scale, maximumLegiblePageScale());
1232 if (pageScaleFactor() < defaultScaleWhenAlreadyLegible)
1233 scale = std::max(scale, defaultScaleWhenAlreadyLegible);
1234 scale = clampPageScaleFactorToLimits(scale);
1237 // FIXME: If this is being called for auto zoom during find in page,
1238 // then if the user manually zooms in it'd be nice to preserve the
1239 // relative increase in zoom they caused (if they zoom out then it's ok
1240 // to zoom them back in again). This isn't compatible with our current
1241 // double-tap zoom strategy (fitting the containing block to the screen)
1242 // though.
1244 float screenWidth = m_size.width / scale;
1245 float screenHeight = m_size.height / scale;
1247 // Scroll to vertically align the block.
1248 if (rect.height < screenHeight) {
1249 // Vertically center short blocks.
1250 rect.y -= 0.5 * (screenHeight - rect.height);
1251 } else {
1252 // Ensure position we're zooming to (+ padding) isn't off the bottom of
1253 // the screen.
1254 rect.y = std::max<float>(rect.y, hitPointInRootFrame.y + padding - screenHeight);
1255 } // Otherwise top align the block.
1257 // Do the same thing for horizontal alignment.
1258 if (rect.width < screenWidth)
1259 rect.x -= 0.5 * (screenWidth - rect.width);
1260 else
1261 rect.x = std::max<float>(rect.x, hitPointInRootFrame.x + padding - screenWidth);
1262 scroll.x = rect.x;
1263 scroll.y = rect.y;
1265 scale = clampPageScaleFactorToLimits(scale);
1266 scroll = mainFrameImpl()->frameView()->rootFrameToContents(scroll);
1267 scroll = page()->frameHost().visualViewport().clampDocumentOffsetAtScale(scroll, scale);
1270 static Node* findCursorDefiningAncestor(Node* node, LocalFrame* frame)
1272 // Go up the tree to find the node that defines a mouse cursor style
1273 while (node) {
1274 if (node->layoutObject()) {
1275 ECursor cursor = node->layoutObject()->style()->cursor();
1276 if (cursor != CURSOR_AUTO || frame->eventHandler().useHandCursor(node, node->isLink()))
1277 break;
1279 node = LayoutTreeBuilderTraversal::parent(*node);
1282 return node;
1285 static bool showsHandCursor(Node* node, LocalFrame* frame)
1287 if (!node || !node->layoutObject())
1288 return false;
1290 ECursor cursor = node->layoutObject()->style()->cursor();
1291 return cursor == CURSOR_POINTER
1292 || (cursor == CURSOR_AUTO && frame->eventHandler().useHandCursor(node, node->isLink()));
1295 Node* WebViewImpl::bestTapNode(const GestureEventWithHitTestResults& targetedTapEvent)
1297 TRACE_EVENT0("input", "WebViewImpl::bestTapNode");
1299 if (!m_page || !m_page->mainFrame())
1300 return 0;
1302 Node* bestTouchNode = targetedTapEvent.hitTestResult().innerNode();
1303 if (!bestTouchNode)
1304 return nullptr;
1306 // We might hit something like an image map that has no layoutObject on it
1307 // Walk up the tree until we have a node with an attached layoutObject
1308 while (!bestTouchNode->layoutObject()) {
1309 bestTouchNode = LayoutTreeBuilderTraversal::parent(*bestTouchNode);
1310 if (!bestTouchNode)
1311 return nullptr;
1314 // Editable nodes should not be highlighted (e.g., <input>)
1315 if (bestTouchNode->hasEditableStyle())
1316 return nullptr;
1318 Node* cursorDefiningAncestor =
1319 findCursorDefiningAncestor(bestTouchNode, m_page->deprecatedLocalMainFrame());
1320 // We show a highlight on tap only when the current node shows a hand cursor
1321 if (!cursorDefiningAncestor || !showsHandCursor(cursorDefiningAncestor, m_page->deprecatedLocalMainFrame())) {
1322 return 0;
1325 // We should pick the largest enclosing node with hand cursor set. We do this by first jumping
1326 // up to cursorDefiningAncestor (which is already known to have hand cursor set). Then we locate
1327 // the next cursor-defining ancestor up in the the tree and repeat the jumps as long as the node
1328 // has hand cursor set.
1329 do {
1330 bestTouchNode = cursorDefiningAncestor;
1331 cursorDefiningAncestor = findCursorDefiningAncestor(LayoutTreeBuilderTraversal::parent(*bestTouchNode),
1332 m_page->deprecatedLocalMainFrame());
1333 } while (cursorDefiningAncestor && showsHandCursor(cursorDefiningAncestor, m_page->deprecatedLocalMainFrame()));
1335 return bestTouchNode;
1338 void WebViewImpl::enableTapHighlightAtPoint(const GestureEventWithHitTestResults& targetedTapEvent)
1340 Node* touchNode = bestTapNode(targetedTapEvent);
1342 WillBeHeapVector<RawPtrWillBeMember<Node>> highlightNodes;
1343 highlightNodes.append(touchNode);
1345 enableTapHighlights(highlightNodes);
1348 void WebViewImpl::enableTapHighlights(WillBeHeapVector<RawPtrWillBeMember<Node>>& highlightNodes)
1350 if (highlightNodes.isEmpty())
1351 return;
1353 // Always clear any existing highlight when this is invoked, even if we
1354 // don't get a new target to highlight.
1355 m_linkHighlights.clear();
1357 // LinkHighlight reads out layout and compositing state, so we need to make sure that's all up to date.
1358 layout();
1360 for (size_t i = 0; i < highlightNodes.size(); ++i) {
1361 Node* node = highlightNodes[i];
1363 if (!node || !node->layoutObject())
1364 continue;
1366 Color highlightColor = node->layoutObject()->style()->tapHighlightColor();
1367 // Safari documentation for -webkit-tap-highlight-color says if the specified color has 0 alpha,
1368 // then tap highlighting is disabled.
1369 // http://developer.apple.com/library/safari/#documentation/appleapplications/reference/safaricssref/articles/standardcssproperties.html
1370 if (!highlightColor.alpha())
1371 continue;
1373 m_linkHighlights.append(LinkHighlightImpl::create(node, this));
1377 void WebViewImpl::animateDoubleTapZoom(const IntPoint& pointInRootFrame)
1379 if (!mainFrameImpl())
1380 return;
1382 WebRect blockBounds = computeBlockBound(pointInRootFrame, false);
1383 float scale;
1384 WebPoint scroll;
1386 computeScaleAndScrollForBlockRect(pointInRootFrame, blockBounds, touchPointPadding, minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio, scale, scroll);
1388 bool stillAtPreviousDoubleTapScale = (pageScaleFactor() == m_doubleTapZoomPageScaleFactor
1389 && m_doubleTapZoomPageScaleFactor != minimumPageScaleFactor())
1390 || m_doubleTapZoomPending;
1392 bool scaleUnchanged = fabs(pageScaleFactor() - scale) < minScaleDifference;
1393 bool shouldZoomOut = blockBounds.isEmpty() || scaleUnchanged || stillAtPreviousDoubleTapScale;
1395 bool isAnimating;
1397 if (shouldZoomOut) {
1398 scale = minimumPageScaleFactor();
1399 isAnimating = startPageScaleAnimation(mainFrameImpl()->frameView()->rootFrameToContents(pointInRootFrame), true, scale, doubleTapZoomAnimationDurationInSeconds);
1400 } else {
1401 isAnimating = startPageScaleAnimation(scroll, false, scale, doubleTapZoomAnimationDurationInSeconds);
1404 if (isAnimating) {
1405 m_doubleTapZoomPageScaleFactor = scale;
1406 m_doubleTapZoomPending = true;
1410 void WebViewImpl::zoomToFindInPageRect(const WebRect& rectInRootFrame)
1412 if (!mainFrameImpl())
1413 return;
1415 WebRect blockBounds = computeBlockBound(WebPoint(rectInRootFrame.x + rectInRootFrame.width / 2, rectInRootFrame.y + rectInRootFrame.height / 2), true);
1417 if (blockBounds.isEmpty()) {
1418 // Keep current scale (no need to scroll as x,y will normally already
1419 // be visible). FIXME: Revisit this if it isn't always true.
1420 return;
1423 float scale;
1424 WebPoint scroll;
1426 computeScaleAndScrollForBlockRect(WebPoint(rectInRootFrame.x, rectInRootFrame.y), blockBounds, nonUserInitiatedPointPadding, minimumPageScaleFactor(), scale, scroll);
1428 startPageScaleAnimation(scroll, false, scale, findInPageAnimationDurationInSeconds);
1431 bool WebViewImpl::zoomToMultipleTargetsRect(const WebRect& rectInRootFrame)
1433 if (!mainFrameImpl())
1434 return false;
1436 float scale;
1437 WebPoint scroll;
1439 computeScaleAndScrollForBlockRect(WebPoint(rectInRootFrame.x, rectInRootFrame.y), rectInRootFrame, nonUserInitiatedPointPadding, minimumPageScaleFactor(), scale, scroll);
1441 if (scale <= pageScaleFactor())
1442 return false;
1444 startPageScaleAnimation(scroll, false, scale, multipleTargetsZoomAnimationDurationInSeconds);
1445 return true;
1448 void WebViewImpl::hasTouchEventHandlers(bool hasTouchHandlers)
1450 if (m_client)
1451 m_client->hasTouchEventHandlers(hasTouchHandlers);
1454 bool WebViewImpl::hasTouchEventHandlersAt(const WebPoint& point)
1456 // FIXME: Implement this. Note that the point must be divided by pageScaleFactor.
1457 return true;
1460 #if !OS(MACOSX)
1461 // Mac has no way to open a context menu based on a keyboard event.
1462 bool WebViewImpl::sendContextMenuEvent(const WebKeyboardEvent& event)
1464 // The contextMenuController() holds onto the last context menu that was
1465 // popped up on the page until a new one is created. We need to clear
1466 // this menu before propagating the event through the DOM so that we can
1467 // detect if we create a new menu for this event, since we won't create
1468 // a new menu if the DOM swallows the event and the defaultEventHandler does
1469 // not run.
1470 page()->contextMenuController().clearContextMenu();
1472 bool handled;
1474 ContextMenuAllowedScope scope;
1475 Frame* focusedFrame = page()->focusController().focusedOrMainFrame();
1476 if (!focusedFrame->isLocalFrame())
1477 return false;
1478 handled = toLocalFrame(focusedFrame)->eventHandler().sendContextMenuEventForKey(nullptr);
1480 return handled;
1482 #endif
1484 void WebViewImpl::showContextMenuAtPoint(float x, float y, PassRefPtrWillBeRawPtr<ContextMenuProvider> menuProvider)
1486 if (!page()->mainFrame()->isLocalFrame())
1487 return;
1489 ContextMenuAllowedScope scope;
1490 page()->contextMenuController().clearContextMenu();
1491 page()->contextMenuController().showContextMenuAtPoint(page()->deprecatedLocalMainFrame(), x, y, menuProvider);
1495 void WebViewImpl::showContextMenuForElement(WebElement element)
1497 if (!page())
1498 return;
1500 page()->contextMenuController().clearContextMenu();
1502 ContextMenuAllowedScope scope;
1503 if (LocalFrame* focusedFrame = toLocalFrame(page()->focusController().focusedOrMainFrame()))
1504 focusedFrame->eventHandler().sendContextMenuEventForKey(element.unwrap<Element>());
1508 bool WebViewImpl::keyEventDefault(const WebKeyboardEvent& event)
1510 LocalFrame* frame = toLocalFrame(focusedCoreFrame());
1511 if (!frame)
1512 return false;
1514 switch (event.type) {
1515 case WebInputEvent::Char:
1516 if (event.windowsKeyCode == VKEY_SPACE) {
1517 int keyCode = ((event.modifiers & WebInputEvent::ShiftKey) ? VKEY_PRIOR : VKEY_NEXT);
1518 return scrollViewWithKeyboard(keyCode, event.modifiers);
1520 break;
1521 case WebInputEvent::RawKeyDown:
1522 if (event.modifiers == WebInputEvent::ControlKey) {
1523 switch (event.windowsKeyCode) {
1524 #if !OS(MACOSX)
1525 case 'A':
1526 focusedFrame()->executeCommand(WebString::fromUTF8("SelectAll"));
1527 return true;
1528 case VKEY_INSERT:
1529 case 'C':
1530 focusedFrame()->executeCommand(WebString::fromUTF8("Copy"));
1531 return true;
1532 #endif
1533 // Match FF behavior in the sense that Ctrl+home/end are the only Ctrl
1534 // key combinations which affect scrolling. Safari is buggy in the
1535 // sense that it scrolls the page for all Ctrl+scrolling key
1536 // combinations. For e.g. Ctrl+pgup/pgdn/up/down, etc.
1537 case VKEY_HOME:
1538 case VKEY_END:
1539 break;
1540 default:
1541 return false;
1544 if (!event.isSystemKey && !(event.modifiers & WebInputEvent::ShiftKey))
1545 return scrollViewWithKeyboard(event.windowsKeyCode, event.modifiers);
1546 break;
1547 default:
1548 break;
1550 return false;
1553 bool WebViewImpl::scrollViewWithKeyboard(int keyCode, int modifiers)
1555 ScrollDirectionPhysical scrollDirectionPhysical;
1556 ScrollGranularity scrollGranularity;
1557 #if OS(MACOSX)
1558 // Control-Up/Down should be PageUp/Down on Mac.
1559 if (modifiers & WebMouseEvent::ControlKey) {
1560 if (keyCode == VKEY_UP)
1561 keyCode = VKEY_PRIOR;
1562 else if (keyCode == VKEY_DOWN)
1563 keyCode = VKEY_NEXT;
1565 #endif
1566 if (!mapKeyCodeForScroll(keyCode, &scrollDirectionPhysical, &scrollGranularity))
1567 return false;
1569 if (LocalFrame* frame = toLocalFrame(focusedCoreFrame()))
1570 return frame->eventHandler().bubblingScroll(toScrollDirection(scrollDirectionPhysical), scrollGranularity);
1571 return false;
1574 bool WebViewImpl::mapKeyCodeForScroll(
1575 int keyCode,
1576 ScrollDirectionPhysical* scrollDirection,
1577 ScrollGranularity* scrollGranularity)
1579 switch (keyCode) {
1580 case VKEY_LEFT:
1581 *scrollDirection = ScrollLeft;
1582 *scrollGranularity = ScrollByLine;
1583 break;
1584 case VKEY_RIGHT:
1585 *scrollDirection = ScrollRight;
1586 *scrollGranularity = ScrollByLine;
1587 break;
1588 case VKEY_UP:
1589 *scrollDirection = ScrollUp;
1590 *scrollGranularity = ScrollByLine;
1591 break;
1592 case VKEY_DOWN:
1593 *scrollDirection = ScrollDown;
1594 *scrollGranularity = ScrollByLine;
1595 break;
1596 case VKEY_HOME:
1597 *scrollDirection = ScrollUp;
1598 *scrollGranularity = ScrollByDocument;
1599 break;
1600 case VKEY_END:
1601 *scrollDirection = ScrollDown;
1602 *scrollGranularity = ScrollByDocument;
1603 break;
1604 case VKEY_PRIOR: // page up
1605 *scrollDirection = ScrollUp;
1606 *scrollGranularity = ScrollByPage;
1607 break;
1608 case VKEY_NEXT: // page down
1609 *scrollDirection = ScrollDown;
1610 *scrollGranularity = ScrollByPage;
1611 break;
1612 default:
1613 return false;
1616 return true;
1619 PagePopup* WebViewImpl::openPagePopup(PagePopupClient* client)
1621 ASSERT(client);
1622 if (hasOpenedPopup())
1623 hidePopups();
1624 ASSERT(!m_pagePopup);
1626 WebWidget* popupWidget = m_client->createPopupMenu(WebPopupTypePage);
1627 ASSERT(popupWidget);
1628 m_pagePopup = toWebPagePopupImpl(popupWidget);
1629 if (!m_pagePopup->initialize(this, client)) {
1630 m_pagePopup->closePopup();
1631 m_pagePopup = nullptr;
1633 enablePopupMouseWheelEventListener();
1634 return m_pagePopup.get();
1637 void WebViewImpl::closePagePopup(PagePopup* popup)
1639 ASSERT(popup);
1640 WebPagePopupImpl* popupImpl = toWebPagePopupImpl(popup);
1641 ASSERT(m_pagePopup.get() == popupImpl);
1642 if (m_pagePopup.get() != popupImpl)
1643 return;
1644 m_pagePopup->closePopup();
1645 m_pagePopup = nullptr;
1646 disablePopupMouseWheelEventListener();
1649 void WebViewImpl::cancelPagePopup()
1651 if (m_pagePopup)
1652 m_pagePopup->cancel();
1655 void WebViewImpl::enablePopupMouseWheelEventListener()
1657 ASSERT(!m_popupMouseWheelEventListener);
1658 ASSERT(mainFrameImpl()->frame()->document());
1659 // We register an empty event listener, EmptyEventListener, so that mouse
1660 // wheel events get sent to the WebView.
1661 m_popupMouseWheelEventListener = EmptyEventListener::create();
1662 mainFrameImpl()->frame()->document()->addEventListener(EventTypeNames::mousewheel, m_popupMouseWheelEventListener, false);
1665 void WebViewImpl::disablePopupMouseWheelEventListener()
1667 ASSERT(m_popupMouseWheelEventListener);
1668 ASSERT(mainFrameImpl()->frame()->document());
1669 // Document may have already removed the event listener, for instance, due
1670 // to a navigation, but remove it anyway.
1671 mainFrameImpl()->frame()->document()->removeEventListener(EventTypeNames::mousewheel, m_popupMouseWheelEventListener.release(), false);
1674 LocalDOMWindow* WebViewImpl::pagePopupWindow() const
1676 return m_pagePopup ? m_pagePopup->window() : nullptr;
1679 Frame* WebViewImpl::focusedCoreFrame() const
1681 return m_page ? m_page->focusController().focusedOrMainFrame() : 0;
1684 WebViewImpl* WebViewImpl::fromPage(Page* page)
1686 if (!page)
1687 return 0;
1688 return static_cast<WebViewImpl*>(page->chromeClient().webView());
1691 // WebWidget ------------------------------------------------------------------
1693 void WebViewImpl::close()
1695 WebDevToolsAgentImpl::webViewImplClosed(this);
1696 ASSERT(allInstances().contains(this));
1697 allInstances().remove(this);
1699 if (m_page) {
1700 // Initiate shutdown for the entire frameset. This will cause a lot of
1701 // notifications to be sent.
1702 m_page->willBeDestroyed();
1703 m_page.clear();
1706 // Reset the delegate to prevent notifications being sent as we're being
1707 // deleted.
1708 m_client = nullptr;
1710 deref(); // Balances ref() acquired in WebView::create
1713 void WebViewImpl::willStartLiveResize()
1715 if (mainFrameImpl() && mainFrameImpl()->frameView())
1716 mainFrameImpl()->frameView()->willStartLiveResize();
1719 WebSize WebViewImpl::size()
1721 return m_size;
1724 void WebViewImpl::resizeVisualViewport(const WebSize& newSize)
1726 page()->frameHost().visualViewport().setSize(newSize);
1727 page()->frameHost().visualViewport().clampToBoundaries();
1730 void WebViewImpl::resizePinchViewport(const WebSize& newSize)
1732 resizeVisualViewport(newSize);
1735 void WebViewImpl::performResize()
1737 pageScaleConstraintsSet().didChangeViewSize(m_size);
1739 updatePageDefinedViewportConstraints(mainFrameImpl()->frame()->document()->viewportDescription());
1740 updateMainFrameLayoutSize();
1742 page()->frameHost().visualViewport().setSize(m_size);
1744 if (mainFrameImpl()->frameView()) {
1745 if (!mainFrameImpl()->frameView()->needsLayout())
1746 postLayoutResize(mainFrameImpl());
1749 // When device emulation is enabled, device size values may change - they are
1750 // usually set equal to the view size. These values are not considered viewport-dependent
1751 // (see MediaQueryExp::isViewportDependent), since they are only viewport-dependent in emulation mode,
1752 // and thus will not be invalidated in |FrameView::performPreLayoutTasks|.
1753 // Therefore we should force explicit media queries invalidation here.
1754 if (m_devToolsEmulator->deviceEmulationEnabled()) {
1755 if (Document* document = mainFrameImpl()->frame()->document())
1756 document->mediaQueryAffectingValueChanged();
1760 void WebViewImpl::setTopControlsHeight(float height, bool topControlsShrinkLayoutSize)
1762 topControls().setHeight(height, topControlsShrinkLayoutSize);
1765 void WebViewImpl::updateTopControlsState(WebTopControlsState constraint, WebTopControlsState current, bool animate)
1767 topControls().updateConstraints(constraint);
1768 if (m_layerTreeView)
1769 m_layerTreeView->updateTopControlsState(constraint, current, animate);
1772 void WebViewImpl::didUpdateTopControls()
1774 if (m_layerTreeView) {
1775 m_layerTreeView->setTopControlsShownRatio(topControls().shownRatio());
1776 m_layerTreeView->setTopControlsHeight(topControls().height(), topControls().shrinkViewport());
1779 WebLocalFrameImpl* mainFrame = mainFrameImpl();
1780 if (!mainFrame)
1781 return;
1783 FrameView* view = mainFrame->frameView();
1784 if (!view)
1785 return;
1787 VisualViewport& visualViewport = page()->frameHost().visualViewport();
1788 float topControlsViewportAdjustment = topControls().layoutHeight() - topControls().contentOffset();
1789 visualViewport.setTopControlsAdjustment(topControlsViewportAdjustment);
1791 // Shrink the FrameView by the amount that will maintain the aspect-ratio with the VisualViewport.
1792 view->setTopControlsViewportAdjustment(topControlsViewportAdjustment / minimumPageScaleFactor());
1795 TopControls& WebViewImpl::topControls()
1797 return page()->frameHost().topControls();
1800 void WebViewImpl::resizeViewWhileAnchored(FrameView* view)
1802 // FIXME: TextAutosizer does not yet support out-of-process frames.
1803 if (mainFrameImpl() && mainFrameImpl()->frame()->isLocalFrame()) {
1804 // Avoids unnecessary invalidations while various bits of state in TextAutosizer are updated.
1805 TextAutosizer::DeferUpdatePageInfo deferUpdatePageInfo(page());
1806 performResize();
1807 } else {
1808 performResize();
1811 m_fullscreenController->updateSize();
1813 // Relayout immediately to recalculate the minimum scale limit for rotation anchoring.
1814 if (view->needsLayout())
1815 view->layout();
1818 void WebViewImpl::resize(const WebSize& newSize)
1820 if (m_shouldAutoResize || m_size == newSize)
1821 return;
1823 WebLocalFrameImpl* mainFrame = mainFrameImpl();
1824 if (!mainFrame)
1825 return;
1827 FrameView* view = mainFrame->frameView();
1828 if (!view)
1829 return;
1831 VisualViewport& visualViewport = page()->frameHost().visualViewport();
1833 bool isRotation = settings()->mainFrameResizesAreOrientationChanges()
1834 && m_size.width && contentsSize().width() && newSize.width != m_size.width && !m_fullscreenController->isFullscreen();
1835 m_size = newSize;
1837 FloatSize viewportAnchorCoords(viewportAnchorCoordX, viewportAnchorCoordY);
1838 if (isRotation) {
1839 RotationViewportAnchor anchor(*view, visualViewport, viewportAnchorCoords, pageScaleConstraintsSet());
1840 resizeViewWhileAnchored(view);
1841 } else {
1842 ResizeViewportAnchor anchor(*view, visualViewport);
1843 resizeViewWhileAnchored(view);
1845 sendResizeEventAndRepaint();
1848 void WebViewImpl::willEndLiveResize()
1850 if (mainFrameImpl() && mainFrameImpl()->frameView())
1851 mainFrameImpl()->frameView()->willEndLiveResize();
1854 void WebViewImpl::didEnterFullScreen()
1856 m_fullscreenController->didEnterFullScreen();
1859 void WebViewImpl::didExitFullScreen()
1861 m_fullscreenController->didExitFullScreen();
1864 void WebViewImpl::beginFrame(const WebBeginFrameArgs& frameTime)
1866 TRACE_EVENT0("blink", "WebViewImpl::beginFrame");
1868 WebBeginFrameArgs validFrameTime(frameTime);
1869 if (!validFrameTime.lastFrameTimeMonotonic)
1870 validFrameTime.lastFrameTimeMonotonic = monotonicallyIncreasingTime();
1872 // Create synthetic wheel events as necessary for fling.
1873 if (m_gestureAnimation) {
1874 if (m_gestureAnimation->animate(validFrameTime.lastFrameTimeMonotonic))
1875 scheduleAnimation();
1876 else {
1877 endActiveFlingAnimation();
1879 PlatformGestureEvent endScrollEvent(PlatformEvent::GestureScrollEnd,
1880 m_positionOnFlingStart, m_globalPositionOnFlingStart,
1881 IntSize(), 0, false, false, false, false);
1882 endScrollEvent.setScrollGestureData(0, 0, 0, 0, true, false, -1 /* null plugin id */);
1884 mainFrameImpl()->frame()->eventHandler().handleGestureScrollEnd(endScrollEvent);
1888 if (!m_page)
1889 return;
1891 // FIXME: This should probably be using the local root?
1892 if (m_page->mainFrame()->isLocalFrame())
1893 PageWidgetDelegate::animate(*m_page, validFrameTime.lastFrameTimeMonotonic, *m_page->deprecatedLocalMainFrame());
1896 void WebViewImpl::layout()
1898 TRACE_EVENT0("blink", "WebViewImpl::layout");
1899 if (!mainFrameImpl())
1900 return;
1902 PageWidgetDelegate::layout(*m_page, *mainFrameImpl()->frame());
1903 updateLayerTreeBackgroundColor();
1904 if (InspectorOverlayImpl* overlay = inspectorOverlay())
1905 overlay->layout();
1906 for (size_t i = 0; i < m_linkHighlights.size(); ++i)
1907 m_linkHighlights[i]->updateGeometry();
1909 if (FrameView* view = mainFrameImpl()->frameView()) {
1910 LocalFrame* frame = mainFrameImpl()->frame();
1912 if (m_shouldDispatchFirstVisuallyNonEmptyLayout && view->isVisuallyNonEmpty()) {
1913 m_shouldDispatchFirstVisuallyNonEmptyLayout = false;
1914 // TODO(esprehn): Move users of this callback to something
1915 // better, the heuristic for "visually non-empty" is bad.
1916 client()->didFirstVisuallyNonEmptyLayout();
1919 if (m_shouldDispatchFirstLayoutAfterFinishedParsing && frame->document()->hasFinishedParsing()) {
1920 m_shouldDispatchFirstLayoutAfterFinishedParsing = false;
1921 client()->didFirstLayoutAfterFinishedParsing();
1926 void WebViewImpl::paint(WebCanvas* canvas, const WebRect& rect)
1928 // This should only be used when compositing is not being used for this
1929 // WebView, and it is painting into the recording of its parent.
1930 ASSERT(!isAcceleratedCompositingActive());
1932 double paintStart = currentTime();
1933 PageWidgetDelegate::paint(*m_page, canvas, rect, *m_page->deprecatedLocalMainFrame());
1934 double paintEnd = currentTime();
1935 double pixelsPerSec = (rect.width * rect.height) / (paintEnd - paintStart);
1936 Platform::current()->histogramCustomCounts("Renderer4.SoftwarePaintDurationMS", (paintEnd - paintStart) * 1000, 0, 120, 30);
1937 Platform::current()->histogramCustomCounts("Renderer4.SoftwarePaintMegapixPerSecond", pixelsPerSec / 1000000, 10, 210, 30);
1940 #if OS(ANDROID)
1941 void WebViewImpl::paintCompositedDeprecated(WebCanvas* canvas, const WebRect& rect)
1943 // Note: This method exists on OS(ANDROID) and will hopefully be
1944 // removed once the link disambiguation feature renders using
1945 // the compositor.
1946 ASSERT(isAcceleratedCompositingActive());
1948 PageWidgetDelegate::paintIgnoringCompositing(*m_page, canvas, rect, *m_page->deprecatedLocalMainFrame());
1950 #endif
1952 void WebViewImpl::layoutAndPaintAsync(WebLayoutAndPaintAsyncCallback* callback)
1954 m_layerTreeView->layoutAndPaintAsync(callback);
1957 void WebViewImpl::compositeAndReadbackAsync(WebCompositeAndReadbackAsyncCallback* callback)
1959 m_layerTreeView->compositeAndReadbackAsync(callback);
1962 void WebViewImpl::themeChanged()
1964 if (!page())
1965 return;
1966 if (!page()->mainFrame()->isLocalFrame())
1967 return;
1968 FrameView* view = page()->deprecatedLocalMainFrame()->view();
1970 WebRect damagedRect(0, 0, m_size.width, m_size.height);
1971 view->invalidateRect(damagedRect);
1974 void WebViewImpl::enterFullScreenForElement(Element* element)
1976 m_fullscreenController->enterFullScreenForElement(element);
1979 void WebViewImpl::exitFullScreenForElement(Element* element)
1981 m_fullscreenController->exitFullScreenForElement(element);
1984 void WebViewImpl::clearCompositedSelection()
1986 if (m_layerTreeView)
1987 m_layerTreeView->clearSelection();
1990 void WebViewImpl::updateCompositedSelection(const WebSelection& selection)
1992 if (m_layerTreeView)
1993 m_layerTreeView->registerSelection(selection);
1996 bool WebViewImpl::hasHorizontalScrollbar()
1998 return mainFrameImpl()->frameView()->horizontalScrollbar();
2001 bool WebViewImpl::hasVerticalScrollbar()
2003 return mainFrameImpl()->frameView()->verticalScrollbar();
2006 const WebInputEvent* WebViewImpl::m_currentInputEvent = nullptr;
2008 // FIXME: autogenerate this kind of code, and use it throughout Blink rather than
2009 // the one-offs for subsets of these values.
2010 static String inputTypeToName(WebInputEvent::Type type)
2012 switch (type) {
2013 case WebInputEvent::MouseDown:
2014 return EventTypeNames::mousedown;
2015 case WebInputEvent::MouseUp:
2016 return EventTypeNames::mouseup;
2017 case WebInputEvent::MouseMove:
2018 return EventTypeNames::mousemove;
2019 case WebInputEvent::MouseEnter:
2020 return EventTypeNames::mouseenter;
2021 case WebInputEvent::MouseLeave:
2022 return EventTypeNames::mouseleave;
2023 case WebInputEvent::ContextMenu:
2024 return EventTypeNames::contextmenu;
2025 case WebInputEvent::MouseWheel:
2026 return EventTypeNames::mousewheel;
2027 case WebInputEvent::KeyDown:
2028 return EventTypeNames::keydown;
2029 case WebInputEvent::KeyUp:
2030 return EventTypeNames::keyup;
2031 case WebInputEvent::GestureScrollBegin:
2032 return EventTypeNames::gesturescrollstart;
2033 case WebInputEvent::GestureScrollEnd:
2034 return EventTypeNames::gesturescrollend;
2035 case WebInputEvent::GestureScrollUpdate:
2036 return EventTypeNames::gesturescrollupdate;
2037 case WebInputEvent::GestureTapDown:
2038 return EventTypeNames::gesturetapdown;
2039 case WebInputEvent::GestureShowPress:
2040 return EventTypeNames::gestureshowpress;
2041 case WebInputEvent::GestureTap:
2042 return EventTypeNames::gesturetap;
2043 case WebInputEvent::GestureTapUnconfirmed:
2044 return EventTypeNames::gesturetapunconfirmed;
2045 case WebInputEvent::TouchStart:
2046 return EventTypeNames::touchstart;
2047 case WebInputEvent::TouchMove:
2048 return EventTypeNames::touchmove;
2049 case WebInputEvent::TouchEnd:
2050 return EventTypeNames::touchend;
2051 case WebInputEvent::TouchCancel:
2052 return EventTypeNames::touchcancel;
2053 default:
2054 return String("unknown");
2058 bool WebViewImpl::handleInputEvent(const WebInputEvent& inputEvent)
2060 // TODO(dcheng): The fact that this is getting called when there is no local
2061 // main frame is problematic and probably indicates a bug in the input event
2062 // routing code.
2063 if (!mainFrameImpl())
2064 return false;
2066 WebAutofillClient* autofillClient = mainFrameImpl()->autofillClient();
2067 UserGestureNotifier notifier(autofillClient, &m_userGestureObserved);
2068 // On the first input event since page load, |notifier| instructs the
2069 // autofill client to unblock values of password input fields of any forms
2070 // on the page. There is a single input event, GestureTap, which can both
2071 // be the first event after page load, and cause a form submission. In that
2072 // case, the form submission happens before the autofill client is told
2073 // to unblock the password values, and so the password values are not
2074 // submitted. To avoid that, GestureTap is handled explicitly:
2075 if (inputEvent.type == WebInputEvent::GestureTap && autofillClient) {
2076 m_userGestureObserved = true;
2077 autofillClient->firstUserGestureObserved();
2080 TRACE_EVENT1("input", "WebViewImpl::handleInputEvent", "type", inputTypeToName(inputEvent.type).ascii());
2081 // If we've started a drag and drop operation, ignore input events until
2082 // we're done.
2083 if (m_doingDragAndDrop)
2084 return true;
2086 if (m_devToolsEmulator->handleInputEvent(inputEvent))
2087 return true;
2089 if (InspectorOverlayImpl* overlay = inspectorOverlay()) {
2090 if (overlay->handleInputEvent(inputEvent))
2091 return true;
2094 // Report the event to be NOT processed by WebKit, so that the browser can handle it appropriately.
2095 if (m_ignoreInputEvents)
2096 return false;
2098 TemporaryChange<const WebInputEvent*> currentEventChange(m_currentInputEvent, &inputEvent);
2099 UIEventWithKeyState::clearNewTabModifierSetFromIsolatedWorld();
2101 if (isPointerLocked() && WebInputEvent::isMouseEventType(inputEvent.type)) {
2102 pointerLockMouseEvent(inputEvent);
2103 return true;
2106 if (m_mouseCaptureNode && WebInputEvent::isMouseEventType(inputEvent.type)) {
2107 TRACE_EVENT1("input", "captured mouse event", "type", inputEvent.type);
2108 // Save m_mouseCaptureNode since mouseCaptureLost() will clear it.
2109 RefPtrWillBeRawPtr<Node> node = m_mouseCaptureNode;
2111 // Not all platforms call mouseCaptureLost() directly.
2112 if (inputEvent.type == WebInputEvent::MouseUp)
2113 mouseCaptureLost();
2115 OwnPtr<UserGestureIndicator> gestureIndicator;
2117 AtomicString eventType;
2118 switch (inputEvent.type) {
2119 case WebInputEvent::MouseMove:
2120 eventType = EventTypeNames::mousemove;
2121 break;
2122 case WebInputEvent::MouseLeave:
2123 eventType = EventTypeNames::mouseout;
2124 break;
2125 case WebInputEvent::MouseDown:
2126 eventType = EventTypeNames::mousedown;
2127 gestureIndicator = adoptPtr(new UserGestureIndicator(DefinitelyProcessingNewUserGesture));
2128 m_mouseCaptureGestureToken = gestureIndicator->currentToken();
2129 break;
2130 case WebInputEvent::MouseUp:
2131 eventType = EventTypeNames::mouseup;
2132 gestureIndicator = adoptPtr(new UserGestureIndicator(m_mouseCaptureGestureToken.release()));
2133 break;
2134 default:
2135 ASSERT_NOT_REACHED();
2138 node->dispatchMouseEvent(
2139 PlatformMouseEventBuilder(mainFrameImpl()->frameView(), static_cast<const WebMouseEvent&>(inputEvent)),
2140 eventType, static_cast<const WebMouseEvent&>(inputEvent).clickCount);
2141 return true;
2144 // FIXME: This should take in the intended frame, not the local frame root.
2145 if (PageWidgetDelegate::handleInputEvent(*this, inputEvent, mainFrameImpl()->frame()))
2146 return true;
2148 // Unhandled touchpad gesture pinch events synthesize mouse wheel events.
2149 if (inputEvent.type == WebInputEvent::GesturePinchUpdate) {
2150 const WebGestureEvent& pinchEvent = static_cast<const WebGestureEvent&>(inputEvent);
2152 // First, synthesize a Windows-like wheel event to send to any handlers that may exist.
2153 if (handleSyntheticWheelFromTouchpadPinchEvent(pinchEvent))
2154 return true;
2156 if (pinchEvent.data.pinchUpdate.zoomDisabled)
2157 return false;
2159 if (page()->frameHost().visualViewport().magnifyScaleAroundAnchor(pinchEvent.data.pinchUpdate.scale, FloatPoint(pinchEvent.x, pinchEvent.y)))
2160 return true;
2163 return false;
2166 void WebViewImpl::setCursorVisibilityState(bool isVisible)
2168 if (m_page)
2169 m_page->setIsCursorVisible(isVisible);
2172 void WebViewImpl::mouseCaptureLost()
2174 TRACE_EVENT_ASYNC_END0("input", "capturing mouse", this);
2175 m_mouseCaptureNode = nullptr;
2178 void WebViewImpl::setFocus(bool enable)
2180 m_page->focusController().setFocused(enable);
2181 if (enable) {
2182 m_page->focusController().setActive(true);
2183 RefPtrWillBeRawPtr<Frame> focusedFrame = m_page->focusController().focusedFrame();
2184 if (focusedFrame && focusedFrame->isLocalFrame()) {
2185 LocalFrame* localFrame = toLocalFrame(focusedFrame.get());
2186 Element* element = localFrame->document()->focusedElement();
2187 if (element && localFrame->selection().selection().isNone()) {
2188 // If the selection was cleared while the WebView was not
2189 // focused, then the focus element shows with a focus ring but
2190 // no caret and does respond to keyboard inputs.
2191 if (element->isTextFormControl()) {
2192 element->updateFocusAppearance(true);
2193 } else if (element->isContentEditable()) {
2194 // updateFocusAppearance() selects all the text of
2195 // contentseditable DIVs. So we set the selection explicitly
2196 // instead. Note that this has the side effect of moving the
2197 // caret back to the beginning of the text.
2198 Position position(element, 0);
2199 localFrame->selection().setSelection(VisibleSelection(position, SEL_DEFAULT_AFFINITY));
2203 m_imeAcceptEvents = true;
2204 } else {
2205 hidePopups();
2207 // Clear focus on the currently focused frame if any.
2208 if (!m_page)
2209 return;
2211 LocalFrame* frame = m_page->mainFrame() && m_page->mainFrame()->isLocalFrame()
2212 ? m_page->deprecatedLocalMainFrame() : 0;
2213 if (!frame)
2214 return;
2216 RefPtrWillBeRawPtr<Frame> focusedFrame = m_page->focusController().focusedFrame();
2217 if (focusedFrame && focusedFrame->isLocalFrame()) {
2218 // Finish an ongoing composition to delete the composition node.
2219 if (toLocalFrame(focusedFrame.get())->inputMethodController().hasComposition()) {
2220 WebAutofillClient* autofillClient = WebLocalFrameImpl::fromFrame(toLocalFrame(focusedFrame.get()))->autofillClient();
2222 if (autofillClient)
2223 autofillClient->setIgnoreTextChanges(true);
2225 toLocalFrame(focusedFrame.get())->inputMethodController().confirmComposition();
2227 if (autofillClient)
2228 autofillClient->setIgnoreTextChanges(false);
2230 m_imeAcceptEvents = false;
2235 bool WebViewImpl::setComposition(
2236 const WebString& text,
2237 const WebVector<WebCompositionUnderline>& underlines,
2238 int selectionStart,
2239 int selectionEnd)
2241 LocalFrame* focused = toLocalFrame(focusedCoreFrame());
2242 if (!focused || !m_imeAcceptEvents)
2243 return false;
2245 if (WebPlugin* plugin = focusedPluginIfInputMethodSupported(focused))
2246 return plugin->setComposition(text, underlines, selectionStart, selectionEnd);
2248 // The input focus has been moved to another WebWidget object.
2249 // We should use this |editor| object only to complete the ongoing
2250 // composition.
2251 InputMethodController& inputMethodController = focused->inputMethodController();
2252 if (!focused->editor().canEdit() && !inputMethodController.hasComposition())
2253 return false;
2255 // We should verify the parent node of this IME composition node are
2256 // editable because JavaScript may delete a parent node of the composition
2257 // node. In this case, WebKit crashes while deleting texts from the parent
2258 // node, which doesn't exist any longer.
2259 const EphemeralRange range = inputMethodController.compositionEphemeralRange();
2260 if (range.isNotNull()) {
2261 Node* node = range.startPosition().computeContainerNode();
2262 if (!node || !node->isContentEditable())
2263 return false;
2266 // A keypress event is canceled. If an ongoing composition exists, then the
2267 // keydown event should have arisen from a handled key (e.g., backspace).
2268 // In this case we ignore the cancellation and continue; otherwise (no
2269 // ongoing composition) we exit and signal success only for attempts to
2270 // clear the composition.
2271 if (m_suppressNextKeypressEvent && !inputMethodController.hasComposition())
2272 return text.isEmpty();
2274 UserGestureIndicator gestureIndicator(DefinitelyProcessingNewUserGesture);
2276 // When the range of composition underlines overlap with the range between
2277 // selectionStart and selectionEnd, WebKit somehow won't paint the selection
2278 // at all (see InlineTextBox::paint() function in InlineTextBox.cpp).
2279 // But the selection range actually takes effect.
2280 inputMethodController.setComposition(String(text),
2281 CompositionUnderlineVectorBuilder(underlines),
2282 selectionStart, selectionEnd);
2284 return text.isEmpty() || inputMethodController.hasComposition();
2287 bool WebViewImpl::confirmComposition()
2289 return confirmComposition(DoNotKeepSelection);
2292 bool WebViewImpl::confirmComposition(ConfirmCompositionBehavior selectionBehavior)
2294 return confirmComposition(WebString(), selectionBehavior);
2297 bool WebViewImpl::confirmComposition(const WebString& text)
2299 return confirmComposition(text, DoNotKeepSelection);
2302 bool WebViewImpl::confirmComposition(const WebString& text, ConfirmCompositionBehavior selectionBehavior)
2304 LocalFrame* focused = toLocalFrame(focusedCoreFrame());
2305 if (!focused || !m_imeAcceptEvents)
2306 return false;
2308 if (WebPlugin* plugin = focusedPluginIfInputMethodSupported(focused))
2309 return plugin->confirmComposition(text, selectionBehavior);
2311 return focused->inputMethodController().confirmCompositionOrInsertText(text, selectionBehavior == KeepSelection ? InputMethodController::KeepSelection : InputMethodController::DoNotKeepSelection);
2314 bool WebViewImpl::compositionRange(size_t* location, size_t* length)
2316 // FIXME: Long term, the focused frame should be a local frame. For now,
2317 // return early to avoid crashes.
2318 Frame* frame = focusedCoreFrame();
2319 if (!frame || frame->isRemoteFrame())
2320 return false;
2322 LocalFrame* focused = toLocalFrame(frame);
2323 if (!focused || !m_imeAcceptEvents)
2324 return false;
2326 const EphemeralRange range = focused->inputMethodController().compositionEphemeralRange();
2327 if (range.isNull())
2328 return false;
2330 Element* editable = focused->selection().rootEditableElementOrDocumentElement();
2331 ASSERT(editable);
2332 PlainTextRange plainTextRange(PlainTextRange::create(*editable, range));
2333 if (plainTextRange.isNull())
2334 return false;
2335 *location = plainTextRange.start();
2336 *length = plainTextRange.length();
2337 return true;
2340 WebTextInputInfo WebViewImpl::textInputInfo()
2342 WebTextInputInfo info;
2344 Frame* focusedFrame = focusedCoreFrame();
2345 if (!focusedFrame->isLocalFrame())
2346 return info;
2348 LocalFrame* focused = toLocalFrame(focusedFrame);
2349 if (!focused)
2350 return info;
2352 FrameSelection& selection = focused->selection();
2353 Element* element = selection.selection().rootEditableElement();
2354 if (!element)
2355 return info;
2357 info.inputMode = inputModeOfFocusedElement();
2359 info.type = textInputType();
2360 info.flags = textInputFlags();
2361 if (info.type == WebTextInputTypeNone)
2362 return info;
2364 if (!focused->editor().canEdit())
2365 return info;
2367 // Emits an object replacement character for each replaced element so that
2368 // it is exposed to IME and thus could be deleted by IME on android.
2369 info.value = plainText(EphemeralRange::rangeOfContents(*element), TextIteratorEmitsObjectReplacementCharacter);
2371 if (info.value.isEmpty())
2372 return info;
2374 EphemeralRange firstRange = firstEphemeralRangeOf(selection.selection());
2375 if (firstRange.isNotNull()) {
2376 PlainTextRange plainTextRange(PlainTextRange::create(*element, firstRange));
2377 if (plainTextRange.isNotNull()) {
2378 info.selectionStart = plainTextRange.start();
2379 info.selectionEnd = plainTextRange.end();
2383 EphemeralRange range = focused->inputMethodController().compositionEphemeralRange();
2384 if (range.isNotNull()) {
2385 PlainTextRange plainTextRange(PlainTextRange::create(*element, range));
2386 if (plainTextRange.isNotNull()) {
2387 info.compositionStart = plainTextRange.start();
2388 info.compositionEnd = plainTextRange.end();
2392 return info;
2395 WebTextInputType WebViewImpl::textInputType()
2397 Element* element = focusedElement();
2398 if (!element)
2399 return WebTextInputTypeNone;
2401 if (isHTMLInputElement(*element)) {
2402 HTMLInputElement& input = toHTMLInputElement(*element);
2403 const AtomicString& type = input.type();
2405 if (input.isDisabledOrReadOnly())
2406 return WebTextInputTypeNone;
2408 if (type == InputTypeNames::password)
2409 return WebTextInputTypePassword;
2410 if (type == InputTypeNames::search)
2411 return WebTextInputTypeSearch;
2412 if (type == InputTypeNames::email)
2413 return WebTextInputTypeEmail;
2414 if (type == InputTypeNames::number)
2415 return WebTextInputTypeNumber;
2416 if (type == InputTypeNames::tel)
2417 return WebTextInputTypeTelephone;
2418 if (type == InputTypeNames::url)
2419 return WebTextInputTypeURL;
2420 if (type == InputTypeNames::date)
2421 return WebTextInputTypeDate;
2422 if (type == InputTypeNames::datetime_local)
2423 return WebTextInputTypeDateTimeLocal;
2424 if (type == InputTypeNames::month)
2425 return WebTextInputTypeMonth;
2426 if (type == InputTypeNames::time)
2427 return WebTextInputTypeTime;
2428 if (type == InputTypeNames::week)
2429 return WebTextInputTypeWeek;
2430 if (type == InputTypeNames::text)
2431 return WebTextInputTypeText;
2433 return WebTextInputTypeNone;
2436 if (isHTMLTextAreaElement(*element)) {
2437 if (toHTMLTextAreaElement(*element).isDisabledOrReadOnly())
2438 return WebTextInputTypeNone;
2439 return WebTextInputTypeTextArea;
2442 #if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
2443 if (element->isHTMLElement()) {
2444 if (toHTMLElement(element)->isDateTimeFieldElement())
2445 return WebTextInputTypeDateTimeField;
2447 #endif
2449 if (element->isContentEditable(Node::UserSelectAllIsAlwaysNonEditable))
2450 return WebTextInputTypeContentEditable;
2452 return WebTextInputTypeNone;
2455 int WebViewImpl::textInputFlags()
2457 Element* element = focusedElement();
2458 if (!element)
2459 return WebTextInputFlagNone;
2461 DEFINE_STATIC_LOCAL(AtomicString, autocompleteString, ("autocomplete", AtomicString::ConstructFromLiteral));
2462 DEFINE_STATIC_LOCAL(AtomicString, autocorrectString, ("autocorrect", AtomicString::ConstructFromLiteral));
2463 int flags = 0;
2465 const AtomicString& autocomplete = element->getAttribute(autocompleteString);
2466 if (autocomplete == "on")
2467 flags |= WebTextInputFlagAutocompleteOn;
2468 else if (autocomplete == "off")
2469 flags |= WebTextInputFlagAutocompleteOff;
2471 const AtomicString& autocorrect = element->getAttribute(autocorrectString);
2472 if (autocorrect == "on")
2473 flags |= WebTextInputFlagAutocorrectOn;
2474 else if (autocorrect == "off")
2475 flags |= WebTextInputFlagAutocorrectOff;
2477 SpellcheckAttributeState spellcheck = element->spellcheckAttributeState();
2478 if (spellcheck == SpellcheckAttributeTrue)
2479 flags |= WebTextInputFlagSpellcheckOn;
2480 else if (spellcheck == SpellcheckAttributeFalse)
2481 flags |= WebTextInputFlagSpellcheckOff;
2483 if (isHTMLTextFormControlElement(element)) {
2484 HTMLTextFormControlElement* formElement = static_cast<HTMLTextFormControlElement*>(element);
2485 if (formElement->supportsAutocapitalize()) {
2486 DEFINE_STATIC_LOCAL(const AtomicString, none, ("none", AtomicString::ConstructFromLiteral));
2487 DEFINE_STATIC_LOCAL(const AtomicString, characters, ("characters", AtomicString::ConstructFromLiteral));
2488 DEFINE_STATIC_LOCAL(const AtomicString, words, ("words", AtomicString::ConstructFromLiteral));
2489 DEFINE_STATIC_LOCAL(const AtomicString, sentences, ("sentences", AtomicString::ConstructFromLiteral));
2491 const AtomicString& autocapitalize = formElement->autocapitalize();
2492 if (autocapitalize == none)
2493 flags |= WebTextInputFlagAutocapitalizeNone;
2494 else if (autocapitalize == characters)
2495 flags |= WebTextInputFlagAutocapitalizeCharacters;
2496 else if (autocapitalize == words)
2497 flags |= WebTextInputFlagAutocapitalizeWords;
2498 else if (autocapitalize == sentences)
2499 flags |= WebTextInputFlagAutocapitalizeSentences;
2500 else
2501 ASSERT_NOT_REACHED();
2505 return flags;
2508 WebString WebViewImpl::inputModeOfFocusedElement()
2510 if (!RuntimeEnabledFeatures::inputModeAttributeEnabled())
2511 return WebString();
2513 Element* element = focusedElement();
2514 if (!element)
2515 return WebString();
2517 if (isHTMLInputElement(*element)) {
2518 const HTMLInputElement& input = toHTMLInputElement(*element);
2519 if (input.supportsInputModeAttribute())
2520 return input.fastGetAttribute(HTMLNames::inputmodeAttr).lower();
2521 return WebString();
2523 if (isHTMLTextAreaElement(*element)) {
2524 const HTMLTextAreaElement& textarea = toHTMLTextAreaElement(*element);
2525 return textarea.fastGetAttribute(HTMLNames::inputmodeAttr).lower();
2528 return WebString();
2531 bool WebViewImpl::selectionBounds(WebRect& anchor, WebRect& focus) const
2533 const Frame* frame = focusedCoreFrame();
2534 if (!frame || !frame->isLocalFrame())
2535 return false;
2537 const LocalFrame* localFrame = toLocalFrame(frame);
2538 if (!localFrame)
2539 return false;
2540 FrameSelection& selection = localFrame->selection();
2542 if (selection.isCaret()) {
2543 anchor = focus = selection.absoluteCaretBounds();
2544 } else {
2545 const EphemeralRange selectedRange = selection.selection().toNormalizedEphemeralRange();
2546 if (selectedRange.isNull())
2547 return false;
2548 anchor = localFrame->editor().firstRectForRange(EphemeralRange(selectedRange.startPosition()));
2549 focus = localFrame->editor().firstRectForRange(EphemeralRange(selectedRange.endPosition()));
2552 anchor = localFrame->view()->contentsToViewport(anchor);
2553 focus = localFrame->view()->contentsToViewport(focus);
2555 if (!selection.selection().isBaseFirst())
2556 std::swap(anchor, focus);
2557 return true;
2560 WebPlugin* WebViewImpl::focusedPluginIfInputMethodSupported(LocalFrame* frame)
2562 WebPluginContainerImpl* container = WebLocalFrameImpl::pluginContainerFromNode(frame, WebNode(focusedElement()));
2563 if (container && container->supportsInputMethod())
2564 return container->plugin();
2565 return 0;
2568 bool WebViewImpl::selectionTextDirection(WebTextDirection& start, WebTextDirection& end) const
2570 const Frame* frame = focusedCoreFrame();
2571 if (!frame || frame->isRemoteFrame())
2572 return false;
2573 FrameSelection& selection = toLocalFrame(frame)->selection();
2574 if (selection.selection().toNormalizedEphemeralRange().isNull())
2575 return false;
2576 start = toWebTextDirection(primaryDirectionOf(*selection.start().anchorNode()));
2577 end = toWebTextDirection(primaryDirectionOf(*selection.end().anchorNode()));
2578 return true;
2581 bool WebViewImpl::isSelectionAnchorFirst() const
2583 const Frame* frame = focusedCoreFrame();
2584 if (!frame || frame->isRemoteFrame())
2585 return false;
2586 return toLocalFrame(frame)->selection().selection().isBaseFirst();
2589 WebColor WebViewImpl::backgroundColor() const
2591 if (isTransparent())
2592 return Color::transparent;
2593 if (!m_page)
2594 return m_baseBackgroundColor;
2595 if (!m_page->mainFrame())
2596 return m_baseBackgroundColor;
2597 if (!m_page->mainFrame()->isLocalFrame())
2598 return m_baseBackgroundColor;
2599 FrameView* view = m_page->deprecatedLocalMainFrame()->view();
2600 return view->documentBackgroundColor().rgb();
2603 WebPagePopup* WebViewImpl::pagePopup() const
2605 return m_pagePopup.get();
2608 bool WebViewImpl::caretOrSelectionRange(size_t* location, size_t* length)
2610 const LocalFrame* focused = toLocalFrame(focusedCoreFrame());
2611 if (!focused)
2612 return false;
2614 PlainTextRange selectionOffsets = focused->inputMethodController().getSelectionOffsets();
2615 if (selectionOffsets.isNull())
2616 return false;
2618 *location = selectionOffsets.start();
2619 *length = selectionOffsets.length();
2620 return true;
2623 void WebViewImpl::setTextDirection(WebTextDirection direction)
2625 // The Editor::setBaseWritingDirection() function checks if we can change
2626 // the text direction of the selected node and updates its DOM "dir"
2627 // attribute and its CSS "direction" property.
2628 // So, we just call the function as Safari does.
2629 const LocalFrame* focused = toLocalFrame(focusedCoreFrame());
2630 if (!focused)
2631 return;
2633 Editor& editor = focused->editor();
2634 if (!editor.canEdit())
2635 return;
2637 switch (direction) {
2638 case WebTextDirectionDefault:
2639 editor.setBaseWritingDirection(NaturalWritingDirection);
2640 break;
2642 case WebTextDirectionLeftToRight:
2643 editor.setBaseWritingDirection(LeftToRightWritingDirection);
2644 break;
2646 case WebTextDirectionRightToLeft:
2647 editor.setBaseWritingDirection(RightToLeftWritingDirection);
2648 break;
2650 default:
2651 notImplemented();
2652 break;
2656 bool WebViewImpl::isAcceleratedCompositingActive() const
2658 return m_rootLayer;
2661 void WebViewImpl::willCloseLayerTreeView()
2663 if (m_linkHighlightsTimeline) {
2664 detachCompositorAnimationTimeline(m_linkHighlightsTimeline.get());
2665 m_linkHighlightsTimeline.clear();
2668 setRootGraphicsLayer(nullptr);
2669 m_layerTreeView = 0;
2672 void WebViewImpl::didAcquirePointerLock()
2674 if (page())
2675 page()->pointerLockController().didAcquirePointerLock();
2678 void WebViewImpl::didNotAcquirePointerLock()
2680 if (page())
2681 page()->pointerLockController().didNotAcquirePointerLock();
2684 void WebViewImpl::didLosePointerLock()
2686 m_pointerLockGestureToken.clear();
2687 if (page())
2688 page()->pointerLockController().didLosePointerLock();
2691 void WebViewImpl::didChangeWindowResizerRect()
2693 if (mainFrameImpl()->frameView())
2694 mainFrameImpl()->frameView()->windowResizerRectChanged();
2697 // WebView --------------------------------------------------------------------
2699 WebSettingsImpl* WebViewImpl::settingsImpl()
2701 if (!m_webSettings)
2702 m_webSettings = adoptPtr(new WebSettingsImpl(&m_page->settings(), m_devToolsEmulator.get()));
2703 ASSERT(m_webSettings);
2704 return m_webSettings.get();
2707 WebSettings* WebViewImpl::settings()
2709 return settingsImpl();
2712 WebString WebViewImpl::pageEncoding() const
2714 if (!m_page)
2715 return WebString();
2717 if (!m_page->mainFrame()->isLocalFrame())
2718 return WebString();
2720 // FIXME: Is this check needed?
2721 if (!m_page->deprecatedLocalMainFrame()->document()->loader())
2722 return WebString();
2724 return m_page->deprecatedLocalMainFrame()->document()->encodingName();
2727 void WebViewImpl::setPageEncoding(const WebString& encodingName)
2729 if (!m_page)
2730 return;
2732 // Only change override encoding, don't change default encoding.
2733 // Note that the new encoding must be 0 if it isn't supposed to be set.
2734 AtomicString newEncodingName;
2735 if (!encodingName.isEmpty())
2736 newEncodingName = encodingName;
2737 m_page->frameHost().setOverrideEncoding(newEncodingName);
2739 if (m_page->mainFrame()->isLocalFrame()) {
2740 if (!m_page->deprecatedLocalMainFrame()->loader().currentItem())
2741 return;
2742 FrameLoadRequest request = FrameLoadRequest(
2743 nullptr,
2744 m_page->deprecatedLocalMainFrame()->loader().resourceRequestForReload(
2745 FrameLoadTypeReload, KURL(), ClientRedirect));
2746 request.setClientRedirect(ClientRedirect);
2747 m_page->deprecatedLocalMainFrame()->loader().load(request, FrameLoadTypeReload);
2751 WebFrame* WebViewImpl::mainFrame()
2753 return WebFrame::fromFrame(m_page ? m_page->mainFrame() : 0);
2756 WebFrame* WebViewImpl::findFrameByName(
2757 const WebString& name, WebFrame* relativeToFrame)
2759 // FIXME: Either this should only deal with WebLocalFrames or it should move to WebFrame.
2760 if (!relativeToFrame)
2761 relativeToFrame = mainFrame();
2762 Frame* frame = toWebLocalFrameImpl(relativeToFrame)->frame();
2763 frame = frame->tree().find(name);
2764 if (!frame || !frame->isLocalFrame())
2765 return 0;
2766 return WebLocalFrameImpl::fromFrame(toLocalFrame(frame));
2769 WebFrame* WebViewImpl::focusedFrame()
2771 return WebFrame::fromFrame(focusedCoreFrame());
2774 void WebViewImpl::setFocusedFrame(WebFrame* frame)
2776 if (!frame) {
2777 // Clears the focused frame if any.
2778 Frame* focusedFrame = focusedCoreFrame();
2779 if (focusedFrame && focusedFrame->isLocalFrame())
2780 toLocalFrame(focusedFrame)->selection().setFocused(false);
2781 return;
2783 LocalFrame* coreFrame = toWebLocalFrameImpl(frame)->frame();
2784 coreFrame->page()->focusController().setFocusedFrame(coreFrame);
2787 void WebViewImpl::setInitialFocus(bool reverse)
2789 if (!m_page)
2790 return;
2791 Frame* frame = page()->focusController().focusedOrMainFrame();
2792 if (frame->isLocalFrame()) {
2793 if (Document* document = toLocalFrame(frame)->document())
2794 document->setFocusedElement(nullptr);
2796 page()->focusController().setInitialFocus(reverse ? WebFocusTypeBackward : WebFocusTypeForward);
2799 void WebViewImpl::clearFocusedElement()
2801 RefPtrWillBeRawPtr<Frame> frame = focusedCoreFrame();
2802 if (!frame || !frame->isLocalFrame())
2803 return;
2805 LocalFrame* localFrame = toLocalFrame(frame.get());
2807 RefPtrWillBeRawPtr<Document> document = localFrame->document();
2808 if (!document)
2809 return;
2811 RefPtrWillBeRawPtr<Element> oldFocusedElement = document->focusedElement();
2813 // Clear the focused node.
2814 document->setFocusedElement(nullptr);
2816 if (!oldFocusedElement)
2817 return;
2819 // If a text field has focus, we need to make sure the selection controller
2820 // knows to remove selection from it. Otherwise, the text field is still
2821 // processing keyboard events even though focus has been moved to the page and
2822 // keystrokes get eaten as a result.
2823 if (oldFocusedElement->isContentEditable() || oldFocusedElement->isTextFormControl())
2824 localFrame->selection().clear();
2827 bool WebViewImpl::scrollFocusedNodeIntoRect(const WebRect& rectInViewport)
2829 LocalFrame* frame = page()->mainFrame() && page()->mainFrame()->isLocalFrame()
2830 ? page()->deprecatedLocalMainFrame() : 0;
2831 Element* element = focusedElement();
2832 if (!frame || !frame->view() || !element)
2833 return false;
2835 element->document().updateLayoutIgnorePendingStylesheets();
2837 bool zoomInToLegibleScale = m_webSettings->autoZoomFocusedNodeToLegibleScale()
2838 && !shouldDisableDesktopWorkarounds();
2840 if (zoomInToLegibleScale) {
2841 // When deciding whether to zoom in on a focused text box, we should decide not to
2842 // zoom in if the user won't be able to zoom out. e.g if the textbox is within a
2843 // touch-action: none container the user can't zoom back out.
2844 TouchAction action = TouchActionUtil::computeEffectiveTouchAction(*element);
2845 if (action != TouchActionAuto && !(action & TouchActionPinchZoom))
2846 zoomInToLegibleScale = false;
2849 float scale;
2850 IntPoint scroll;
2851 bool needAnimation;
2852 computeScaleAndScrollForFocusedNode(element, zoomInToLegibleScale, scale, scroll, needAnimation);
2853 if (needAnimation)
2854 return startPageScaleAnimation(scroll, false, scale, scrollAndScaleAnimationDurationInSeconds);
2856 return false;
2859 void WebViewImpl::smoothScroll(int targetX, int targetY, long durationMs)
2861 IntPoint targetPosition(targetX, targetY);
2862 startPageScaleAnimation(targetPosition, false, pageScaleFactor(), (double)durationMs / 1000);
2865 void WebViewImpl::computeScaleAndScrollForFocusedNode(Node* focusedNode, bool zoomInToLegibleScale, float& newScale, IntPoint& newScroll, bool& needAnimation)
2867 VisualViewport& visualViewport = page()->frameHost().visualViewport();
2869 WebRect caretInViewport, unusedEnd;
2870 selectionBounds(caretInViewport, unusedEnd);
2872 // 'caretInDocument' is rect encompassing the blinking cursor relative to the root document.
2873 IntRect caretInDocument = mainFrameImpl()->frameView()->frameToContents(visualViewport.viewportToRootFrame(caretInViewport));
2874 IntRect textboxRectInDocument = mainFrameImpl()->frameView()->frameToContents(
2875 focusedNode->document().view()->contentsToRootFrame(pixelSnappedIntRect(focusedNode->Node::boundingBox())));
2877 if (!zoomInToLegibleScale) {
2878 newScale = pageScaleFactor();
2879 } else {
2880 // Pick a scale which is reasonably readable. This is the scale at which
2881 // the caret height will become minReadableCaretHeightForNode (adjusted
2882 // for dpi and font scale factor).
2883 const int minReadableCaretHeightForNode = textboxRectInDocument.height() >= 2 * caretInDocument.height() ? minReadableCaretHeightForTextArea : minReadableCaretHeight;
2884 newScale = clampPageScaleFactorToLimits(maximumLegiblePageScale() * minReadableCaretHeightForNode / caretInDocument.height());
2885 newScale = std::max(newScale, pageScaleFactor());
2887 const float deltaScale = newScale / pageScaleFactor();
2889 needAnimation = false;
2891 // If we are at less than the target zoom level, zoom in.
2892 if (deltaScale > minScaleChangeToTriggerZoom)
2893 needAnimation = true;
2894 else
2895 newScale = pageScaleFactor();
2897 // If the caret is offscreen, then animate.
2898 if (!visualViewport.visibleRectInDocument().contains(caretInDocument))
2899 needAnimation = true;
2901 // If the box is partially offscreen and it's possible to bring it fully
2902 // onscreen, then animate.
2903 if (visualViewport.visibleRect().width() >= textboxRectInDocument.width()
2904 && visualViewport.visibleRect().height() >= textboxRectInDocument.height()
2905 && !visualViewport.visibleRectInDocument().contains(textboxRectInDocument))
2906 needAnimation = true;
2908 if (!needAnimation)
2909 return;
2911 FloatSize targetViewportSize = visualViewport.size();
2912 targetViewportSize.scale(1 / newScale);
2914 if (textboxRectInDocument.width() <= targetViewportSize.width()) {
2915 // Field is narrower than screen. Try to leave padding on left so field's
2916 // label is visible, but it's more important to ensure entire field is
2917 // onscreen.
2918 int idealLeftPadding = targetViewportSize.width() * leftBoxRatio;
2919 int maxLeftPaddingKeepingBoxOnscreen = targetViewportSize.width() - textboxRectInDocument.width();
2920 newScroll.setX(textboxRectInDocument.x() - std::min<int>(idealLeftPadding, maxLeftPaddingKeepingBoxOnscreen));
2921 } else {
2922 // Field is wider than screen. Try to left-align field, unless caret would
2923 // be offscreen, in which case right-align the caret.
2924 newScroll.setX(std::max<int>(textboxRectInDocument.x(), caretInDocument.x() + caretInDocument.width() + caretPadding - targetViewportSize.width()));
2926 if (textboxRectInDocument.height() <= targetViewportSize.height()) {
2927 // Field is shorter than screen. Vertically center it.
2928 newScroll.setY(textboxRectInDocument.y() - (targetViewportSize.height() - textboxRectInDocument.height()) / 2);
2929 } else {
2930 // Field is taller than screen. Try to top align field, unless caret would
2931 // be offscreen, in which case bottom-align the caret.
2932 newScroll.setY(std::max<int>(textboxRectInDocument.y(), caretInDocument.y() + caretInDocument.height() + caretPadding - targetViewportSize.height()));
2936 void WebViewImpl::advanceFocus(bool reverse)
2938 page()->focusController().advanceFocus(reverse ? WebFocusTypeBackward : WebFocusTypeForward);
2941 double WebViewImpl::zoomLevel()
2943 return m_zoomLevel;
2946 double WebViewImpl::setZoomLevel(double zoomLevel)
2948 if (zoomLevel < m_minimumZoomLevel)
2949 m_zoomLevel = m_minimumZoomLevel;
2950 else if (zoomLevel > m_maximumZoomLevel)
2951 m_zoomLevel = m_maximumZoomLevel;
2952 else
2953 m_zoomLevel = zoomLevel;
2955 LocalFrame* frame = mainFrameImpl()->frame();
2956 if (!WebLocalFrameImpl::pluginContainerFromFrame(frame)) {
2957 float zoomFactor = m_zoomFactorOverride ? m_zoomFactorOverride : static_cast<float>(zoomLevelToZoomFactor(m_zoomLevel));
2958 frame->setPageZoomFactor(zoomFactor);
2961 return m_zoomLevel;
2964 void WebViewImpl::zoomLimitsChanged(double minimumZoomLevel,
2965 double maximumZoomLevel)
2967 m_minimumZoomLevel = minimumZoomLevel;
2968 m_maximumZoomLevel = maximumZoomLevel;
2969 m_client->zoomLimitsChanged(m_minimumZoomLevel, m_maximumZoomLevel);
2972 float WebViewImpl::textZoomFactor()
2974 return mainFrameImpl()->frame()->textZoomFactor();
2977 float WebViewImpl::setTextZoomFactor(float textZoomFactor)
2979 LocalFrame* frame = mainFrameImpl()->frame();
2980 if (WebLocalFrameImpl::pluginContainerFromFrame(frame))
2981 return 1;
2983 frame->setTextZoomFactor(textZoomFactor);
2985 return textZoomFactor;
2988 double WebView::zoomLevelToZoomFactor(double zoomLevel)
2990 return pow(textSizeMultiplierRatio, zoomLevel);
2993 double WebView::zoomFactorToZoomLevel(double factor)
2995 // Since factor = 1.2^level, level = log(factor) / log(1.2)
2996 return log(factor) / log(textSizeMultiplierRatio);
2999 float WebViewImpl::pageScaleFactor() const
3001 if (!page())
3002 return 1;
3004 return page()->frameHost().visualViewport().scale();
3007 float WebViewImpl::clampPageScaleFactorToLimits(float scaleFactor) const
3009 return pageScaleConstraintsSet().finalConstraints().clampToConstraints(scaleFactor);
3012 void WebViewImpl::setVisualViewportOffset(const WebFloatPoint& offset)
3014 ASSERT(page());
3015 page()->frameHost().visualViewport().setLocation(offset);
3018 void WebViewImpl::setPinchViewportOffset(const WebFloatPoint& offset)
3020 setVisualViewportOffset(offset);
3023 WebFloatPoint WebViewImpl::visualViewportOffset() const
3025 ASSERT(page());
3026 return page()->frameHost().visualViewport().visibleRect().location();
3029 WebFloatPoint WebViewImpl::pinchViewportOffset() const
3031 return visualViewportOffset();
3034 void WebViewImpl::scrollAndRescaleViewports(float scaleFactor,
3035 const IntPoint& mainFrameOrigin,
3036 const FloatPoint& visualViewportOrigin)
3038 if (!page())
3039 return;
3041 if (!mainFrameImpl())
3042 return;
3044 FrameView * view = mainFrameImpl()->frameView();
3045 if (!view)
3046 return;
3048 // Order is important: visual viewport location is clamped based on
3049 // main frame scroll position and visual viewport scale.
3051 view->setScrollPosition(mainFrameOrigin, ProgrammaticScroll);
3053 setPageScaleFactor(scaleFactor);
3055 page()->frameHost().visualViewport().setLocation(visualViewportOrigin);
3058 void WebViewImpl::setPageScaleFactorAndLocation(float scaleFactor, const FloatPoint& location)
3060 ASSERT(page());
3062 page()->frameHost().visualViewport().setScaleAndLocation(
3063 clampPageScaleFactorToLimits(scaleFactor),
3064 location);
3067 void WebViewImpl::setPageScaleFactor(float scaleFactor)
3069 ASSERT(page());
3071 scaleFactor = clampPageScaleFactorToLimits(scaleFactor);
3072 if (scaleFactor == pageScaleFactor())
3073 return;
3075 page()->frameHost().visualViewport().setScale(scaleFactor);
3078 float WebViewImpl::deviceScaleFactor() const
3080 if (!page())
3081 return 1;
3083 return page()->deviceScaleFactor();
3086 void WebViewImpl::setDeviceScaleFactor(float scaleFactor)
3088 if (!page())
3089 return;
3091 page()->setDeviceScaleFactor(scaleFactor);
3093 if (m_layerTreeView)
3094 updateLayerTreeDeviceScaleFactor();
3097 void WebViewImpl::setDeviceColorProfile(const WebVector<char>& colorProfile)
3099 if (!page())
3100 return;
3102 Vector<char> deviceProfile;
3103 deviceProfile.append(colorProfile.data(), colorProfile.size());
3105 page()->setDeviceColorProfile(deviceProfile);
3108 void WebViewImpl::resetDeviceColorProfile()
3110 if (!page())
3111 return;
3113 page()->resetDeviceColorProfile();
3116 void WebViewImpl::enableAutoResizeMode(const WebSize& minSize, const WebSize& maxSize)
3118 m_shouldAutoResize = true;
3119 m_minAutoSize = minSize;
3120 m_maxAutoSize = maxSize;
3121 configureAutoResizeMode();
3124 void WebViewImpl::disableAutoResizeMode()
3126 m_shouldAutoResize = false;
3127 configureAutoResizeMode();
3130 void WebViewImpl::setDefaultPageScaleLimits(float minScale, float maxScale)
3132 return page()->frameHost().setDefaultPageScaleLimits(minScale, maxScale);
3135 void WebViewImpl::setInitialPageScaleOverride(float initialPageScaleFactorOverride)
3137 PageScaleConstraints constraints = pageScaleConstraintsSet().userAgentConstraints();
3138 constraints.initialScale = initialPageScaleFactorOverride;
3140 if (constraints == pageScaleConstraintsSet().userAgentConstraints())
3141 return;
3143 pageScaleConstraintsSet().setNeedsReset(true);
3144 page()->frameHost().setUserAgentPageScaleConstraints(constraints);
3147 void WebViewImpl::setMaximumLegibleScale(float maximumLegibleScale)
3149 m_maximumLegibleScale = maximumLegibleScale;
3152 void WebViewImpl::setIgnoreViewportTagScaleLimits(bool ignore)
3154 PageScaleConstraints constraints = pageScaleConstraintsSet().userAgentConstraints();
3155 if (ignore) {
3156 constraints.minimumScale = pageScaleConstraintsSet().defaultConstraints().minimumScale;
3157 constraints.maximumScale = pageScaleConstraintsSet().defaultConstraints().maximumScale;
3158 } else {
3159 constraints.minimumScale = -1;
3160 constraints.maximumScale = -1;
3162 page()->frameHost().setUserAgentPageScaleConstraints(constraints);
3165 IntSize WebViewImpl::mainFrameSize()
3167 return pageScaleConstraintsSet().mainFrameSize();
3170 PageScaleConstraintsSet& WebViewImpl::pageScaleConstraintsSet() const
3172 return page()->frameHost().pageScaleConstraintsSet();
3175 void WebViewImpl::refreshPageScaleFactorAfterLayout()
3177 if (!mainFrame() || !page() || !page()->mainFrame() || !page()->mainFrame()->isLocalFrame() || !page()->deprecatedLocalMainFrame()->view())
3178 return;
3179 FrameView* view = page()->deprecatedLocalMainFrame()->view();
3181 updatePageDefinedViewportConstraints(mainFrameImpl()->frame()->document()->viewportDescription());
3182 pageScaleConstraintsSet().computeFinalConstraints();
3184 int verticalScrollbarWidth = 0;
3185 if (view->verticalScrollbar() && !view->verticalScrollbar()->isOverlayScrollbar())
3186 verticalScrollbarWidth = view->verticalScrollbar()->width();
3187 pageScaleConstraintsSet().adjustFinalConstraintsToContentsSize(contentsSize(), verticalScrollbarWidth, settings()->shrinksViewportContentToFit());
3189 float newPageScaleFactor = pageScaleFactor();
3190 if (pageScaleConstraintsSet().needsReset() && pageScaleConstraintsSet().finalConstraints().initialScale != -1) {
3191 newPageScaleFactor = pageScaleConstraintsSet().finalConstraints().initialScale;
3192 pageScaleConstraintsSet().setNeedsReset(false);
3194 setPageScaleFactor(newPageScaleFactor);
3196 updateLayerTreeViewport();
3199 void WebViewImpl::updatePageDefinedViewportConstraints(const ViewportDescription& description)
3201 // If we're not reading the viewport meta tag, allow GPU rasterization.
3202 if (!settingsImpl()->viewportMetaEnabled()) {
3203 m_matchesHeuristicsForGpuRasterization = true;
3204 if (m_layerTreeView)
3205 m_layerTreeView->heuristicsForGpuRasterizationUpdated(m_matchesHeuristicsForGpuRasterization);
3208 if (!settings()->viewportEnabled() || !page() || (!m_size.width && !m_size.height) || !page()->mainFrame()->isLocalFrame())
3209 return;
3211 Document* document = page()->deprecatedLocalMainFrame()->document();
3213 m_matchesHeuristicsForGpuRasterization = description.matchesHeuristicsForGpuRasterization();
3214 if (m_layerTreeView)
3215 m_layerTreeView->heuristicsForGpuRasterizationUpdated(m_matchesHeuristicsForGpuRasterization);
3217 Length defaultMinWidth = document->viewportDefaultMinWidth();
3218 if (defaultMinWidth.isAuto())
3219 defaultMinWidth = Length(ExtendToZoom);
3221 ViewportDescription adjustedDescription = description;
3222 if (settingsImpl()->viewportMetaLayoutSizeQuirk() && adjustedDescription.type == ViewportDescription::ViewportMeta) {
3223 const int legacyWidthSnappingMagicNumber = 320;
3224 if (adjustedDescription.maxWidth.isFixed() && adjustedDescription.maxWidth.value() <= legacyWidthSnappingMagicNumber)
3225 adjustedDescription.maxWidth = Length(DeviceWidth);
3226 if (adjustedDescription.maxHeight.isFixed() && adjustedDescription.maxHeight.value() <= m_size.height)
3227 adjustedDescription.maxHeight = Length(DeviceHeight);
3228 adjustedDescription.minWidth = adjustedDescription.maxWidth;
3229 adjustedDescription.minHeight = adjustedDescription.maxHeight;
3232 float oldInitialScale = pageScaleConstraintsSet().pageDefinedConstraints().initialScale;
3233 pageScaleConstraintsSet().updatePageDefinedConstraints(adjustedDescription, defaultMinWidth);
3235 if (settingsImpl()->clobberUserAgentInitialScaleQuirk()
3236 && pageScaleConstraintsSet().userAgentConstraints().initialScale != -1
3237 && pageScaleConstraintsSet().userAgentConstraints().initialScale * deviceScaleFactor() <= 1) {
3238 if (description.maxWidth == Length(DeviceWidth)
3239 || (description.maxWidth.type() == Auto && pageScaleConstraintsSet().pageDefinedConstraints().initialScale == 1.0f))
3240 setInitialPageScaleOverride(-1);
3243 pageScaleConstraintsSet().adjustForAndroidWebViewQuirks(adjustedDescription, defaultMinWidth.intValue(), deviceScaleFactor(), settingsImpl()->supportDeprecatedTargetDensityDPI(), page()->settings().wideViewportQuirkEnabled(), page()->settings().useWideViewport(), page()->settings().loadWithOverviewMode(), settingsImpl()->viewportMetaNonUserScalableQuirk());
3244 float newInitialScale = pageScaleConstraintsSet().pageDefinedConstraints().initialScale;
3245 if (oldInitialScale != newInitialScale && newInitialScale != -1) {
3246 pageScaleConstraintsSet().setNeedsReset(true);
3247 if (mainFrameImpl() && mainFrameImpl()->frameView())
3248 mainFrameImpl()->frameView()->setNeedsLayout();
3251 updateMainFrameLayoutSize();
3253 if (LocalFrame* frame = page()->deprecatedLocalMainFrame()) {
3254 if (TextAutosizer* textAutosizer = frame->document()->textAutosizer())
3255 textAutosizer->updatePageInfoInAllFrames();
3259 void WebViewImpl::updateMainFrameLayoutSize()
3261 if (m_shouldAutoResize || !mainFrameImpl())
3262 return;
3264 RefPtrWillBeRawPtr<FrameView> view = mainFrameImpl()->frameView();
3265 if (!view)
3266 return;
3268 WebSize layoutSize = m_size;
3270 if (settings()->viewportEnabled())
3271 layoutSize = pageScaleConstraintsSet().layoutSize();
3273 if (page()->settings().forceZeroLayoutHeight())
3274 layoutSize.height = 0;
3276 view->setLayoutSize(layoutSize);
3278 // Resizing marks the frame as needsLayout. Inform clients so that they
3279 // will perform the layout. Widgets held by WebPluginContainerImpl do not otherwise
3280 // see this resize layout invalidation.
3281 if (client())
3282 client()->didUpdateLayoutSize(layoutSize);
3285 IntSize WebViewImpl::contentsSize() const
3287 if (!page()->mainFrame()->isLocalFrame())
3288 return IntSize();
3289 LayoutView* root = page()->deprecatedLocalMainFrame()->contentLayoutObject();
3290 if (!root)
3291 return IntSize();
3292 return root->documentRect().size();
3295 WebSize WebViewImpl::contentsPreferredMinimumSize()
3297 layout();
3299 Document* document = m_page->mainFrame()->isLocalFrame() ? m_page->deprecatedLocalMainFrame()->document() : 0;
3300 if (!document || !document->layoutView() || !document->documentElement() || !document->documentElement()->layoutBox())
3301 return WebSize();
3303 int widthScaled = document->layoutView()->minPreferredLogicalWidth().round(); // Already accounts for zoom.
3304 int heightScaled = document->documentElement()->layoutBox()->scrollHeight().round();
3305 return IntSize(widthScaled, heightScaled);
3308 void WebViewImpl::setCompositedDisplayList(PassOwnPtr<CompositedDisplayList> compositedDisplayList)
3310 m_compositedDisplayList.assign(compositedDisplayList);
3313 WebCompositedDisplayList* WebViewImpl::compositedDisplayList()
3315 return &m_compositedDisplayList;
3318 void WebViewImpl::enableViewport()
3320 settings()->setViewportEnabled(true);
3323 void WebViewImpl::disableViewport()
3325 settings()->setViewportEnabled(false);
3326 pageScaleConstraintsSet().clearPageDefinedConstraints();
3327 updateMainFrameLayoutSize();
3330 float WebViewImpl::defaultMinimumPageScaleFactor() const
3332 return pageScaleConstraintsSet().defaultConstraints().minimumScale;
3335 float WebViewImpl::defaultMaximumPageScaleFactor() const
3337 return pageScaleConstraintsSet().defaultConstraints().maximumScale;
3340 float WebViewImpl::minimumPageScaleFactor() const
3342 return pageScaleConstraintsSet().finalConstraints().minimumScale;
3345 float WebViewImpl::maximumPageScaleFactor() const
3347 return pageScaleConstraintsSet().finalConstraints().maximumScale;
3350 void WebViewImpl::resetScrollAndScaleState()
3352 resetScrollAndScaleState(false);
3355 void WebViewImpl::resetScrollAndScaleStateImmediately()
3357 resetScrollAndScaleState(true);
3360 void WebViewImpl::resetScrollAndScaleState(bool immediately)
3362 page()->frameHost().visualViewport().reset();
3364 if (!page()->mainFrame()->isLocalFrame())
3365 return;
3367 if (FrameView* frameView = toLocalFrame(page()->mainFrame())->view()) {
3368 ScrollableArea* scrollableArea = frameView->layoutViewportScrollableArea();
3370 if (scrollableArea->scrollPositionDouble() != DoublePoint::zero())
3371 scrollableArea->setScrollPosition(DoublePoint::zero(), ProgrammaticScroll);
3374 pageScaleConstraintsSet().setNeedsReset(true);
3375 if (immediately)
3376 refreshPageScaleFactorAfterLayout();
3378 // Clobber saved scales and scroll offsets.
3379 if (FrameView* view = page()->deprecatedLocalMainFrame()->document()->view())
3380 view->cacheCurrentScrollPosition();
3383 void WebViewImpl::performMediaPlayerAction(const WebMediaPlayerAction& action,
3384 const WebPoint& location)
3386 HitTestResult result = hitTestResultForViewportPos(location);
3387 RefPtrWillBeRawPtr<Node> node = result.innerNode();
3388 if (!isHTMLVideoElement(*node) && !isHTMLAudioElement(*node))
3389 return;
3391 RefPtrWillBeRawPtr<HTMLMediaElement> mediaElement = static_pointer_cast<HTMLMediaElement>(node);
3392 switch (action.type) {
3393 case WebMediaPlayerAction::Play:
3394 if (action.enable)
3395 mediaElement->play();
3396 else
3397 mediaElement->pause();
3398 break;
3399 case WebMediaPlayerAction::Mute:
3400 mediaElement->setMuted(action.enable);
3401 break;
3402 case WebMediaPlayerAction::Loop:
3403 mediaElement->setLoop(action.enable);
3404 break;
3405 case WebMediaPlayerAction::Controls:
3406 mediaElement->setBooleanAttribute(HTMLNames::controlsAttr, action.enable);
3407 break;
3408 default:
3409 ASSERT_NOT_REACHED();
3413 void WebViewImpl::performPluginAction(const WebPluginAction& action,
3414 const WebPoint& location)
3416 // FIXME: Location is probably in viewport coordinates
3417 HitTestResult result = hitTestResultForRootFramePos(location);
3418 RefPtrWillBeRawPtr<Node> node = result.innerNode();
3419 if (!isHTMLObjectElement(*node) && !isHTMLEmbedElement(*node))
3420 return;
3422 LayoutObject* object = node->layoutObject();
3423 if (object && object->isLayoutPart()) {
3424 Widget* widget = toLayoutPart(object)->widget();
3425 if (widget && widget->isPluginContainer()) {
3426 WebPluginContainerImpl* plugin = toWebPluginContainerImpl(widget);
3427 switch (action.type) {
3428 case WebPluginAction::Rotate90Clockwise:
3429 plugin->plugin()->rotateView(WebPlugin::RotationType90Clockwise);
3430 break;
3431 case WebPluginAction::Rotate90Counterclockwise:
3432 plugin->plugin()->rotateView(WebPlugin::RotationType90Counterclockwise);
3433 break;
3434 default:
3435 ASSERT_NOT_REACHED();
3441 WebHitTestResult WebViewImpl::hitTestResultAt(const WebPoint& point)
3443 return coreHitTestResultAt(point);
3446 HitTestResult WebViewImpl::coreHitTestResultAt(const WebPoint& pointInViewport)
3448 FrameView* view = mainFrameImpl()->frameView();
3449 IntPoint pointInRootFrame = view->contentsToFrame(view->viewportToContents(pointInViewport));
3450 return hitTestResultForRootFramePos(pointInRootFrame);
3453 void WebViewImpl::copyImageAt(const WebPoint& point)
3455 if (!m_page)
3456 return;
3458 HitTestResult result = hitTestResultForViewportPos(point);
3459 if (!isHTMLCanvasElement(result.innerNodeOrImageMapImage()) && result.absoluteImageURL().isEmpty()) {
3460 // There isn't actually an image at these coordinates. Might be because
3461 // the window scrolled while the context menu was open or because the page
3462 // changed itself between when we thought there was an image here and when
3463 // we actually tried to retreive the image.
3465 // FIXME: implement a cache of the most recent HitTestResult to avoid having
3466 // to do two hit tests.
3467 return;
3470 m_page->deprecatedLocalMainFrame()->editor().copyImage(result);
3473 void WebViewImpl::saveImageAt(const WebPoint& point)
3475 if (!m_client)
3476 return;
3478 Node* node = hitTestResultForViewportPos(point).innerNodeOrImageMapImage();
3479 if (!node || !(isHTMLCanvasElement(*node) || isHTMLImageElement(*node)))
3480 return;
3482 String url = toElement(*node).imageSourceURL();
3483 if (!KURL(KURL(), url).protocolIsData())
3484 return;
3486 m_client->saveImageFromDataURL(url);
3489 void WebViewImpl::dragSourceEndedAt(
3490 const WebPoint& clientPoint,
3491 const WebPoint& screenPoint,
3492 WebDragOperation operation)
3494 PlatformMouseEvent pme(clientPoint, screenPoint, LeftButton, PlatformEvent::MouseMoved,
3495 0, false, false, false, false, PlatformMouseEvent::RealOrIndistinguishable, 0);
3496 m_page->deprecatedLocalMainFrame()->eventHandler().dragSourceEndedAt(pme,
3497 static_cast<DragOperation>(operation));
3500 void WebViewImpl::dragSourceSystemDragEnded()
3502 // It's possible for us to get this callback while not doing a drag if
3503 // it's from a previous page that got unloaded.
3504 if (m_doingDragAndDrop) {
3505 m_page->dragController().dragEnded();
3506 m_doingDragAndDrop = false;
3510 WebDragOperation WebViewImpl::dragTargetDragEnter(
3511 const WebDragData& webDragData,
3512 const WebPoint& clientPoint,
3513 const WebPoint& screenPoint,
3514 WebDragOperationsMask operationsAllowed,
3515 int modifiers)
3517 ASSERT(!m_currentDragData);
3519 m_currentDragData = DataObject::create(webDragData);
3520 m_operationsAllowed = operationsAllowed;
3522 return dragTargetDragEnterOrOver(clientPoint, screenPoint, DragEnter, modifiers);
3525 WebDragOperation WebViewImpl::dragTargetDragOver(
3526 const WebPoint& clientPoint,
3527 const WebPoint& screenPoint,
3528 WebDragOperationsMask operationsAllowed,
3529 int modifiers)
3531 m_operationsAllowed = operationsAllowed;
3533 return dragTargetDragEnterOrOver(clientPoint, screenPoint, DragOver, modifiers);
3536 void WebViewImpl::dragTargetDragLeave()
3538 ASSERT(m_currentDragData);
3540 DragData dragData(
3541 m_currentDragData.get(),
3542 IntPoint(),
3543 IntPoint(),
3544 static_cast<DragOperation>(m_operationsAllowed));
3546 m_page->dragController().dragExited(&dragData);
3548 // FIXME: why is the drag scroll timer not stopped here?
3550 m_dragOperation = WebDragOperationNone;
3551 m_currentDragData = nullptr;
3554 void WebViewImpl::dragTargetDrop(const WebPoint& clientPoint,
3555 const WebPoint& screenPoint,
3556 int modifiers)
3558 ASSERT(m_currentDragData);
3560 WebAutofillClient* autofillClient = mainFrameImpl() ? mainFrameImpl()->autofillClient() : 0;
3561 UserGestureNotifier notifier(autofillClient, &m_userGestureObserved);
3563 // If this webview transitions from the "drop accepting" state to the "not
3564 // accepting" state, then our IPC message reply indicating that may be in-
3565 // flight, or else delayed by javascript processing in this webview. If a
3566 // drop happens before our IPC reply has reached the browser process, then
3567 // the browser forwards the drop to this webview. So only allow a drop to
3568 // proceed if our webview m_dragOperation state is not DragOperationNone.
3570 if (m_dragOperation == WebDragOperationNone) { // IPC RACE CONDITION: do not allow this drop.
3571 dragTargetDragLeave();
3572 return;
3575 m_currentDragData->setModifiers(toPlatformMouseEventModifiers(modifiers));
3576 DragData dragData(
3577 m_currentDragData.get(),
3578 clientPoint,
3579 screenPoint,
3580 static_cast<DragOperation>(m_operationsAllowed));
3582 UserGestureIndicator gesture(DefinitelyProcessingNewUserGesture);
3583 m_page->dragController().performDrag(&dragData);
3585 m_dragOperation = WebDragOperationNone;
3586 m_currentDragData = nullptr;
3589 void WebViewImpl::spellingMarkers(WebVector<uint32_t>* markers)
3591 Vector<uint32_t> result;
3592 for (Frame* frame = m_page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
3593 if (!frame->isLocalFrame())
3594 continue;
3595 const DocumentMarkerVector& documentMarkers = toLocalFrame(frame)->document()->markers().markers();
3596 for (size_t i = 0; i < documentMarkers.size(); ++i)
3597 result.append(documentMarkers[i]->hash());
3599 markers->assign(result);
3602 void WebViewImpl::removeSpellingMarkersUnderWords(const WebVector<WebString>& words)
3604 Vector<String> convertedWords;
3605 convertedWords.append(words.data(), words.size());
3607 for (Frame* frame = m_page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
3608 if (frame->isLocalFrame())
3609 toLocalFrame(frame)->removeSpellingMarkersUnderWords(convertedWords);
3613 WebDragOperation WebViewImpl::dragTargetDragEnterOrOver(const WebPoint& clientPoint, const WebPoint& screenPoint, DragAction dragAction, int modifiers)
3615 ASSERT(m_currentDragData);
3617 m_currentDragData->setModifiers(toPlatformMouseEventModifiers(modifiers));
3618 DragData dragData(
3619 m_currentDragData.get(),
3620 clientPoint,
3621 screenPoint,
3622 static_cast<DragOperation>(m_operationsAllowed));
3624 DragSession dragSession;
3625 if (dragAction == DragEnter)
3626 dragSession = m_page->dragController().dragEntered(&dragData);
3627 else
3628 dragSession = m_page->dragController().dragUpdated(&dragData);
3630 DragOperation dropEffect = dragSession.operation;
3632 // Mask the drop effect operation against the drag source's allowed operations.
3633 if (!(dropEffect & dragData.draggingSourceOperationMask()))
3634 dropEffect = DragOperationNone;
3636 m_dragOperation = static_cast<WebDragOperation>(dropEffect);
3638 return m_dragOperation;
3641 void WebViewImpl::sendResizeEventAndRepaint()
3643 // FIXME: This is wrong. The FrameView is responsible sending a resizeEvent
3644 // as part of layout. Layout is also responsible for sending invalidations
3645 // to the embedder. This method and all callers may be wrong. -- eseidel.
3646 if (mainFrameImpl()->frameView()) {
3647 // Enqueues the resize event.
3648 mainFrameImpl()->frame()->document()->enqueueResizeEvent();
3651 if (m_client) {
3652 if (m_layerTreeView) {
3653 updateLayerTreeViewport();
3654 } else {
3655 WebRect damagedRect(0, 0, m_size.width, m_size.height);
3656 m_client->didInvalidateRect(damagedRect);
3659 updatePageOverlays();
3660 m_devToolsEmulator->viewportChanged();
3663 void WebViewImpl::configureAutoResizeMode()
3665 if (!mainFrameImpl() || !mainFrameImpl()->frame() || !mainFrameImpl()->frame()->view())
3666 return;
3668 if (m_shouldAutoResize)
3669 mainFrameImpl()->frame()->view()->enableAutoSizeMode(m_minAutoSize, m_maxAutoSize);
3670 else
3671 mainFrameImpl()->frame()->view()->disableAutoSizeMode();
3674 unsigned long WebViewImpl::createUniqueIdentifierForRequest()
3676 return createUniqueIdentifier();
3679 void WebViewImpl::setCompositorDeviceScaleFactorOverride(float deviceScaleFactor)
3681 if (m_compositorDeviceScaleFactorOverride == deviceScaleFactor)
3682 return;
3683 m_compositorDeviceScaleFactorOverride = deviceScaleFactor;
3684 if (page() && m_layerTreeView)
3685 updateLayerTreeDeviceScaleFactor();
3688 void WebViewImpl::setRootLayerTransform(const WebSize& rootLayerOffset, float rootLayerScale)
3690 if (m_rootLayerScale == rootLayerScale && m_rootLayerOffset == rootLayerOffset)
3691 return;
3692 m_rootLayerScale = rootLayerScale;
3693 m_rootLayerOffset = rootLayerOffset;
3694 if (mainFrameImpl())
3695 mainFrameImpl()->setInputEventsTransformForEmulation(m_rootLayerOffset, m_rootLayerScale);
3696 updateRootLayerTransform();
3699 void WebViewImpl::enableDeviceEmulation(const WebDeviceEmulationParams& params)
3701 m_devToolsEmulator->enableDeviceEmulation(params);
3704 void WebViewImpl::disableDeviceEmulation()
3706 m_devToolsEmulator->disableDeviceEmulation();
3709 WebAXObject WebViewImpl::accessibilityObject()
3711 if (!mainFrameImpl())
3712 return WebAXObject();
3714 Document* document = mainFrameImpl()->frame()->document();
3715 return WebAXObject(toAXObjectCacheImpl(document->axObjectCache())->root());
3718 void WebViewImpl::performCustomContextMenuAction(unsigned action)
3720 if (!m_page)
3721 return;
3722 ContextMenu* menu = m_page->contextMenuController().contextMenu();
3723 if (!menu)
3724 return;
3725 const ContextMenuItem* item = menu->itemWithAction(static_cast<ContextMenuAction>(ContextMenuItemBaseCustomTag + action));
3726 if (item)
3727 m_page->contextMenuController().contextMenuItemSelected(item);
3728 m_page->contextMenuController().clearContextMenu();
3731 void WebViewImpl::showContextMenu()
3733 if (!page())
3734 return;
3736 page()->contextMenuController().clearContextMenu();
3738 ContextMenuAllowedScope scope;
3739 if (LocalFrame* focusedFrame = toLocalFrame(page()->focusController().focusedOrMainFrame()))
3740 focusedFrame->eventHandler().sendContextMenuEventForKey(nullptr);
3744 void WebViewImpl::extractSmartClipData(WebRect rectInViewport, WebString& clipText, WebString& clipHtml, WebRect& clipRectInViewport)
3746 LocalFrame* localFrame = toLocalFrame(focusedCoreFrame());
3747 if (!localFrame)
3748 return;
3749 SmartClipData clipData = SmartClip(localFrame).dataForRect(rectInViewport);
3750 clipText = clipData.clipData();
3751 clipRectInViewport = clipData.rectInViewport();
3753 WebLocalFrameImpl* frame = mainFrameImpl();
3754 if (!frame)
3755 return;
3756 WebPoint startPoint(rectInViewport.x, rectInViewport.y);
3757 WebPoint endPoint(rectInViewport.x + rectInViewport.width, rectInViewport.y + rectInViewport.height);
3758 VisiblePosition startVisiblePosition = frame->visiblePositionForViewportPoint(startPoint);
3759 VisiblePosition endVisiblePosition = frame->visiblePositionForViewportPoint(endPoint);
3761 Position startPosition = startVisiblePosition.deepEquivalent();
3762 Position endPosition = endVisiblePosition.deepEquivalent();
3764 // document() will return null if -webkit-user-select is set to none.
3765 if (!startPosition.document() || !endPosition.document())
3766 return;
3768 clipHtml = createMarkup(startPosition, endPosition, AnnotateForInterchange, ConvertBlocksToInlines::NotConvert, ResolveNonLocalURLs);
3771 void WebViewImpl::hidePopups()
3773 cancelPagePopup();
3776 void WebViewImpl::setIsTransparent(bool isTransparent)
3778 // Set any existing frames to be transparent.
3779 Frame* frame = m_page->mainFrame();
3780 while (frame) {
3781 if (frame->isLocalFrame())
3782 toLocalFrame(frame)->view()->setTransparent(isTransparent);
3783 frame = frame->tree().traverseNext();
3786 // Future frames check this to know whether to be transparent.
3787 m_isTransparent = isTransparent;
3789 if (m_layerTreeView)
3790 m_layerTreeView->setHasTransparentBackground(this->isTransparent());
3793 bool WebViewImpl::isTransparent() const
3795 return m_isTransparent;
3798 void WebViewImpl::setBaseBackgroundColor(WebColor color)
3800 layout();
3802 if (m_baseBackgroundColor == color)
3803 return;
3805 m_baseBackgroundColor = color;
3807 if (m_page->mainFrame() && m_page->mainFrame()->isLocalFrame())
3808 m_page->deprecatedLocalMainFrame()->view()->setBaseBackgroundColor(color);
3810 updateLayerTreeBackgroundColor();
3813 void WebViewImpl::setIsActive(bool active)
3815 if (page())
3816 page()->focusController().setActive(active);
3819 bool WebViewImpl::isActive() const
3821 return page() ? page()->focusController().isActive() : false;
3824 void WebViewImpl::setDomainRelaxationForbidden(bool forbidden, const WebString& scheme)
3826 SchemeRegistry::setDomainRelaxationForbiddenForURLScheme(forbidden, String(scheme));
3829 void WebViewImpl::setWindowFeatures(const WebWindowFeatures& features)
3831 m_page->chromeClient().setWindowFeatures(features);
3834 void WebViewImpl::setOpenedByDOM()
3836 m_page->setOpenedByDOM();
3839 void WebViewImpl::setSelectionColors(unsigned activeBackgroundColor,
3840 unsigned activeForegroundColor,
3841 unsigned inactiveBackgroundColor,
3842 unsigned inactiveForegroundColor) {
3843 #if USE(DEFAULT_RENDER_THEME)
3844 LayoutThemeDefault::setSelectionColors(activeBackgroundColor, activeForegroundColor, inactiveBackgroundColor, inactiveForegroundColor);
3845 LayoutTheme::theme().platformColorsDidChange();
3846 #endif
3849 void WebViewImpl::didCommitLoad(bool isNewNavigation, bool isNavigationWithinPage)
3851 if (isNewNavigation && !isNavigationWithinPage) {
3852 pageScaleConstraintsSet().setNeedsReset(true);
3853 m_pageImportanceSignals.onCommitLoad();
3856 // Give the visual viewport's scroll layer its initial size.
3857 page()->frameHost().visualViewport().mainFrameDidChangeSize();
3859 // Make sure link highlight from previous page is cleared.
3860 m_linkHighlights.clear();
3861 endActiveFlingAnimation();
3862 m_userGestureObserved = false;
3865 void WebViewImpl::documentElementAvailable(WebLocalFrameImpl* webframe)
3867 if (webframe != mainFrameImpl())
3868 return;
3870 // For non-HTML documents the willInsertBody notification won't happen
3871 // so we resume as soon as we have a document element. Even for XHTML
3872 // documents there may never be a <body> (since the parser won't always
3873 // insert one), so we resume here too. That does mean XHTML documents make
3874 // frames when there's only a <head>, but such documents are pretty rare.
3875 if (!mainFrameImpl()->frame()->document()->isHTMLDocument())
3876 resumeTreeViewCommitsIfRenderingReady();
3879 void WebViewImpl::willInsertBody(WebLocalFrameImpl* webframe)
3881 if (webframe != mainFrameImpl())
3882 return;
3884 // If we get to the <body> try to resume commits since we should have content
3885 // to paint now.
3886 // TODO(esprehn): Is this really optimal? We might start producing frames
3887 // for very little content, should we wait for some herustic like
3888 // isVisuallyNonEmpty() ?
3889 resumeTreeViewCommitsIfRenderingReady();
3892 void WebViewImpl::didFinishDocumentLoad(WebLocalFrameImpl* webframe)
3894 if (webframe != mainFrameImpl())
3895 return;
3896 resumeTreeViewCommitsIfRenderingReady();
3899 void WebViewImpl::didRemoveAllPendingStylesheet(WebLocalFrameImpl* webframe)
3901 if (webframe != mainFrameImpl())
3902 return;
3904 Document& document = *mainFrameImpl()->frame()->document();
3906 // For HTML if we have no more stylesheets to load and we're past the body
3907 // tag, we should have something to paint so resume.
3908 if (document.isHTMLDocument() && !document.body())
3909 return;
3911 // For non-HTML there is no body so resume as soon as the sheets are loaded.
3912 if (!document.isHTMLDocument() && !document.documentElement())
3913 return;
3915 resumeTreeViewCommitsIfRenderingReady();
3918 void WebViewImpl::resumeTreeViewCommitsIfRenderingReady()
3920 LocalFrame* frame = mainFrameImpl()->frame();
3921 if (!frame->loader().stateMachine()->committedFirstRealDocumentLoad())
3922 return;
3923 if (!frame->document()->isRenderingReady())
3924 return;
3925 if (m_layerTreeView) {
3926 m_layerTreeView->setDeferCommits(false);
3927 m_layerTreeView->setNeedsBeginFrame();
3931 void WebViewImpl::postLayoutResize(WebLocalFrameImpl* webframe)
3933 FrameView* view = webframe->frame()->view();
3934 if (webframe == mainFrame())
3935 view->resize(mainFrameSize());
3936 else
3937 view->resize(webframe->frameView()->size());
3940 void WebViewImpl::layoutUpdated(WebLocalFrameImpl* webframe)
3942 if (!m_client || !webframe->frame()->isLocalRoot())
3943 return;
3945 if (m_shouldAutoResize && webframe->frame() && webframe->frame()->view()) {
3946 WebSize frameSize = webframe->frame()->view()->frameRect().size();
3947 if (frameSize != m_size) {
3948 m_size = frameSize;
3950 page()->frameHost().visualViewport().setSize(m_size);
3951 pageScaleConstraintsSet().didChangeViewSize(m_size);
3953 m_client->didAutoResize(m_size);
3954 sendResizeEventAndRepaint();
3958 if (pageScaleConstraintsSet().constraintsDirty())
3959 refreshPageScaleFactorAfterLayout();
3961 FrameView* view = webframe->frame()->view();
3963 postLayoutResize(webframe);
3965 // Relayout immediately to avoid violating the rule that needsLayout()
3966 // isn't set at the end of a layout.
3967 if (view->needsLayout())
3968 view->layout();
3970 // In case we didn't have a size when the top controls were updated.
3971 didUpdateTopControls();
3973 m_client->didUpdateLayout();
3976 void WebViewImpl::didChangeContentsSize()
3978 pageScaleConstraintsSet().didChangeContentsSize(contentsSize(), pageScaleFactor());
3981 void WebViewImpl::pageScaleFactorChanged()
3983 pageScaleConstraintsSet().setNeedsReset(false);
3984 updateLayerTreeViewport();
3985 m_devToolsEmulator->viewportChanged();
3986 m_client->pageScaleFactorChanged();
3989 bool WebViewImpl::useExternalPopupMenus()
3991 return shouldUseExternalPopupMenus;
3994 void WebViewImpl::startDragging(LocalFrame* frame,
3995 const WebDragData& dragData,
3996 WebDragOperationsMask mask,
3997 const WebImage& dragImage,
3998 const WebPoint& dragImageOffset)
4000 if (!m_client)
4001 return;
4002 ASSERT(!m_doingDragAndDrop);
4003 m_doingDragAndDrop = true;
4004 m_client->startDragging(WebLocalFrameImpl::fromFrame(frame), dragData, mask, dragImage, dragImageOffset);
4007 void WebViewImpl::setIgnoreInputEvents(bool newValue)
4009 ASSERT(m_ignoreInputEvents != newValue);
4010 m_ignoreInputEvents = newValue;
4013 void WebViewImpl::setBackgroundColorOverride(WebColor color)
4015 m_backgroundColorOverride = color;
4016 updateLayerTreeBackgroundColor();
4019 void WebViewImpl::setZoomFactorOverride(float zoomFactor)
4021 m_zoomFactorOverride = zoomFactor;
4022 setZoomLevel(zoomLevel());
4025 void WebViewImpl::setPageOverlayColor(WebColor color)
4027 if (m_pageColorOverlay)
4028 m_pageColorOverlay.clear();
4030 if (color == Color::transparent)
4031 return;
4033 m_pageColorOverlay = PageOverlay::create(this, new ColorOverlay(color));
4034 m_pageColorOverlay->update();
4037 WebPageImportanceSignals* WebViewImpl::pageImportanceSignals()
4039 return &m_pageImportanceSignals;
4042 Element* WebViewImpl::focusedElement() const
4044 Frame* frame = m_page->focusController().focusedFrame();
4045 if (!frame || !frame->isLocalFrame())
4046 return 0;
4048 Document* document = toLocalFrame(frame)->document();
4049 if (!document)
4050 return 0;
4052 return document->focusedElement();
4055 HitTestResult WebViewImpl::hitTestResultForViewportPos(const IntPoint& posInViewport)
4057 IntPoint rootFramePoint(m_page->frameHost().visualViewport().viewportToRootFrame(posInViewport));
4058 return hitTestResultForRootFramePos(rootFramePoint);
4061 HitTestResult WebViewImpl::hitTestResultForRootFramePos(const IntPoint& posInRootFrame)
4063 if (!m_page->mainFrame()->isLocalFrame())
4064 return HitTestResult();
4065 IntPoint docPoint(m_page->deprecatedLocalMainFrame()->view()->rootFrameToContents(posInRootFrame));
4066 HitTestResult result = m_page->deprecatedLocalMainFrame()->eventHandler().hitTestResultAtPoint(docPoint, HitTestRequest::ReadOnly | HitTestRequest::Active);
4067 result.setToShadowHostIfInUserAgentShadowRoot();
4068 return result;
4071 WebHitTestResult WebViewImpl::hitTestResultForTap(const WebPoint& tapPointWindowPos, const WebSize& tapArea)
4073 if (!m_page->mainFrame()->isLocalFrame())
4074 return HitTestResult();
4076 WebGestureEvent tapEvent;
4077 tapEvent.x = tapPointWindowPos.x;
4078 tapEvent.y = tapPointWindowPos.y;
4079 tapEvent.type = WebInputEvent::GestureTap;
4080 tapEvent.data.tap.tapCount = 1;
4081 tapEvent.data.tap.width = tapArea.width;
4082 tapEvent.data.tap.height = tapArea.height;
4084 PlatformGestureEventBuilder platformEvent(mainFrameImpl()->frameView(), tapEvent);
4086 HitTestResult result = m_page->deprecatedLocalMainFrame()->eventHandler().hitTestResultForGestureEvent(platformEvent, HitTestRequest::ReadOnly | HitTestRequest::Active).hitTestResult();
4088 result.setToShadowHostIfInUserAgentShadowRoot();
4089 return result;
4092 void WebViewImpl::setTabsToLinks(bool enable)
4094 m_tabsToLinks = enable;
4097 bool WebViewImpl::tabsToLinks() const
4099 return m_tabsToLinks;
4102 void WebViewImpl::setRootGraphicsLayer(GraphicsLayer* layer)
4104 if (!m_layerTreeView)
4105 return;
4107 VisualViewport& visualViewport = page()->frameHost().visualViewport();
4108 visualViewport.attachToLayerTree(layer, graphicsLayerFactory());
4109 if (layer) {
4110 m_rootGraphicsLayer = visualViewport.rootGraphicsLayer();
4111 m_rootLayer = visualViewport.rootGraphicsLayer()->platformLayer();
4112 m_rootTransformLayer = visualViewport.rootGraphicsLayer();
4113 updateRootLayerTransform();
4114 m_layerTreeView->setRootLayer(*m_rootLayer);
4115 // We register viewport layers here since there may not be a layer
4116 // tree view prior to this point.
4117 page()->frameHost().visualViewport().registerLayersWithTreeView(m_layerTreeView);
4118 updatePageOverlays();
4119 // TODO(enne): Work around page visibility changes not being
4120 // propogated to the WebView in some circumstances. This needs to
4121 // be refreshed here when setting a new root layer to avoid being
4122 // stuck in a presumed incorrectly invisible state.
4123 bool visible = page()->visibilityState() == PageVisibilityStateVisible;
4124 m_layerTreeView->setVisible(visible);
4125 } else {
4126 m_rootGraphicsLayer = nullptr;
4127 m_rootLayer = nullptr;
4128 m_rootTransformLayer = nullptr;
4129 // This means that we're transitioning to a new page. Suppress
4130 // commits until Blink generates invalidations so we don't
4131 // attempt to paint too early in the next page load.
4132 m_layerTreeView->setDeferCommits(true);
4133 m_layerTreeView->clearRootLayer();
4134 m_shouldDispatchFirstVisuallyNonEmptyLayout = true;
4135 m_shouldDispatchFirstLayoutAfterFinishedParsing = true;
4136 page()->frameHost().visualViewport().clearLayersForTreeView(m_layerTreeView);
4140 void WebViewImpl::invalidateRect(const IntRect& rect)
4142 if (m_layerTreeView)
4143 updateLayerTreeViewport();
4144 else if (m_client)
4145 m_client->didInvalidateRect(rect);
4148 GraphicsLayerFactory* WebViewImpl::graphicsLayerFactory() const
4150 return m_graphicsLayerFactory.get();
4153 DeprecatedPaintLayerCompositor* WebViewImpl::compositor() const
4155 if (!page() || !page()->mainFrame() || !page()->mainFrame()->isLocalFrame())
4156 return 0;
4158 if (!page()->deprecatedLocalMainFrame()->document() || !page()->deprecatedLocalMainFrame()->document()->layoutView())
4159 return 0;
4161 return page()->deprecatedLocalMainFrame()->document()->layoutView()->compositor();
4164 void WebViewImpl::registerForAnimations(WebLayer* layer)
4166 if (m_layerTreeView)
4167 m_layerTreeView->registerForAnimations(layer);
4170 GraphicsLayer* WebViewImpl::rootGraphicsLayer()
4172 return m_rootGraphicsLayer;
4175 void WebViewImpl::scheduleAnimation()
4177 if (m_layerTreeView) {
4178 m_layerTreeView->setNeedsBeginFrame();
4179 return;
4181 if (m_client)
4182 m_client->scheduleAnimation();
4185 void WebViewImpl::attachCompositorAnimationTimeline(WebCompositorAnimationTimeline* timeline)
4187 if (m_layerTreeView)
4188 m_layerTreeView->attachCompositorAnimationTimeline(timeline);
4191 void WebViewImpl::detachCompositorAnimationTimeline(WebCompositorAnimationTimeline* timeline)
4193 if (m_layerTreeView)
4194 m_layerTreeView->detachCompositorAnimationTimeline(timeline);
4197 void WebViewImpl::initializeLayerTreeView()
4199 if (m_client) {
4200 m_client->initializeLayerTreeView();
4201 m_layerTreeView = m_client->layerTreeView();
4204 if (WebDevToolsAgentImpl* devTools = mainFrameDevToolsAgentImpl())
4205 devTools->layerTreeViewChanged(m_layerTreeView);
4207 m_page->settings().setAcceleratedCompositingEnabled(m_layerTreeView != 0);
4209 // FIXME: only unittests, click to play, Android priting, and printing (for headers and footers)
4210 // make this assert necessary. We should make them not hit this code and then delete allowsBrokenNullLayerTreeView.
4211 ASSERT(m_layerTreeView || !m_client || m_client->allowsBrokenNullLayerTreeView());
4213 if (RuntimeEnabledFeatures::compositorAnimationTimelinesEnabled() && Platform::current()->isThreadedAnimationEnabled() && m_layerTreeView) {
4214 ASSERT(Platform::current()->compositorSupport());
4215 m_linkHighlightsTimeline = adoptPtr(Platform::current()->compositorSupport()->createAnimationTimeline());
4216 attachCompositorAnimationTimeline(m_linkHighlightsTimeline.get());
4220 void WebViewImpl::applyViewportDeltas(
4221 const WebFloatSize& visualViewportDelta,
4222 const WebFloatSize& layoutViewportDelta,
4223 const WebFloatSize& elasticOverscrollDelta,
4224 float pageScaleDelta,
4225 float topControlsShownRatioDelta)
4227 if (!mainFrameImpl())
4228 return;
4229 FrameView* frameView = mainFrameImpl()->frameView();
4230 if (!frameView)
4231 return;
4233 topControls().setShownRatio(topControls().shownRatio() + topControlsShownRatioDelta);
4235 FloatPoint visualViewportOffset = page()->frameHost().visualViewport().visibleRect().location();
4236 visualViewportOffset.move(visualViewportDelta.width, visualViewportDelta.height);
4237 setPageScaleFactorAndLocation(pageScaleFactor() * pageScaleDelta, visualViewportOffset);
4239 if (pageScaleDelta != 1)
4240 m_doubleTapZoomPending = false;
4242 m_elasticOverscroll += elasticOverscrollDelta;
4243 frameView->didUpdateElasticOverscroll();
4245 ScrollableArea* layoutViewport = frameView->layoutViewportScrollableArea();
4247 DoublePoint layoutViewportPosition = layoutViewport->scrollPositionDouble()
4248 + DoubleSize(layoutViewportDelta.width, layoutViewportDelta.height);
4250 if (layoutViewport->scrollPositionDouble() != layoutViewportPosition) {
4251 layoutViewport->setScrollPosition(layoutViewportPosition, CompositorScroll);
4252 if (DocumentLoader* documentLoader = mainFrameImpl()->frame()->loader().documentLoader())
4253 documentLoader->initialScrollState().wasScrolledByUser = true;
4257 void WebViewImpl::recordFrameTimingEvent(FrameTimingEventType eventType, int64_t FrameId, const WebVector<WebFrameTimingEvent>& events)
4259 Frame* frame = m_page ? m_page->mainFrame() : 0;
4261 while (frame && frame->frameID() != FrameId) {
4262 frame = frame->tree().traverseNext();
4265 if (!frame || !frame->domWindow() || !frame->domWindow()->document())
4266 return; // Can't find frame, it may have been cleaned up from the DOM.
4268 blink::DOMWindow* domWindow = frame->domWindow();
4269 blink::Performance* performance = DOMWindowPerformance::performance(*domWindow);
4270 for (size_t i = 0; i < events.size(); ++i) {
4271 if (eventType == CompositeEvent)
4272 performance->addCompositeTiming(domWindow->document(), events[i].sourceFrame, events[i].startTime);
4273 else if (eventType == RenderEvent)
4274 performance->addRenderTiming(domWindow->document(), events[i].sourceFrame, events[i].startTime, events[i].finishTime);
4278 void WebViewImpl::updateLayerTreeViewport()
4280 if (!page() || !m_layerTreeView)
4281 return;
4283 m_layerTreeView->setPageScaleFactorAndLimits(pageScaleFactor(), minimumPageScaleFactor(), maximumPageScaleFactor());
4286 void WebViewImpl::updateLayerTreeBackgroundColor()
4288 if (!m_layerTreeView)
4289 return;
4291 m_layerTreeView->setBackgroundColor(alphaChannel(m_backgroundColorOverride) ? m_backgroundColorOverride : backgroundColor());
4294 void WebViewImpl::updateLayerTreeDeviceScaleFactor()
4296 ASSERT(page());
4297 ASSERT(m_layerTreeView);
4299 float deviceScaleFactor = m_compositorDeviceScaleFactorOverride ? m_compositorDeviceScaleFactorOverride : page()->deviceScaleFactor();
4300 m_layerTreeView->setDeviceScaleFactor(deviceScaleFactor);
4303 void WebViewImpl::updateRootLayerTransform()
4305 // If we don't have a root graphics layer, we won't bother trying to find
4306 // or update the transform layer.
4307 if (!m_rootGraphicsLayer)
4308 return;
4310 if (m_rootTransformLayer) {
4311 TransformationMatrix transform;
4312 transform.translate(m_rootLayerOffset.width, m_rootLayerOffset.height);
4313 transform = transform.scale(m_rootLayerScale);
4314 m_rootTransformLayer->setTransform(transform);
4318 bool WebViewImpl::detectContentOnTouch(const GestureEventWithHitTestResults& targetedEvent)
4320 if (!m_page->mainFrame()->isLocalFrame())
4321 return false;
4323 // Need a local copy of the hit test as setToShadowHostIfInUserAgentShadowRoot() will modify it.
4324 HitTestResult touchHit = targetedEvent.hitTestResult();
4325 touchHit.setToShadowHostIfInUserAgentShadowRoot();
4327 if (touchHit.isContentEditable())
4328 return false;
4330 Node* node = touchHit.innerNode();
4331 if (!node || !node->isTextNode())
4332 return false;
4334 // Ignore when tapping on links or nodes listening to click events, unless the click event is on the
4335 // body element, in which case it's unlikely that the original node itself was intended to be clickable.
4336 for (; node && !isHTMLBodyElement(*node); node = LayoutTreeBuilderTraversal::parent(*node)) {
4337 if (node->isLink() || node->willRespondToTouchEvents() || node->willRespondToMouseClickEvents())
4338 return false;
4341 WebContentDetectionResult content = m_client->detectContentAround(touchHit);
4342 if (!content.isValid())
4343 return false;
4345 m_client->scheduleContentIntent(content.intent());
4346 return true;
4349 void WebViewImpl::setVisibilityState(WebPageVisibilityState visibilityState,
4350 bool isInitialState) {
4351 ASSERT(visibilityState == WebPageVisibilityStateVisible || visibilityState == WebPageVisibilityStateHidden || visibilityState == WebPageVisibilityStatePrerender);
4353 if (page())
4354 m_page->setVisibilityState(static_cast<PageVisibilityState>(static_cast<int>(visibilityState)), isInitialState);
4356 if (m_layerTreeView) {
4357 bool visible = visibilityState == WebPageVisibilityStateVisible;
4358 m_layerTreeView->setVisible(visible);
4362 bool WebViewImpl::requestPointerLock()
4364 return m_client && m_client->requestPointerLock();
4367 void WebViewImpl::requestPointerUnlock()
4369 if (m_client)
4370 m_client->requestPointerUnlock();
4373 bool WebViewImpl::isPointerLocked()
4375 return m_client && m_client->isPointerLocked();
4378 void WebViewImpl::pointerLockMouseEvent(const WebInputEvent& event)
4380 OwnPtr<UserGestureIndicator> gestureIndicator;
4381 AtomicString eventType;
4382 switch (event.type) {
4383 case WebInputEvent::MouseDown:
4384 eventType = EventTypeNames::mousedown;
4385 gestureIndicator = adoptPtr(new UserGestureIndicator(DefinitelyProcessingNewUserGesture));
4386 m_pointerLockGestureToken = gestureIndicator->currentToken();
4387 break;
4388 case WebInputEvent::MouseUp:
4389 eventType = EventTypeNames::mouseup;
4390 gestureIndicator = adoptPtr(new UserGestureIndicator(m_pointerLockGestureToken.release()));
4391 break;
4392 case WebInputEvent::MouseMove:
4393 eventType = EventTypeNames::mousemove;
4394 break;
4395 default:
4396 ASSERT_NOT_REACHED();
4399 const WebMouseEvent& mouseEvent = static_cast<const WebMouseEvent&>(event);
4401 if (page())
4402 page()->pointerLockController().dispatchLockedMouseEvent(
4403 PlatformMouseEventBuilder(mainFrameImpl()->frameView(), mouseEvent),
4404 eventType);
4407 bool WebViewImpl::shouldDisableDesktopWorkarounds()
4409 if (!settings()->viewportEnabled())
4410 return false;
4412 // A document is considered adapted to small screen UAs if one of these holds:
4413 // 1. The author specified viewport has a constrained width that is equal to
4414 // the initial viewport width.
4415 // 2. The author has disabled viewport zoom.
4417 const PageScaleConstraints& constraints = pageScaleConstraintsSet().pageDefinedConstraints();
4419 if (!mainFrameImpl() || !mainFrameImpl()->frameView())
4420 return false;
4422 return mainFrameImpl()->frameView()->layoutSize().width() == m_size.width
4423 || (constraints.minimumScale == constraints.maximumScale && constraints.minimumScale != -1);
4426 void WebViewImpl::forceNextWebGLContextCreationToFail()
4428 WebGLRenderingContext::forceNextWebGLContextCreationToFail();
4431 void WebViewImpl::forceNextDrawingBufferCreationToFail()
4433 DrawingBuffer::forceNextDrawingBufferCreationToFail();
4436 void WebViewImpl::updatePageOverlays()
4438 if (m_pageColorOverlay)
4439 m_pageColorOverlay->update();
4440 if (InspectorOverlayImpl* overlay = inspectorOverlay()) {
4441 PageOverlay* inspectorPageOverlay = overlay->pageOverlay();
4442 if (inspectorPageOverlay)
4443 inspectorPageOverlay->update();
4447 } // namespace blink