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
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
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.
32 #include "web/WebViewImpl.h"
34 #include "core/CSSValueKeywords.h"
35 #include "core/HTMLNames.h"
36 #include "core/accessibility/AXObjectCache.h"
37 #include "core/clipboard/DataObject.h"
38 #include "core/dom/Document.h"
39 #include "core/dom/DocumentMarkerController.h"
40 #include "core/dom/Text.h"
41 #include "core/editing/Editor.h"
42 #include "core/editing/FrameSelection.h"
43 #include "core/editing/InputMethodController.h"
44 #include "core/editing/TextIterator.h"
45 #include "core/events/KeyboardEvent.h"
46 #include "core/events/WheelEvent.h"
47 #include "core/frame/EventHandlerRegistry.h"
48 #include "core/frame/FrameHost.h"
49 #include "core/frame/FrameView.h"
50 #include "core/frame/LocalFrame.h"
51 #include "core/frame/PinchViewport.h"
52 #include "core/frame/Settings.h"
53 #include "core/frame/SmartClip.h"
54 #include "core/html/HTMLInputElement.h"
55 #include "core/html/HTMLMediaElement.h"
56 #include "core/html/HTMLPlugInElement.h"
57 #include "core/html/HTMLTextAreaElement.h"
58 #include "core/html/ime/InputMethodContext.h"
59 #include "core/inspector/InspectorController.h"
60 #include "core/loader/DocumentLoader.h"
61 #include "core/loader/FrameLoader.h"
62 #include "core/loader/UniqueIdentifier.h"
63 #include "core/page/Chrome.h"
64 #include "core/page/ContextMenuController.h"
65 #include "core/page/DragController.h"
66 #include "core/page/DragData.h"
67 #include "core/page/DragSession.h"
68 #include "core/page/EventHandler.h"
69 #include "core/page/FocusController.h"
70 #include "core/page/FrameTree.h"
71 #include "core/page/InjectedStyleSheets.h"
72 #include "core/page/Page.h"
73 #include "core/page/PagePopupClient.h"
74 #include "core/page/PointerLockController.h"
75 #include "core/page/ScopedPageLoadDeferrer.h"
76 #include "core/page/TouchDisambiguation.h"
77 #include "core/rendering/FastTextAutosizer.h"
78 #include "core/rendering/RenderView.h"
79 #include "core/rendering/RenderWidget.h"
80 #include "core/rendering/TextAutosizer.h"
81 #include "core/rendering/compositing/RenderLayerCompositor.h"
82 #include "modules/device_orientation/DeviceOrientationInspectorAgent.h"
83 #include "modules/encryptedmedia/MediaKeysController.h"
84 #include "modules/filesystem/InspectorFileSystemAgent.h"
85 #include "modules/indexeddb/InspectorIndexedDBAgent.h"
86 #include "modules/push_messaging/PushController.h"
87 #include "platform/ContextMenu.h"
88 #include "platform/ContextMenuItem.h"
89 #include "platform/Cursor.h"
90 #include "platform/KeyboardCodes.h"
91 #include "platform/NotImplemented.h"
92 #include "platform/OverscrollTheme.h"
93 #include "platform/PlatformGestureEvent.h"
94 #include "platform/PlatformKeyboardEvent.h"
95 #include "platform/PlatformMouseEvent.h"
96 #include "platform/PlatformWheelEvent.h"
97 #include "platform/PopupMenuClient.h"
98 #include "platform/RuntimeEnabledFeatures.h"
99 #include "platform/TraceEvent.h"
100 #include "platform/UserGestureIndicator.h"
101 #include "platform/exported/WebActiveGestureAnimation.h"
102 #include "platform/fonts/FontCache.h"
103 #include "platform/graphics/Color.h"
104 #include "platform/graphics/Image.h"
105 #include "platform/graphics/ImageBuffer.h"
106 #include "platform/scroll/ScrollbarTheme.h"
107 #include "platform/weborigin/SchemeRegistry.h"
108 #include "public/platform/Platform.h"
109 #include "public/platform/WebDragData.h"
110 #include "public/platform/WebFloatPoint.h"
111 #include "public/platform/WebGestureCurve.h"
112 #include "public/platform/WebImage.h"
113 #include "public/platform/WebLayerTreeView.h"
114 #include "public/platform/WebVector.h"
115 #include "public/web/WebAXObject.h"
116 #include "public/web/WebActiveWheelFlingParameters.h"
117 #include "public/web/WebAutofillClient.h"
118 #include "public/web/WebFrameClient.h"
119 #include "public/web/WebHitTestResult.h"
120 #include "public/web/WebInputElement.h"
121 #include "public/web/WebMediaPlayerAction.h"
122 #include "public/web/WebNode.h"
123 #include "public/web/WebPlugin.h"
124 #include "public/web/WebPluginAction.h"
125 #include "public/web/WebRange.h"
126 #include "public/web/WebTextInputInfo.h"
127 #include "public/web/WebViewClient.h"
128 #include "public/web/WebWindowFeatures.h"
129 #include "web/CompositionUnderlineVectorBuilder.h"
130 #include "web/ContextFeaturesClientImpl.h"
131 #include "web/DatabaseClientImpl.h"
132 #include "web/FullscreenController.h"
133 #include "web/GraphicsLayerFactoryChromium.h"
134 #include "web/LinkHighlight.h"
135 #include "web/NavigatorContentUtilsClientImpl.h"
136 #include "web/PopupContainer.h"
137 #include "web/PrerendererClientImpl.h"
138 #include "web/SpeechRecognitionClientProxy.h"
139 #include "web/StorageQuotaClientImpl.h"
140 #include "web/ValidationMessageClientImpl.h"
141 #include "web/ViewportAnchor.h"
142 #include "web/WebDevToolsAgentImpl.h"
143 #include "web/WebDevToolsAgentPrivate.h"
144 #include "web/WebInputEventConversion.h"
145 #include "web/WebLocalFrameImpl.h"
146 #include "web/WebPagePopupImpl.h"
147 #include "web/WebPluginContainerImpl.h"
148 #include "web/WebPopupMenuImpl.h"
149 #include "web/WebRemoteFrameImpl.h"
150 #include "web/WebSettingsImpl.h"
151 #include "web/WorkerGlobalScopeProxyProviderImpl.h"
152 #include "web/painting/ContinuousPainter.h"
153 #include "wtf/CurrentTime.h"
154 #include "wtf/RefPtr.h"
155 #include "wtf/TemporaryChange.h"
157 #if USE(DEFAULT_RENDER_THEME)
158 #include "core/rendering/RenderThemeChromiumDefault.h"
161 // Get rid of WTF's pow define so we can use std::pow.
163 #include <cmath> // for std::pow
165 using namespace WebCore;
167 // The following constants control parameters for automated scaling of webpages
168 // (such as due to a double tap gesture or find in page etc.). These are
169 // experimentally determined.
170 static const int touchPointPadding = 32;
171 static const int nonUserInitiatedPointPadding = 11;
172 static const float minScaleDifference = 0.01f;
173 static const float doubleTapZoomContentDefaultMargin = 5;
174 static const float doubleTapZoomContentMinimumMargin = 2;
175 static const double doubleTapZoomAnimationDurationInSeconds = 0.25;
176 static const float doubleTapZoomAlreadyLegibleRatio = 1.2f;
178 static const double multipleTargetsZoomAnimationDurationInSeconds = 0.25;
179 static const double findInPageAnimationDurationInSeconds = 0;
181 // Constants for viewport anchoring on resize.
182 static const float viewportAnchorXCoord = 0.5f;
183 static const float viewportAnchorYCoord = 0;
185 // Constants for zooming in on a focused text field.
186 static const double scrollAndScaleAnimationDurationInSeconds = 0.2;
187 static const int minReadableCaretHeight = 18;
188 static const float minScaleChangeToTriggerZoom = 1.05f;
189 static const float leftBoxRatio = 0.3f;
190 static const int caretPadding = 10;
194 // Change the text zoom level by kTextSizeMultiplierRatio each time the user
195 // zooms text in or out (ie., change by 20%). The min and max values limit
196 // text zoom to half and 3x the original text size. These three values match
197 // those in Apple's port in WebKit/WebKit/WebView/WebView.mm
198 const double WebView::textSizeMultiplierRatio = 1.2;
199 const double WebView::minTextSizeMultiplier = 0.5;
200 const double WebView::maxTextSizeMultiplier = 3.0;
202 // Used to defer all page activity in cases where the embedder wishes to run
203 // a nested event loop. Using a stack enables nesting of message loop invocations.
204 static Vector<ScopedPageLoadDeferrer*>& pageLoadDeferrerStack()
206 DEFINE_STATIC_LOCAL(Vector<ScopedPageLoadDeferrer*>, deferrerStack, ());
207 return deferrerStack;
210 // Ensure that the WebDragOperation enum values stay in sync with the original
211 // DragOperation constants.
212 #define COMPILE_ASSERT_MATCHING_ENUM(coreName) \
213 COMPILE_ASSERT(int(coreName) == int(Web##coreName), dummy##coreName)
214 COMPILE_ASSERT_MATCHING_ENUM(DragOperationNone);
215 COMPILE_ASSERT_MATCHING_ENUM(DragOperationCopy);
216 COMPILE_ASSERT_MATCHING_ENUM(DragOperationLink);
217 COMPILE_ASSERT_MATCHING_ENUM(DragOperationGeneric);
218 COMPILE_ASSERT_MATCHING_ENUM(DragOperationPrivate);
219 COMPILE_ASSERT_MATCHING_ENUM(DragOperationMove);
220 COMPILE_ASSERT_MATCHING_ENUM(DragOperationDelete);
221 COMPILE_ASSERT_MATCHING_ENUM(DragOperationEvery);
223 static bool shouldUseExternalPopupMenus = false;
225 static int webInputEventKeyStateToPlatformEventKeyState(int webInputEventKeyState)
227 int platformEventKeyState = 0;
228 if (webInputEventKeyState & WebInputEvent::ShiftKey)
229 platformEventKeyState = platformEventKeyState | WebCore::PlatformEvent::ShiftKey;
230 if (webInputEventKeyState & WebInputEvent::ControlKey)
231 platformEventKeyState = platformEventKeyState | WebCore::PlatformEvent::CtrlKey;
232 if (webInputEventKeyState & WebInputEvent::AltKey)
233 platformEventKeyState = platformEventKeyState | WebCore::PlatformEvent::AltKey;
234 if (webInputEventKeyState & WebInputEvent::MetaKey)
235 platformEventKeyState = platformEventKeyState | WebCore::PlatformEvent::MetaKey;
236 return platformEventKeyState;
241 class UserGestureNotifier {
243 // If a UserGestureIndicator is created for a user gesture during the
244 // lifetime of a UserGestureNotifier and *userGestureObserved is false,
245 // the object will notify the client and set *userGestureObserved to true.
246 UserGestureNotifier(WebAutofillClient*, bool* userGestureObserved);
247 ~UserGestureNotifier();
250 WebAutofillClient* const m_client;
251 bool* const m_userGestureObserved;
254 UserGestureNotifier::UserGestureNotifier(WebAutofillClient* client, bool* userGestureObserved)
256 , m_userGestureObserved(userGestureObserved)
258 ASSERT(m_userGestureObserved);
260 UserGestureIndicator::clearProcessedUserGestureInPast();
263 UserGestureNotifier::~UserGestureNotifier()
265 if (!*m_userGestureObserved && UserGestureIndicator::processedUserGestureInPast()) {
266 *m_userGestureObserved = true;
268 m_client->firstUserGestureObserved();
274 // WebView ----------------------------------------------------------------
276 WebView* WebView::create(WebViewClient* client)
278 // Pass the WebViewImpl's self-reference to the caller.
279 return WebViewImpl::create(client);
282 WebViewImpl* WebViewImpl::create(WebViewClient* client)
284 // Pass the WebViewImpl's self-reference to the caller.
285 return adoptRef(new WebViewImpl(client)).leakRef();
288 void WebView::setUseExternalPopupMenus(bool useExternalPopupMenus)
290 shouldUseExternalPopupMenus = useExternalPopupMenus;
293 void WebView::updateVisitedLinkState(unsigned long long linkHash)
295 Page::visitedStateChanged(linkHash);
298 void WebView::resetVisitedLinkState()
300 Page::allVisitedStateChanged();
303 void WebView::willEnterModalLoop()
305 pageLoadDeferrerStack().append(new ScopedPageLoadDeferrer());
308 void WebView::didExitModalLoop()
310 ASSERT(pageLoadDeferrerStack().size());
312 delete pageLoadDeferrerStack().last();
313 pageLoadDeferrerStack().removeLast();
316 void WebViewImpl::setMainFrame(WebFrame* frame)
318 if (frame->isWebLocalFrame())
319 toWebLocalFrameImpl(frame)->initializeAsMainFrame(page());
321 toWebRemoteFrameImpl(frame)->initializeAsMainFrame(page());
324 void WebViewImpl::setAutofillClient(WebAutofillClient* autofillClient)
326 m_autofillClient = autofillClient;
329 void WebViewImpl::setDevToolsAgentClient(WebDevToolsAgentClient* devToolsClient)
332 m_devToolsAgent = adoptPtr(new WebDevToolsAgentImpl(this, devToolsClient));
334 m_devToolsAgent.clear();
337 void WebViewImpl::setPrerendererClient(WebPrerendererClient* prerendererClient)
340 providePrerendererClientTo(*m_page, new PrerendererClientImpl(prerendererClient));
343 void WebViewImpl::setSpellCheckClient(WebSpellCheckClient* spellCheckClient)
345 m_spellCheckClient = spellCheckClient;
348 WebViewImpl::WebViewImpl(WebViewClient* client)
350 , m_autofillClient(0)
351 , m_spellCheckClient(0)
352 , m_chromeClientImpl(this)
353 , m_contextMenuClientImpl(this)
354 , m_dragClientImpl(this)
355 , m_editorClientImpl(this)
356 , m_inspectorClientImpl(this)
357 , m_backForwardClientImpl(this)
358 , m_spellCheckerClientImpl(this)
359 , m_storageClientImpl(this)
360 , m_fixedLayoutSizeLock(false)
361 , m_shouldAutoResize(false)
363 , m_minimumZoomLevel(zoomFactorToZoomLevel(minTextSizeMultiplier))
364 , m_maximumZoomLevel(zoomFactorToZoomLevel(maxTextSizeMultiplier))
365 , m_doubleTapZoomPageScaleFactor(0)
366 , m_doubleTapZoomPending(false)
367 , m_enableFakePageScaleAnimationForTesting(false)
368 , m_fakePageScaleAnimationPageScaleFactor(0)
369 , m_fakePageScaleAnimationUseAnchor(false)
370 , m_contextMenuAllowed(false)
371 , m_doingDragAndDrop(false)
372 , m_ignoreInputEvents(false)
373 , m_compositorDeviceScaleFactorOverride(0)
374 , m_rootLayerScale(1)
375 , m_suppressNextKeypressEvent(false)
376 , m_imeAcceptEvents(true)
377 , m_operationsAllowed(WebDragOperationNone)
378 , m_dragOperation(WebDragOperationNone)
379 , m_isTransparent(false)
380 , m_tabsToLinks(false)
383 , m_rootGraphicsLayer(0)
384 , m_rootTransformLayer(0)
385 , m_graphicsLayerFactory(adoptPtr(new GraphicsLayerFactoryChromium(this)))
386 , m_isAcceleratedCompositingActive(false)
387 , m_layerTreeViewCommitsDeferred(false)
388 , m_matchesHeuristicsForGpuRasterization(false)
389 , m_recreatingGraphicsContext(false)
391 , m_flingSourceDevice(false)
392 , m_fullscreenController(FullscreenController::create(this))
393 , m_showFPSCounter(false)
394 , m_showPaintRects(false)
395 , m_showDebugBorders(false)
396 , m_continuousPaintingEnabled(false)
397 , m_showScrollBottleneckRects(false)
398 , m_baseBackgroundColor(Color::white)
399 , m_backgroundColorOverride(Color::transparent)
400 , m_zoomFactorOverride(0)
401 , m_userGestureObserved(false)
403 Page::PageClients pageClients;
404 pageClients.chromeClient = &m_chromeClientImpl;
405 pageClients.contextMenuClient = &m_contextMenuClientImpl;
406 pageClients.editorClient = &m_editorClientImpl;
407 pageClients.dragClient = &m_dragClientImpl;
408 pageClients.inspectorClient = &m_inspectorClientImpl;
409 pageClients.backForwardClient = &m_backForwardClientImpl;
410 pageClients.spellCheckerClient = &m_spellCheckerClientImpl;
411 pageClients.storageClient = &m_storageClientImpl;
413 m_page = adoptPtrWillBeNoop(new Page(pageClients));
414 MediaKeysController::provideMediaKeysTo(*m_page, &m_mediaKeysClientImpl);
415 provideSpeechRecognitionTo(*m_page, SpeechRecognitionClientProxy::create(client ? client->speechRecognizer() : 0));
416 provideNavigatorContentUtilsTo(*m_page, NavigatorContentUtilsClientImpl::create(this));
418 provideContextFeaturesTo(*m_page, ContextFeaturesClientImpl::create());
419 DeviceOrientationInspectorAgent::provideTo(*m_page);
421 m_page->inspectorController().registerModuleAgent(InspectorFileSystemAgent::create(m_page.get()));
422 provideDatabaseClientTo(*m_page, DatabaseClientImpl::create());
423 InspectorIndexedDBAgent::provideTo(m_page.get());
424 provideStorageQuotaClientTo(*m_page, StorageQuotaClientImpl::create());
425 m_page->setValidationMessageClient(ValidationMessageClientImpl::create(*this));
426 provideWorkerGlobalScopeProxyProviderTo(*m_page, WorkerGlobalScopeProxyProviderImpl::create());
428 m_page->makeOrdinary();
431 providePushControllerTo(*m_page, m_client->webPushClient());
432 setDeviceScaleFactor(m_client->screenInfo().deviceScaleFactor);
433 setVisibilityState(m_client->visibilityState(), true);
436 m_inspectorSettingsMap = adoptPtr(new SettingsMap);
439 WebViewImpl::~WebViewImpl()
444 WebLocalFrameImpl* WebViewImpl::mainFrameImpl()
446 return m_page && m_page->mainFrame() && m_page->mainFrame()->isLocalFrame() ? WebLocalFrameImpl::fromFrame(m_page->deprecatedLocalMainFrame()) : 0;
449 bool WebViewImpl::tabKeyCyclesThroughElements() const
452 return m_page->tabKeyCyclesThroughElements();
455 void WebViewImpl::setTabKeyCyclesThroughElements(bool value)
458 m_page->setTabKeyCyclesThroughElements(value);
461 void WebViewImpl::handleMouseLeave(LocalFrame& mainFrame, const WebMouseEvent& event)
463 m_client->setMouseOverURL(WebURL());
464 PageWidgetEventHandler::handleMouseLeave(mainFrame, event);
467 void WebViewImpl::handleMouseDown(LocalFrame& mainFrame, const WebMouseEvent& event)
469 // If there is a popup open, close it as the user is clicking on the page (outside of the
470 // popup). We also save it so we can prevent a click on an element from immediately
471 // reopening the same popup.
472 RefPtr<PopupContainer> selectPopup;
473 RefPtr<WebPagePopupImpl> pagePopup;
474 if (event.button == WebMouseEvent::ButtonLeft) {
475 selectPopup = m_selectPopup;
476 pagePopup = m_pagePopup;
478 ASSERT(!m_selectPopup);
479 ASSERT(!m_pagePopup);
482 m_lastMouseDownPoint = WebPoint(event.x, event.y);
484 // Take capture on a mouse down on a plugin so we can send it mouse events.
485 // If the hit node is a plugin but a scrollbar is over it don't start mouse
486 // capture because it will interfere with the scrollbar receiving events.
487 IntPoint point(event.x, event.y);
488 if (event.button == WebMouseEvent::ButtonLeft && m_page->mainFrame()->isLocalFrame() && !m_page->deprecatedLocalMainFrame()->view()->scrollbarAtPoint(point)) {
489 point = m_page->deprecatedLocalMainFrame()->view()->windowToContents(point);
490 HitTestResult result(m_page->deprecatedLocalMainFrame()->eventHandler().hitTestResultAtPoint(point));
491 Node* hitNode = result.innerNonSharedNode();
493 if (!result.scrollbar() && hitNode && hitNode->renderer() && hitNode->renderer()->isEmbeddedObject()) {
494 m_mouseCaptureNode = hitNode;
495 TRACE_EVENT_ASYNC_BEGIN0("input", "capturing mouse", this);
499 PageWidgetEventHandler::handleMouseDown(mainFrame, event);
501 if (event.button == WebMouseEvent::ButtonLeft && m_mouseCaptureNode)
502 m_mouseCaptureGestureToken = mainFrame.eventHandler().takeLastMouseDownGestureToken();
504 if (m_selectPopup && m_selectPopup == selectPopup) {
505 // That click triggered a select popup which is the same as the one that
506 // was showing before the click. It means the user clicked the select
507 // while the popup was showing, and as a result we first closed then
508 // immediately reopened the select popup. It needs to be closed.
512 if (m_pagePopup && pagePopup && m_pagePopup->hasSamePopupClient(pagePopup.get())) {
513 // That click triggered a page popup that is the same as the one we just closed.
514 // It needs to be closed.
515 closePagePopup(m_pagePopup.get());
518 // Dispatch the contextmenu event regardless of if the click was swallowed.
520 // On Windows, we handle it on mouse up, not down.
522 if (event.button == WebMouseEvent::ButtonRight
523 || (event.button == WebMouseEvent::ButtonLeft
524 && event.modifiers & WebMouseEvent::ControlKey))
525 mouseContextMenu(event);
527 if (event.button == WebMouseEvent::ButtonRight)
528 mouseContextMenu(event);
532 void WebViewImpl::mouseContextMenu(const WebMouseEvent& event)
534 if (!mainFrameImpl() || !mainFrameImpl()->frameView())
537 m_page->contextMenuController().clearContextMenu();
539 PlatformMouseEventBuilder pme(mainFrameImpl()->frameView(), event);
541 // Find the right target frame. See issue 1186900.
542 HitTestResult result = hitTestResultForWindowPos(pme.position());
544 if (result.innerNonSharedNode())
545 targetFrame = result.innerNonSharedNode()->document().frame();
547 targetFrame = m_page->focusController().focusedOrMainFrame();
549 if (!targetFrame->isLocalFrame())
552 LocalFrame* targetLocalFrame = toLocalFrame(targetFrame);
555 targetLocalFrame->view()->setCursor(pointerCursor());
558 m_contextMenuAllowed = true;
559 targetLocalFrame->eventHandler().sendContextMenuEvent(pme);
560 m_contextMenuAllowed = false;
561 // Actually showing the context menu is handled by the ContextMenuClient
565 void WebViewImpl::handleMouseUp(LocalFrame& mainFrame, const WebMouseEvent& event)
567 PageWidgetEventHandler::handleMouseUp(mainFrame, event);
570 // Dispatch the contextmenu event regardless of if the click was swallowed.
571 // On Mac/Linux, we handle it on mouse down, not up.
572 if (event.button == WebMouseEvent::ButtonRight)
573 mouseContextMenu(event);
577 bool WebViewImpl::handleMouseWheel(LocalFrame& mainFrame, const WebMouseWheelEvent& event)
580 return PageWidgetEventHandler::handleMouseWheel(mainFrame, event);
583 bool WebViewImpl::scrollBy(const WebFloatSize& delta, const WebFloatSize& velocity)
585 if (m_flingSourceDevice == WebGestureDeviceTouchpad) {
586 WebMouseWheelEvent syntheticWheel;
587 const float tickDivisor = WebCore::WheelEvent::TickMultiplier;
589 syntheticWheel.deltaX = delta.width;
590 syntheticWheel.deltaY = delta.height;
591 syntheticWheel.wheelTicksX = delta.width / tickDivisor;
592 syntheticWheel.wheelTicksY = delta.height / tickDivisor;
593 syntheticWheel.hasPreciseScrollingDeltas = true;
594 syntheticWheel.x = m_positionOnFlingStart.x;
595 syntheticWheel.y = m_positionOnFlingStart.y;
596 syntheticWheel.globalX = m_globalPositionOnFlingStart.x;
597 syntheticWheel.globalY = m_globalPositionOnFlingStart.y;
598 syntheticWheel.modifiers = m_flingModifier;
600 if (m_page && m_page->mainFrame() && m_page->mainFrame()->isLocalFrame() && m_page->deprecatedLocalMainFrame()->view())
601 return handleMouseWheel(*m_page->deprecatedLocalMainFrame(), syntheticWheel);
603 WebGestureEvent syntheticGestureEvent;
605 syntheticGestureEvent.type = WebInputEvent::GestureScrollUpdateWithoutPropagation;
606 syntheticGestureEvent.data.scrollUpdate.deltaX = delta.width;
607 syntheticGestureEvent.data.scrollUpdate.deltaY = delta.height;
608 syntheticGestureEvent.x = m_positionOnFlingStart.x;
609 syntheticGestureEvent.y = m_positionOnFlingStart.y;
610 syntheticGestureEvent.globalX = m_globalPositionOnFlingStart.x;
611 syntheticGestureEvent.globalY = m_globalPositionOnFlingStart.y;
612 syntheticGestureEvent.modifiers = m_flingModifier;
613 syntheticGestureEvent.sourceDevice = WebGestureDeviceTouchscreen;
615 if (m_page && m_page->mainFrame() && m_page->mainFrame()->isLocalFrame() && m_page->deprecatedLocalMainFrame()->view())
616 return handleGestureEvent(syntheticGestureEvent);
621 bool WebViewImpl::handleGestureEvent(const WebGestureEvent& event)
623 bool eventSwallowed = false;
624 bool eventCancelled = false; // for disambiguation
626 // Special handling for slow-path fling gestures.
627 switch (event.type) {
628 case WebInputEvent::GestureFlingStart: {
629 if (mainFrameImpl()->frame()->eventHandler().isScrollbarHandlingGestures())
631 m_client->cancelScheduledContentIntents();
632 m_positionOnFlingStart = WebPoint(event.x / pageScaleFactor(), event.y / pageScaleFactor());
633 m_globalPositionOnFlingStart = WebPoint(event.globalX, event.globalY);
634 m_flingModifier = event.modifiers;
635 m_flingSourceDevice = event.sourceDevice;
636 OwnPtr<WebGestureCurve> flingCurve = adoptPtr(Platform::current()->createFlingAnimationCurve(event.sourceDevice, WebFloatPoint(event.data.flingStart.velocityX, event.data.flingStart.velocityY), WebSize()));
638 m_gestureAnimation = WebActiveGestureAnimation::createAtAnimationStart(flingCurve.release(), this);
640 eventSwallowed = true;
642 m_client->didHandleGestureEvent(event, eventCancelled);
643 return eventSwallowed;
645 case WebInputEvent::GestureFlingCancel:
646 if (endActiveFlingAnimation())
647 eventSwallowed = true;
649 m_client->didHandleGestureEvent(event, eventCancelled);
650 return eventSwallowed;
655 PlatformGestureEventBuilder platformEvent(mainFrameImpl()->frameView(), event);
657 // Handle link highlighting outside the main switch to avoid getting lost in the
658 // complicated set of cases handled below.
659 switch (event.type) {
660 case WebInputEvent::GestureShowPress:
661 // Queue a highlight animation, then hand off to regular handler.
662 if (settingsImpl()->gestureTapHighlightEnabled())
663 enableTapHighlightAtPoint(platformEvent);
665 case WebInputEvent::GestureTapCancel:
666 case WebInputEvent::GestureTap:
667 case WebInputEvent::GestureLongPress:
668 for (size_t i = 0; i < m_linkHighlights.size(); ++i)
669 m_linkHighlights[i]->startHighlightAnimationIfNeeded();
675 switch (event.type) {
676 case WebInputEvent::GestureTap: {
677 m_client->cancelScheduledContentIntents();
678 if (detectContentOnTouch(platformEvent.position())) {
679 eventSwallowed = true;
683 RefPtr<PopupContainer> selectPopup;
684 selectPopup = m_selectPopup;
686 ASSERT(!m_selectPopup);
688 // Don't trigger a disambiguation popup on sites designed for mobile devices.
689 // Instead, assume that the page has been designed with big enough buttons and links.
690 if (event.data.tap.width > 0 && !shouldDisableDesktopWorkarounds()) {
691 // FIXME: didTapMultipleTargets should just take a rect instead of
693 WebGestureEvent scaledEvent = event;
694 scaledEvent.x = event.x / pageScaleFactor();
695 scaledEvent.y = event.y / pageScaleFactor();
696 scaledEvent.data.tap.width = event.data.tap.width / pageScaleFactor();
697 scaledEvent.data.tap.height = event.data.tap.height / pageScaleFactor();
698 IntRect boundingBox(scaledEvent.x - scaledEvent.data.tap.width / 2, scaledEvent.y - scaledEvent.data.tap.height / 2, scaledEvent.data.tap.width, scaledEvent.data.tap.height);
699 Vector<IntRect> goodTargets;
700 WillBeHeapVector<RawPtrWillBeMember<Node> > highlightNodes;
701 findGoodTouchTargets(boundingBox, mainFrameImpl()->frame(), goodTargets, highlightNodes);
702 // FIXME: replace touch adjustment code when numberOfGoodTargets == 1?
703 // Single candidate case is currently handled by: https://bugs.webkit.org/show_bug.cgi?id=85101
704 if (goodTargets.size() >= 2 && m_client && m_client->didTapMultipleTargets(scaledEvent, goodTargets)) {
705 if (settingsImpl()->gestureTapHighlightEnabled())
706 enableTapHighlights(highlightNodes);
707 for (size_t i = 0; i < m_linkHighlights.size(); ++i)
708 m_linkHighlights[i]->startHighlightAnimationIfNeeded();
709 eventSwallowed = true;
710 eventCancelled = true;
715 eventSwallowed = mainFrameImpl()->frame()->eventHandler().handleGestureEvent(platformEvent);
717 if (m_selectPopup && m_selectPopup == selectPopup) {
718 // That tap triggered a select popup which is the same as the one that
719 // was showing before the tap. It means the user tapped the select
720 // while the popup was showing, and as a result we first closed then
721 // immediately reopened the select popup. It needs to be closed.
727 case WebInputEvent::GestureTwoFingerTap:
728 case WebInputEvent::GestureLongPress:
729 case WebInputEvent::GestureLongTap: {
730 if (!mainFrameImpl() || !mainFrameImpl()->frameView())
733 m_client->cancelScheduledContentIntents();
734 m_page->contextMenuController().clearContextMenu();
735 m_contextMenuAllowed = true;
736 eventSwallowed = mainFrameImpl()->frame()->eventHandler().handleGestureEvent(platformEvent);
737 m_contextMenuAllowed = false;
741 case WebInputEvent::GestureShowPress: {
742 m_client->cancelScheduledContentIntents();
743 eventSwallowed = mainFrameImpl()->frame()->eventHandler().handleGestureEvent(platformEvent);
746 case WebInputEvent::GestureDoubleTap:
747 if (m_webSettings->doubleTapToZoomEnabled() && minimumPageScaleFactor() != maximumPageScaleFactor()) {
748 m_client->cancelScheduledContentIntents();
749 animateDoubleTapZoom(platformEvent.position());
751 // GestureDoubleTap is currently only used by Android for zooming. For WebCore,
752 // GestureTap with tap count = 2 is used instead. So we drop GestureDoubleTap here.
753 eventSwallowed = true;
755 case WebInputEvent::GestureScrollBegin:
756 case WebInputEvent::GesturePinchBegin:
757 m_client->cancelScheduledContentIntents();
758 case WebInputEvent::GestureTapDown:
759 case WebInputEvent::GestureScrollEnd:
760 case WebInputEvent::GestureScrollUpdate:
761 case WebInputEvent::GestureScrollUpdateWithoutPropagation:
762 case WebInputEvent::GestureTapCancel:
763 case WebInputEvent::GestureTapUnconfirmed:
764 case WebInputEvent::GesturePinchEnd:
765 case WebInputEvent::GesturePinchUpdate:
766 case WebInputEvent::GestureFlingStart: {
767 eventSwallowed = mainFrameImpl()->frame()->eventHandler().handleGestureEvent(platformEvent);
771 ASSERT_NOT_REACHED();
773 m_client->didHandleGestureEvent(event, eventCancelled);
774 return eventSwallowed;
777 void WebViewImpl::transferActiveWheelFlingAnimation(const WebActiveWheelFlingParameters& parameters)
779 TRACE_EVENT0("webkit", "WebViewImpl::transferActiveWheelFlingAnimation");
780 ASSERT(!m_gestureAnimation);
781 m_positionOnFlingStart = parameters.point;
782 m_globalPositionOnFlingStart = parameters.globalPoint;
783 m_flingModifier = parameters.modifiers;
784 OwnPtr<WebGestureCurve> curve = adoptPtr(Platform::current()->createFlingAnimationCurve(parameters.sourceDevice, WebFloatPoint(parameters.delta), parameters.cumulativeScroll));
786 m_gestureAnimation = WebActiveGestureAnimation::createWithTimeOffset(curve.release(), this, parameters.startTime);
790 bool WebViewImpl::endActiveFlingAnimation()
792 if (m_gestureAnimation) {
793 m_gestureAnimation.clear();
795 m_layerTreeView->didStopFlinging();
801 bool WebViewImpl::startPageScaleAnimation(const IntPoint& targetPosition, bool useAnchor, float newScale, double durationInSeconds)
803 WebPoint clampedPoint = targetPosition;
805 clampedPoint = clampOffsetAtScale(targetPosition, newScale);
806 if (!durationInSeconds) {
807 setPageScaleFactor(newScale, clampedPoint);
811 if (useAnchor && newScale == pageScaleFactor())
814 if (m_enableFakePageScaleAnimationForTesting) {
815 m_fakePageScaleAnimationTargetPosition = targetPosition;
816 m_fakePageScaleAnimationUseAnchor = useAnchor;
817 m_fakePageScaleAnimationPageScaleFactor = newScale;
819 if (!m_layerTreeView)
821 m_layerTreeView->startPageScaleAnimation(targetPosition, useAnchor, newScale, durationInSeconds);
826 void WebViewImpl::enableFakePageScaleAnimationForTesting(bool enable)
828 m_enableFakePageScaleAnimationForTesting = enable;
831 void WebViewImpl::setShowFPSCounter(bool show)
833 if (m_layerTreeView) {
834 TRACE_EVENT0("webkit", "WebViewImpl::setShowFPSCounter");
835 m_layerTreeView->setShowFPSCounter(show);
837 m_showFPSCounter = show;
840 void WebViewImpl::setShowPaintRects(bool show)
842 if (m_layerTreeView) {
843 TRACE_EVENT0("webkit", "WebViewImpl::setShowPaintRects");
844 m_layerTreeView->setShowPaintRects(show);
846 m_showPaintRects = show;
849 void WebViewImpl::setShowDebugBorders(bool show)
852 m_layerTreeView->setShowDebugBorders(show);
853 m_showDebugBorders = show;
856 void WebViewImpl::setContinuousPaintingEnabled(bool enabled)
858 if (m_layerTreeView) {
859 TRACE_EVENT0("webkit", "WebViewImpl::setContinuousPaintingEnabled");
860 m_layerTreeView->setContinuousPaintingEnabled(enabled);
862 m_continuousPaintingEnabled = enabled;
863 m_client->scheduleAnimation();
866 void WebViewImpl::setShowScrollBottleneckRects(bool show)
869 m_layerTreeView->setShowScrollBottleneckRects(show);
870 m_showScrollBottleneckRects = show;
873 void WebViewImpl::getSelectionRootBounds(WebRect& bounds) const
875 const Frame* frame = focusedWebCoreFrame();
876 if (!frame || !frame->isLocalFrame())
879 Element* root = toLocalFrame(frame)->selection().rootEditableElementOrDocumentElement();
883 // If the selection is inside a form control, the root will be a <div> that
884 // behaves as the editor but we want to return the actual element's bounds.
885 // In practice, that means <textarea> and <input> controls that behave like
887 Element* shadowHost = root->shadowHost();
889 && (isHTMLTextAreaElement(*shadowHost)
890 || (isHTMLInputElement(*shadowHost)
891 && toHTMLInputElement(*shadowHost).isText())))
894 IntRect boundingBox = isHTMLHtmlElement(root)
895 ? IntRect(IntPoint(0, 0), root->document().frame()->view()->contentsSize())
896 : root->pixelSnappedBoundingBox();
898 boundingBox = root->document().frame()->view()->contentsToWindow(boundingBox);
899 boundingBox.scale(pageScaleFactor());
900 bounds = boundingBox;
903 void WebViewImpl::acceptLanguagesChanged()
908 page()->acceptLanguagesChanged();
911 bool WebViewImpl::handleKeyEvent(const WebKeyboardEvent& event)
913 ASSERT((event.type == WebInputEvent::RawKeyDown)
914 || (event.type == WebInputEvent::KeyDown)
915 || (event.type == WebInputEvent::KeyUp));
917 // Halt an in-progress fling on a key event.
918 endActiveFlingAnimation();
920 // Please refer to the comments explaining the m_suppressNextKeypressEvent
922 // The m_suppressNextKeypressEvent is set if the KeyDown is handled by
923 // Webkit. A keyDown event is typically associated with a keyPress(char)
924 // event and a keyUp event. We reset this flag here as this is a new keyDown
926 m_suppressNextKeypressEvent = false;
928 // If there is a select popup, it should be the one processing the event,
931 return m_selectPopup->handleKeyEvent(PlatformKeyboardEventBuilder(event));
933 m_pagePopup->handleKeyEvent(PlatformKeyboardEventBuilder(event));
934 // We need to ignore the next Char event after this otherwise pressing
935 // enter when selecting an item in the popup will go to the page.
936 if (WebInputEvent::RawKeyDown == event.type)
937 m_suppressNextKeypressEvent = true;
941 RefPtr<Frame> focusedFrame = focusedWebCoreFrame();
942 if (focusedFrame && focusedFrame->isRemoteFrameTemporary()) {
943 WebLocalFrameImpl* webFrame = WebLocalFrameImpl::fromFrame(toLocalFrameTemporary(focusedFrame.get()));
944 webFrame->client()->forwardInputEvent(&event);
948 if (!focusedFrame || !focusedFrame->isLocalFrame())
951 RefPtr<LocalFrame> frame = toLocalFrame(focusedFrame.get());
953 PlatformKeyboardEventBuilder evt(event);
955 if (frame->eventHandler().keyEvent(evt)) {
956 if (WebInputEvent::RawKeyDown == event.type) {
957 // Suppress the next keypress event unless the focused node is a plug-in node.
958 // (Flash needs these keypress events to handle non-US keyboards.)
959 Element* element = focusedElement();
960 if (!element || !element->renderer() || !element->renderer()->isEmbeddedObject())
961 m_suppressNextKeypressEvent = true;
967 const WebInputEvent::Type contextMenuTriggeringEventType =
969 WebInputEvent::KeyUp;
971 WebInputEvent::RawKeyDown;
974 bool isUnmodifiedMenuKey = !(event.modifiers & WebInputEvent::InputModifiers) && event.windowsKeyCode == VKEY_APPS;
975 bool isShiftF10 = event.modifiers == WebInputEvent::ShiftKey && event.windowsKeyCode == VKEY_F10;
976 if ((isUnmodifiedMenuKey || isShiftF10) && event.type == contextMenuTriggeringEventType) {
977 sendContextMenuEvent(event);
980 #endif // !OS(MACOSX)
982 return keyEventDefault(event);
985 bool WebViewImpl::handleCharEvent(const WebKeyboardEvent& event)
987 ASSERT(event.type == WebInputEvent::Char);
989 // Please refer to the comments explaining the m_suppressNextKeypressEvent
990 // member. The m_suppressNextKeypressEvent is set if the KeyDown is
991 // handled by Webkit. A keyDown event is typically associated with a
992 // keyPress(char) event and a keyUp event. We reset this flag here as it
993 // only applies to the current keyPress event.
994 bool suppress = m_suppressNextKeypressEvent;
995 m_suppressNextKeypressEvent = false;
997 // If there is a select popup, it should be the one processing the event,
1000 return m_selectPopup->handleKeyEvent(PlatformKeyboardEventBuilder(event));
1002 return m_pagePopup->handleKeyEvent(PlatformKeyboardEventBuilder(event));
1004 LocalFrame* frame = toLocalFrame(focusedWebCoreFrame());
1008 EventHandler& handler = frame->eventHandler();
1010 PlatformKeyboardEventBuilder evt(event);
1011 if (!evt.isCharacterKey())
1014 // Accesskeys are triggered by char events and can't be suppressed.
1015 if (handler.handleAccessKey(evt))
1018 // Safari 3.1 does not pass off windows system key messages (WM_SYSCHAR) to
1019 // the eventHandler::keyEvent. We mimic this behavior on all platforms since
1020 // for now we are converting other platform's key events to windows key
1022 if (evt.isSystemKey())
1025 if (!suppress && !handler.keyEvent(evt))
1026 return keyEventDefault(event);
1031 WebRect WebViewImpl::computeBlockBounds(const WebRect& rect, bool ignoreClipping)
1033 if (!mainFrameImpl())
1036 // Use the rect-based hit test to find the node.
1037 IntPoint point = mainFrameImpl()->frameView()->windowToContents(IntPoint(rect.x, rect.y));
1038 HitTestRequest::HitTestRequestType hitType = HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent | (ignoreClipping ? HitTestRequest::IgnoreClipping : 0);
1039 HitTestResult result = mainFrameImpl()->frame()->eventHandler().hitTestResultAtPoint(point, hitType, IntSize(rect.width, rect.height));
1041 Node* node = result.innerNonSharedNode();
1045 // Find the block type node based on the hit node.
1046 while (node && (!node->renderer() || node->renderer()->isInline()))
1047 node = node->parentNode();
1049 // Return the bounding box in the window coordinate system.
1051 IntRect rect = node->Node::pixelSnappedBoundingBox();
1052 LocalFrame* frame = node->document().frame();
1053 return frame->view()->contentsToWindow(rect);
1058 WebRect WebViewImpl::widenRectWithinPageBounds(const WebRect& source, int targetMargin, int minimumMargin)
1062 maxSize = mainFrame()->contentsSize();
1063 IntSize scrollOffset;
1065 scrollOffset = mainFrame()->scrollOffset();
1066 int leftMargin = targetMargin;
1067 int rightMargin = targetMargin;
1069 const int absoluteSourceX = source.x + scrollOffset.width();
1070 if (leftMargin > absoluteSourceX) {
1071 leftMargin = absoluteSourceX;
1072 rightMargin = std::max(leftMargin, minimumMargin);
1075 const int maximumRightMargin = maxSize.width - (source.width + absoluteSourceX);
1076 if (rightMargin > maximumRightMargin) {
1077 rightMargin = maximumRightMargin;
1078 leftMargin = std::min(leftMargin, std::max(rightMargin, minimumMargin));
1081 const int newWidth = source.width + leftMargin + rightMargin;
1082 const int newX = source.x - leftMargin;
1084 ASSERT(newWidth >= 0);
1085 ASSERT(scrollOffset.width() + newX + newWidth <= maxSize.width);
1087 return WebRect(newX, source.y, newWidth, source.height);
1090 float WebViewImpl::legibleScale() const
1092 // Pages should be as legible as on desktop when at dpi scale, so no
1093 // need to zoom in further when automatically determining zoom level
1094 // (after double tap, find in page, etc), though the user should still
1095 // be allowed to manually pinch zoom in further if they desire.
1096 float legibleScale = 1;
1098 legibleScale *= page()->settings().accessibilityFontScaleFactor();
1099 return legibleScale;
1102 void WebViewImpl::computeScaleAndScrollForBlockRect(const WebPoint& hitPoint, const WebRect& blockRect, float padding, float defaultScaleWhenAlreadyLegible, float& scale, WebPoint& scroll)
1104 scale = pageScaleFactor();
1105 scroll.x = scroll.y = 0;
1107 WebRect rect = blockRect;
1109 if (!rect.isEmpty()) {
1110 float defaultMargin = doubleTapZoomContentDefaultMargin;
1111 float minimumMargin = doubleTapZoomContentMinimumMargin;
1112 // We want the margins to have the same physical size, which means we
1113 // need to express them in post-scale size. To do that we'd need to know
1114 // the scale we're scaling to, but that depends on the margins. Instead
1115 // we express them as a fraction of the target rectangle: this will be
1116 // correct if we end up fully zooming to it, and won't matter if we
1118 rect = widenRectWithinPageBounds(rect,
1119 static_cast<int>(defaultMargin * rect.width / m_size.width),
1120 static_cast<int>(minimumMargin * rect.width / m_size.width));
1121 // Fit block to screen, respecting limits.
1122 scale = static_cast<float>(m_size.width) / rect.width;
1123 scale = std::min(scale, legibleScale());
1124 if (pageScaleFactor() < defaultScaleWhenAlreadyLegible)
1125 scale = std::max(scale, defaultScaleWhenAlreadyLegible);
1126 scale = clampPageScaleFactorToLimits(scale);
1129 // FIXME: If this is being called for auto zoom during find in page,
1130 // then if the user manually zooms in it'd be nice to preserve the
1131 // relative increase in zoom they caused (if they zoom out then it's ok
1132 // to zoom them back in again). This isn't compatible with our current
1133 // double-tap zoom strategy (fitting the containing block to the screen)
1136 float screenWidth = m_size.width / scale;
1137 float screenHeight = m_size.height / scale;
1139 // Scroll to vertically align the block.
1140 if (rect.height < screenHeight) {
1141 // Vertically center short blocks.
1142 rect.y -= 0.5 * (screenHeight - rect.height);
1144 // Ensure position we're zooming to (+ padding) isn't off the bottom of
1146 rect.y = std::max<float>(rect.y, hitPoint.y + padding - screenHeight);
1147 } // Otherwise top align the block.
1149 // Do the same thing for horizontal alignment.
1150 if (rect.width < screenWidth)
1151 rect.x -= 0.5 * (screenWidth - rect.width);
1153 rect.x = std::max<float>(rect.x, hitPoint.x + padding - screenWidth);
1157 scale = clampPageScaleFactorToLimits(scale);
1158 scroll = mainFrameImpl()->frameView()->windowToContents(scroll);
1159 scroll = clampOffsetAtScale(scroll, scale);
1162 static bool invokesHandCursor(Node* node, LocalFrame* frame)
1164 if (!node || !node->renderer())
1167 ECursor cursor = node->renderer()->style()->cursor();
1168 return cursor == CURSOR_POINTER
1169 || (cursor == CURSOR_AUTO && frame->eventHandler().useHandCursor(node, node->isLink()));
1172 Node* WebViewImpl::bestTapNode(const PlatformGestureEvent& tapEvent)
1174 if (!m_page || !m_page->mainFrame() || !m_page->mainFrame()->isLocalFrame())
1177 Node* bestTouchNode = 0;
1179 IntPoint touchEventLocation(tapEvent.position());
1180 m_page->deprecatedLocalMainFrame()->eventHandler().adjustGesturePosition(tapEvent, touchEventLocation);
1182 IntPoint hitTestPoint = m_page->deprecatedLocalMainFrame()->view()->windowToContents(touchEventLocation);
1183 HitTestResult result = m_page->deprecatedLocalMainFrame()->eventHandler().hitTestResultAtPoint(hitTestPoint, HitTestRequest::TouchEvent | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
1184 bestTouchNode = result.targetNode();
1186 // We might hit something like an image map that has no renderer on it
1187 // Walk up the tree until we have a node with an attached renderer
1188 while (bestTouchNode && !bestTouchNode->renderer())
1189 bestTouchNode = bestTouchNode->parentNode();
1191 // Check if we're in the subtree of a node with a hand cursor
1192 // this is the heuristic we use to determine if we show a highlight on tap
1193 while (bestTouchNode && !invokesHandCursor(bestTouchNode, m_page->deprecatedLocalMainFrame()))
1194 bestTouchNode = bestTouchNode->parentNode();
1199 // We should pick the largest enclosing node with hand cursor set.
1200 while (bestTouchNode->parentNode() && invokesHandCursor(bestTouchNode->parentNode(), toLocalFrame(m_page->mainFrame())))
1201 bestTouchNode = bestTouchNode->parentNode();
1203 return bestTouchNode;
1206 void WebViewImpl::enableTapHighlightAtPoint(const PlatformGestureEvent& tapEvent)
1208 Node* touchNode = bestTapNode(tapEvent);
1210 WillBeHeapVector<RawPtrWillBeMember<Node> > highlightNodes;
1211 highlightNodes.append(touchNode);
1213 enableTapHighlights(highlightNodes);
1216 void WebViewImpl::enableTapHighlights(WillBeHeapVector<RawPtrWillBeMember<Node> >& highlightNodes)
1218 if (highlightNodes.isEmpty())
1221 // Always clear any existing highlight when this is invoked, even if we
1222 // don't get a new target to highlight.
1223 m_linkHighlights.clear();
1225 // LinkHighlight reads out layout and compositing state, so we need to make sure that's all up to date.
1228 for (size_t i = 0; i < highlightNodes.size(); ++i) {
1229 Node* node = highlightNodes[i];
1231 if (!node || !node->renderer())
1234 Color highlightColor = node->renderer()->style()->tapHighlightColor();
1235 // Safari documentation for -webkit-tap-highlight-color says if the specified color has 0 alpha,
1236 // then tap highlighting is disabled.
1237 // http://developer.apple.com/library/safari/#documentation/appleapplications/reference/safaricssref/articles/standardcssproperties.html
1238 if (!highlightColor.alpha())
1241 m_linkHighlights.append(LinkHighlight::create(node, this));
1245 void WebViewImpl::animateDoubleTapZoom(const IntPoint& point)
1247 if (!mainFrameImpl())
1250 WebRect rect(point.x(), point.y(), touchPointPadding, touchPointPadding);
1251 WebRect blockBounds = computeBlockBounds(rect, false);
1256 computeScaleAndScrollForBlockRect(point, blockBounds, touchPointPadding, minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio, scale, scroll);
1258 bool stillAtPreviousDoubleTapScale = (pageScaleFactor() == m_doubleTapZoomPageScaleFactor
1259 && m_doubleTapZoomPageScaleFactor != minimumPageScaleFactor())
1260 || m_doubleTapZoomPending;
1262 bool scaleUnchanged = fabs(pageScaleFactor() - scale) < minScaleDifference;
1263 bool shouldZoomOut = blockBounds.isEmpty() || scaleUnchanged || stillAtPreviousDoubleTapScale;
1267 if (shouldZoomOut) {
1268 scale = minimumPageScaleFactor();
1269 isAnimating = startPageScaleAnimation(mainFrameImpl()->frameView()->windowToContents(point), true, scale, doubleTapZoomAnimationDurationInSeconds);
1271 isAnimating = startPageScaleAnimation(scroll, false, scale, doubleTapZoomAnimationDurationInSeconds);
1275 m_doubleTapZoomPageScaleFactor = scale;
1276 m_doubleTapZoomPending = true;
1280 void WebViewImpl::zoomToFindInPageRect(const WebRect& rect)
1282 if (!mainFrameImpl())
1285 WebRect blockBounds = computeBlockBounds(rect, true);
1287 if (blockBounds.isEmpty()) {
1288 // Keep current scale (no need to scroll as x,y will normally already
1289 // be visible). FIXME: Revisit this if it isn't always true.
1296 computeScaleAndScrollForBlockRect(WebPoint(rect.x, rect.y), blockBounds, nonUserInitiatedPointPadding, minimumPageScaleFactor(), scale, scroll);
1298 startPageScaleAnimation(scroll, false, scale, findInPageAnimationDurationInSeconds);
1301 bool WebViewImpl::zoomToMultipleTargetsRect(const WebRect& rect)
1303 if (!mainFrameImpl())
1309 computeScaleAndScrollForBlockRect(WebPoint(rect.x, rect.y), rect, nonUserInitiatedPointPadding, minimumPageScaleFactor(), scale, scroll);
1311 if (scale <= pageScaleFactor())
1314 startPageScaleAnimation(scroll, false, scale, multipleTargetsZoomAnimationDurationInSeconds);
1318 void WebViewImpl::hasTouchEventHandlers(bool hasTouchHandlers)
1321 m_client->hasTouchEventHandlers(hasTouchHandlers);
1324 bool WebViewImpl::hasTouchEventHandlersAt(const WebPoint& point)
1326 // FIXME: Implement this. Note that the point must be divided by pageScaleFactor.
1331 // Mac has no way to open a context menu based on a keyboard event.
1332 bool WebViewImpl::sendContextMenuEvent(const WebKeyboardEvent& event)
1334 // The contextMenuController() holds onto the last context menu that was
1335 // popped up on the page until a new one is created. We need to clear
1336 // this menu before propagating the event through the DOM so that we can
1337 // detect if we create a new menu for this event, since we won't create
1338 // a new menu if the DOM swallows the event and the defaultEventHandler does
1340 page()->contextMenuController().clearContextMenu();
1342 m_contextMenuAllowed = true;
1343 Frame* focusedFrame = page()->focusController().focusedOrMainFrame();
1344 if (!focusedFrame->isLocalFrame())
1346 bool handled = toLocalFrame(focusedFrame)->eventHandler().sendContextMenuEventForKey();
1347 m_contextMenuAllowed = false;
1352 bool WebViewImpl::keyEventDefault(const WebKeyboardEvent& event)
1354 LocalFrame* frame = toLocalFrame(focusedWebCoreFrame());
1358 switch (event.type) {
1359 case WebInputEvent::Char:
1360 if (event.windowsKeyCode == VKEY_SPACE) {
1361 int keyCode = ((event.modifiers & WebInputEvent::ShiftKey) ? VKEY_PRIOR : VKEY_NEXT);
1362 return scrollViewWithKeyboard(keyCode, event.modifiers);
1365 case WebInputEvent::RawKeyDown:
1366 if (event.modifiers == WebInputEvent::ControlKey) {
1367 switch (event.windowsKeyCode) {
1370 focusedFrame()->executeCommand(WebString::fromUTF8("SelectAll"));
1374 focusedFrame()->executeCommand(WebString::fromUTF8("Copy"));
1377 // Match FF behavior in the sense that Ctrl+home/end are the only Ctrl
1378 // key combinations which affect scrolling. Safari is buggy in the
1379 // sense that it scrolls the page for all Ctrl+scrolling key
1380 // combinations. For e.g. Ctrl+pgup/pgdn/up/down, etc.
1388 if (!event.isSystemKey && !(event.modifiers & WebInputEvent::ShiftKey))
1389 return scrollViewWithKeyboard(event.windowsKeyCode, event.modifiers);
1397 bool WebViewImpl::scrollViewWithKeyboard(int keyCode, int modifiers)
1399 ScrollDirection scrollDirection;
1400 ScrollGranularity scrollGranularity;
1402 // Control-Up/Down should be PageUp/Down on Mac.
1403 if (modifiers & WebMouseEvent::ControlKey) {
1404 if (keyCode == VKEY_UP)
1405 keyCode = VKEY_PRIOR;
1406 else if (keyCode == VKEY_DOWN)
1407 keyCode = VKEY_NEXT;
1410 if (!mapKeyCodeForScroll(keyCode, &scrollDirection, &scrollGranularity))
1412 return bubblingScroll(scrollDirection, scrollGranularity);
1415 bool WebViewImpl::mapKeyCodeForScroll(int keyCode,
1416 WebCore::ScrollDirection* scrollDirection,
1417 WebCore::ScrollGranularity* scrollGranularity)
1421 *scrollDirection = ScrollLeft;
1422 *scrollGranularity = ScrollByLine;
1425 *scrollDirection = ScrollRight;
1426 *scrollGranularity = ScrollByLine;
1429 *scrollDirection = ScrollUp;
1430 *scrollGranularity = ScrollByLine;
1433 *scrollDirection = ScrollDown;
1434 *scrollGranularity = ScrollByLine;
1437 *scrollDirection = ScrollUp;
1438 *scrollGranularity = ScrollByDocument;
1441 *scrollDirection = ScrollDown;
1442 *scrollGranularity = ScrollByDocument;
1444 case VKEY_PRIOR: // page up
1445 *scrollDirection = ScrollUp;
1446 *scrollGranularity = ScrollByPage;
1448 case VKEY_NEXT: // page down
1449 *scrollDirection = ScrollDown;
1450 *scrollGranularity = ScrollByPage;
1459 void WebViewImpl::hideSelectPopup()
1462 m_selectPopup->hidePopup();
1465 bool WebViewImpl::bubblingScroll(ScrollDirection scrollDirection, ScrollGranularity scrollGranularity)
1467 LocalFrame* frame = toLocalFrame(focusedWebCoreFrame());
1471 return frame->eventHandler().bubblingScroll(scrollDirection, scrollGranularity);
1474 void WebViewImpl::popupOpened(PopupContainer* popupContainer)
1476 ASSERT(!m_selectPopup);
1477 m_selectPopup = popupContainer;
1478 ASSERT(mainFrameImpl()->frame()->document());
1479 Document& document = *mainFrameImpl()->frame()->document();
1480 page()->frameHost().eventHandlerRegistry().didAddEventHandler(document, EventHandlerRegistry::WheelEvent);
1483 void WebViewImpl::popupClosed(PopupContainer* popupContainer)
1485 ASSERT(m_selectPopup);
1486 m_selectPopup = nullptr;
1487 ASSERT(mainFrameImpl()->frame()->document());
1488 Document& document = *mainFrameImpl()->frame()->document();
1489 // Remove the handler we added in |popupOpened| conditionally, because the
1490 // Document may have already removed it, for instance, due to a navigation.
1491 EventHandlerRegistry* registry = &document.frameHost()->eventHandlerRegistry();
1492 if (registry->eventHandlerTargets(EventHandlerRegistry::WheelEvent)->contains(&document))
1493 registry->didRemoveEventHandler(document, EventHandlerRegistry::WheelEvent);
1496 PagePopup* WebViewImpl::openPagePopup(PagePopupClient* client, const IntRect& originBoundsInRootView)
1499 if (hasOpenedPopup())
1501 ASSERT(!m_pagePopup);
1503 WebWidget* popupWidget = m_client->createPopupMenu(WebPopupTypePage);
1504 ASSERT(popupWidget);
1505 m_pagePopup = toWebPagePopupImpl(popupWidget);
1506 if (!m_pagePopup->initialize(this, client, originBoundsInRootView)) {
1507 m_pagePopup->closePopup();
1508 m_pagePopup = nullptr;
1510 return m_pagePopup.get();
1513 void WebViewImpl::closePagePopup(PagePopup* popup)
1516 WebPagePopupImpl* popupImpl = toWebPagePopupImpl(popup);
1517 ASSERT(m_pagePopup.get() == popupImpl);
1518 if (m_pagePopup.get() != popupImpl)
1520 m_pagePopup->closePopup();
1521 m_pagePopup = nullptr;
1524 Frame* WebViewImpl::focusedWebCoreFrame() const
1526 return m_page ? m_page->focusController().focusedOrMainFrame() : 0;
1529 WebViewImpl* WebViewImpl::fromPage(Page* page)
1533 return static_cast<WebViewImpl*>(page->chrome().client().webView());
1536 // WebWidget ------------------------------------------------------------------
1538 void WebViewImpl::close()
1541 // Initiate shutdown for the entire frameset. This will cause a lot of
1542 // notifications to be sent.
1543 m_page->willBeDestroyed();
1547 // Should happen after m_page.clear().
1548 if (m_devToolsAgent)
1549 m_devToolsAgent.clear();
1551 // Reset the delegate to prevent notifications being sent as we're being
1555 deref(); // Balances ref() acquired in WebView::create
1558 void WebViewImpl::willStartLiveResize()
1560 if (mainFrameImpl() && mainFrameImpl()->frameView())
1561 mainFrameImpl()->frameView()->willStartLiveResize();
1563 LocalFrame* frame = mainFrameImpl()->frame();
1564 WebPluginContainerImpl* pluginContainer = WebLocalFrameImpl::pluginContainerFromFrame(frame);
1565 if (pluginContainer)
1566 pluginContainer->willStartLiveResize();
1569 WebSize WebViewImpl::size()
1574 void WebViewImpl::resizePinchViewport(const WebSize& newSize)
1576 if (!pinchVirtualViewportEnabled())
1579 page()->frameHost().pinchViewport().setSize(newSize);
1582 void WebViewImpl::resize(const WebSize& newSize)
1584 if (m_shouldAutoResize || m_size == newSize)
1587 FrameView* view = mainFrameImpl()->frameView();
1591 WebSize oldSize = m_size;
1592 float oldPageScaleFactor = pageScaleFactor();
1593 int oldContentsWidth = contentsSize().width();
1597 bool shouldAnchorAndRescaleViewport = settings()->mainFrameResizesAreOrientationChanges()
1598 && oldSize.width && oldContentsWidth && newSize.width != oldSize.width && !m_fullscreenController->isFullscreen();
1600 ViewportAnchor viewportAnchor(&mainFrameImpl()->frame()->eventHandler());
1601 if (shouldAnchorAndRescaleViewport) {
1602 viewportAnchor.setAnchor(view->visibleContentRect(),
1603 FloatSize(viewportAnchorXCoord, viewportAnchorYCoord));
1607 // Avoids unnecessary invalidations while various bits of state in FastTextAutosizer are updated.
1608 FastTextAutosizer::DeferUpdatePageInfo deferUpdatePageInfo(page());
1610 m_pageScaleConstraintsSet.didChangeViewSize(m_size);
1612 updatePageDefinedViewportConstraints(mainFrameImpl()->frame()->document()->viewportDescription());
1613 updateMainFrameLayoutSize();
1615 // If the virtual viewport pinch mode is enabled, the main frame will be resized
1616 // after layout so it can be sized to the contentsSize.
1617 if (!pinchVirtualViewportEnabled() && mainFrameImpl()->frameView())
1618 mainFrameImpl()->frameView()->resize(m_size);
1620 if (pinchVirtualViewportEnabled())
1621 page()->frameHost().pinchViewport().setSize(m_size);
1623 // When device emulation is enabled, device size values may change - they are
1624 // usually set equal to the view size. These values are not considered viewport-dependent
1625 // (see MediaQueryExp::isViewportDependent), since they are only viewport-dependent in emulation mode,
1626 // and thus will not be invalidated in |FrameView::performPreLayoutTasks|.
1627 // Therefore we should force explicit media queries invalidation here.
1628 if (page()->inspectorController().deviceEmulationEnabled()) {
1629 if (Document* document = mainFrameImpl()->frame()->document())
1630 document->mediaQueryAffectingValueChanged();
1634 if (settings()->viewportEnabled() && !m_fixedLayoutSizeLock) {
1635 // Relayout immediately to recalculate the minimum scale limit.
1636 if (view->needsLayout())
1639 if (shouldAnchorAndRescaleViewport) {
1640 float viewportWidthRatio = static_cast<float>(newSize.width) / oldSize.width;
1641 float contentsWidthRatio = static_cast<float>(contentsSize().width()) / oldContentsWidth;
1642 float scaleMultiplier = viewportWidthRatio / contentsWidthRatio;
1644 IntSize viewportSize = view->visibleContentRect().size();
1645 if (scaleMultiplier != 1) {
1646 float newPageScaleFactor = oldPageScaleFactor * scaleMultiplier;
1647 viewportSize.scale(pageScaleFactor() / newPageScaleFactor);
1648 IntPoint scrollOffsetAtNewScale = viewportAnchor.computeOrigin(viewportSize);
1649 setPageScaleFactor(newPageScaleFactor, scrollOffsetAtNewScale);
1651 IntPoint scrollOffsetAtNewScale = clampOffsetAtScale(viewportAnchor.computeOrigin(viewportSize), pageScaleFactor());
1652 updateMainFrameScrollPosition(scrollOffsetAtNewScale, false);
1657 sendResizeEventAndRepaint();
1660 void WebViewImpl::willEndLiveResize()
1662 if (mainFrameImpl() && mainFrameImpl()->frameView())
1663 mainFrameImpl()->frameView()->willEndLiveResize();
1665 LocalFrame* frame = mainFrameImpl()->frame();
1666 WebPluginContainerImpl* pluginContainer = WebLocalFrameImpl::pluginContainerFromFrame(frame);
1667 if (pluginContainer)
1668 pluginContainer->willEndLiveResize();
1671 void WebViewImpl::willEnterFullScreen()
1673 m_fullscreenController->willEnterFullScreen();
1676 void WebViewImpl::didEnterFullScreen()
1678 m_fullscreenController->didEnterFullScreen();
1681 void WebViewImpl::willExitFullScreen()
1683 m_fullscreenController->willExitFullScreen();
1686 void WebViewImpl::didExitFullScreen()
1688 m_fullscreenController->didExitFullScreen();
1691 void WebViewImpl::animate(double monotonicFrameBeginTime)
1693 TRACE_EVENT0("webkit", "WebViewImpl::animate");
1695 if (!monotonicFrameBeginTime)
1696 monotonicFrameBeginTime = monotonicallyIncreasingTime();
1698 // Create synthetic wheel events as necessary for fling.
1699 if (m_gestureAnimation) {
1700 if (m_gestureAnimation->animate(monotonicFrameBeginTime))
1701 scheduleAnimation();
1703 endActiveFlingAnimation();
1705 PlatformGestureEvent endScrollEvent(PlatformEvent::GestureScrollEnd,
1706 m_positionOnFlingStart, m_globalPositionOnFlingStart,
1707 IntSize(), 0, false, false, false, false,
1710 mainFrameImpl()->frame()->eventHandler().handleGestureScrollEnd(endScrollEvent);
1717 PageWidgetDelegate::animate(m_page.get(), monotonicFrameBeginTime);
1719 if (m_continuousPaintingEnabled) {
1720 ContinuousPainter::setNeedsDisplayRecursive(m_rootGraphicsLayer, m_pageOverlays.get());
1721 m_client->scheduleAnimation();
1725 void WebViewImpl::layout()
1727 TRACE_EVENT0("webkit", "WebViewImpl::layout");
1728 PageWidgetDelegate::layout(m_page.get());
1729 updateLayerTreeBackgroundColor();
1731 for (size_t i = 0; i < m_linkHighlights.size(); ++i)
1732 m_linkHighlights[i]->updateGeometry();
1735 void WebViewImpl::paint(WebCanvas* canvas, const WebRect& rect)
1737 // This should only be used when compositing is not being used for this
1738 // WebView, and it is painting into the recording of its parent.
1739 ASSERT(!isAcceleratedCompositingActive());
1741 double paintStart = currentTime();
1742 PageWidgetDelegate::paint(m_page.get(), pageOverlays(), canvas, rect, isTransparent() ? PageWidgetDelegate::Translucent : PageWidgetDelegate::Opaque);
1743 double paintEnd = currentTime();
1744 double pixelsPerSec = (rect.width * rect.height) / (paintEnd - paintStart);
1745 blink::Platform::current()->histogramCustomCounts("Renderer4.SoftwarePaintDurationMS", (paintEnd - paintStart) * 1000, 0, 120, 30);
1746 blink::Platform::current()->histogramCustomCounts("Renderer4.SoftwarePaintMegapixPerSecond", pixelsPerSec / 1000000, 10, 210, 30);
1750 void WebViewImpl::paintCompositedDeprecated(WebCanvas* canvas, const WebRect& rect)
1752 // Note: This method exists on OS(ANDROID) and will hopefully be
1753 // removed once the link disambiguation feature renders using
1755 ASSERT(isAcceleratedCompositingActive());
1757 FrameView* view = page()->deprecatedLocalMainFrame()->view();
1758 PaintBehavior oldPaintBehavior = view->paintBehavior();
1759 view->setPaintBehavior(oldPaintBehavior | PaintBehaviorFlattenCompositingLayers);
1761 PageWidgetDelegate::paint(m_page.get(), pageOverlays(), canvas, rect, isTransparent() ? PageWidgetDelegate::Translucent : PageWidgetDelegate::Opaque);
1763 view->setPaintBehavior(oldPaintBehavior);
1767 void WebViewImpl::compositeAndReadbackAsync(WebCompositeAndReadbackAsyncCallback* callback)
1769 ASSERT(isAcceleratedCompositingActive());
1770 m_layerTreeView->compositeAndReadbackAsync(callback);
1773 bool WebViewImpl::isTrackingRepaints() const
1777 if (!page()->mainFrame()->isLocalFrame())
1779 FrameView* view = page()->deprecatedLocalMainFrame()->view();
1780 return view->isTrackingPaintInvalidations();
1783 void WebViewImpl::themeChanged()
1787 if (!page()->mainFrame()->isLocalFrame())
1789 FrameView* view = page()->deprecatedLocalMainFrame()->view();
1791 WebRect damagedRect(0, 0, m_size.width, m_size.height);
1792 view->invalidateRect(damagedRect);
1795 void WebViewImpl::enterFullScreenForElement(WebCore::Element* element)
1797 m_fullscreenController->enterFullScreenForElement(element);
1800 void WebViewImpl::exitFullScreenForElement(WebCore::Element* element)
1802 m_fullscreenController->exitFullScreenForElement(element);
1805 bool WebViewImpl::hasHorizontalScrollbar()
1807 return mainFrameImpl()->frameView()->horizontalScrollbar();
1810 bool WebViewImpl::hasVerticalScrollbar()
1812 return mainFrameImpl()->frameView()->verticalScrollbar();
1815 const WebInputEvent* WebViewImpl::m_currentInputEvent = 0;
1817 // FIXME: autogenerate this kind of code, and use it throughout Blink rather than
1818 // the one-offs for subsets of these values.
1819 static const AtomicString* inputTypeToName(WebInputEvent::Type type)
1822 case WebInputEvent::MouseDown:
1823 return &EventTypeNames::mousedown;
1824 case WebInputEvent::MouseUp:
1825 return &EventTypeNames::mouseup;
1826 case WebInputEvent::MouseMove:
1827 return &EventTypeNames::mousemove;
1828 case WebInputEvent::MouseEnter:
1829 return &EventTypeNames::mouseenter;
1830 case WebInputEvent::MouseLeave:
1831 return &EventTypeNames::mouseleave;
1832 case WebInputEvent::ContextMenu:
1833 return &EventTypeNames::contextmenu;
1834 case WebInputEvent::MouseWheel:
1835 return &EventTypeNames::mousewheel;
1836 case WebInputEvent::KeyDown:
1837 return &EventTypeNames::keydown;
1838 case WebInputEvent::KeyUp:
1839 return &EventTypeNames::keyup;
1840 case WebInputEvent::GestureScrollBegin:
1841 return &EventTypeNames::gesturescrollstart;
1842 case WebInputEvent::GestureScrollEnd:
1843 return &EventTypeNames::gesturescrollend;
1844 case WebInputEvent::GestureScrollUpdate:
1845 return &EventTypeNames::gesturescrollupdate;
1846 case WebInputEvent::TouchStart:
1847 return &EventTypeNames::touchstart;
1848 case WebInputEvent::TouchMove:
1849 return &EventTypeNames::touchmove;
1850 case WebInputEvent::TouchEnd:
1851 return &EventTypeNames::touchend;
1852 case WebInputEvent::TouchCancel:
1853 return &EventTypeNames::touchcancel;
1859 bool WebViewImpl::handleInputEvent(const WebInputEvent& inputEvent)
1861 UserGestureNotifier notifier(m_autofillClient, &m_userGestureObserved);
1862 // On the first input event since page load, |notifier| instructs the
1863 // autofill client to unblock values of password input fields of any forms
1864 // on the page. There is a single input event, GestureTap, which can both
1865 // be the first event after page load, and cause a form submission. In that
1866 // case, the form submission happens before the autofill client is told
1867 // to unblock the password values, and so the password values are not
1868 // submitted. To avoid that, GestureTap is handled explicitly:
1869 if (inputEvent.type == WebInputEvent::GestureTap && m_autofillClient) {
1870 m_userGestureObserved = true;
1871 m_autofillClient->firstUserGestureObserved();
1874 const AtomicString* inputEventName = inputTypeToName(inputEvent.type);
1875 TRACE_EVENT1("input", "WebViewImpl::handleInputEvent", "type", inputEventName ? inputEventName->ascii() : "unknown");
1876 // If we've started a drag and drop operation, ignore input events until
1878 if (m_doingDragAndDrop)
1881 if (m_devToolsAgent && m_devToolsAgent->handleInputEvent(m_page.get(), inputEvent))
1884 // Report the event to be NOT processed by WebKit, so that the browser can handle it appropriately.
1885 if (m_ignoreInputEvents)
1888 TemporaryChange<const WebInputEvent*> currentEventChange(m_currentInputEvent, &inputEvent);
1890 if (isPointerLocked() && WebInputEvent::isMouseEventType(inputEvent.type)) {
1891 pointerLockMouseEvent(inputEvent);
1895 if (m_mouseCaptureNode && WebInputEvent::isMouseEventType(inputEvent.type)) {
1896 TRACE_EVENT1("input", "captured mouse event", "type", inputEvent.type);
1897 // Save m_mouseCaptureNode since mouseCaptureLost() will clear it.
1898 RefPtrWillBeRawPtr<Node> node = m_mouseCaptureNode;
1900 // Not all platforms call mouseCaptureLost() directly.
1901 if (inputEvent.type == WebInputEvent::MouseUp)
1904 OwnPtr<UserGestureIndicator> gestureIndicator;
1906 AtomicString eventType;
1907 switch (inputEvent.type) {
1908 case WebInputEvent::MouseMove:
1909 eventType = EventTypeNames::mousemove;
1911 case WebInputEvent::MouseLeave:
1912 eventType = EventTypeNames::mouseout;
1914 case WebInputEvent::MouseDown:
1915 eventType = EventTypeNames::mousedown;
1916 gestureIndicator = adoptPtr(new UserGestureIndicator(DefinitelyProcessingNewUserGesture));
1917 m_mouseCaptureGestureToken = gestureIndicator->currentToken();
1919 case WebInputEvent::MouseUp:
1920 eventType = EventTypeNames::mouseup;
1921 gestureIndicator = adoptPtr(new UserGestureIndicator(m_mouseCaptureGestureToken.release()));
1924 ASSERT_NOT_REACHED();
1927 node->dispatchMouseEvent(
1928 PlatformMouseEventBuilder(mainFrameImpl()->frameView(), *static_cast<const WebMouseEvent*>(&inputEvent)),
1929 eventType, static_cast<const WebMouseEvent*>(&inputEvent)->clickCount);
1933 return PageWidgetDelegate::handleInputEvent(m_page.get(), *this, inputEvent);
1936 void WebViewImpl::setCursorVisibilityState(bool isVisible)
1939 m_page->setIsCursorVisible(isVisible);
1942 void WebViewImpl::mouseCaptureLost()
1944 TRACE_EVENT_ASYNC_END0("input", "capturing mouse", this);
1945 m_mouseCaptureNode = nullptr;
1948 void WebViewImpl::setFocus(bool enable)
1950 m_page->focusController().setFocused(enable);
1952 m_page->focusController().setActive(true);
1953 RefPtr<Frame> focusedFrame = m_page->focusController().focusedFrame();
1954 if (focusedFrame && focusedFrame->isLocalFrame()) {
1955 LocalFrame* localFrame = toLocalFrame(focusedFrame.get());
1956 Element* element = localFrame->document()->focusedElement();
1957 if (element && localFrame->selection().selection().isNone()) {
1958 // If the selection was cleared while the WebView was not
1959 // focused, then the focus element shows with a focus ring but
1960 // no caret and does respond to keyboard inputs.
1961 if (element->isTextFormControl()) {
1962 element->updateFocusAppearance(true);
1963 } else if (element->isContentEditable()) {
1964 // updateFocusAppearance() selects all the text of
1965 // contentseditable DIVs. So we set the selection explicitly
1966 // instead. Note that this has the side effect of moving the
1967 // caret back to the beginning of the text.
1968 Position position(element, 0, Position::PositionIsOffsetInAnchor);
1969 localFrame->selection().setSelection(VisibleSelection(position, SEL_DEFAULT_AFFINITY));
1973 m_imeAcceptEvents = true;
1977 // Clear focus on the currently focused frame if any.
1981 LocalFrame* frame = m_page->mainFrame() && m_page->mainFrame()->isLocalFrame()
1982 ? m_page->deprecatedLocalMainFrame() : 0;
1986 RefPtr<Frame> focusedFrame = m_page->focusController().focusedFrame();
1987 if (focusedFrame && focusedFrame->isLocalFrame()) {
1988 // Finish an ongoing composition to delete the composition node.
1989 if (toLocalFrame(focusedFrame.get())->inputMethodController().hasComposition()) {
1990 if (m_autofillClient)
1991 m_autofillClient->setIgnoreTextChanges(true);
1993 toLocalFrame(focusedFrame.get())->inputMethodController().confirmComposition();
1995 if (m_autofillClient)
1996 m_autofillClient->setIgnoreTextChanges(false);
1998 m_imeAcceptEvents = false;
2003 bool WebViewImpl::setComposition(
2004 const WebString& text,
2005 const WebVector<WebCompositionUnderline>& underlines,
2009 LocalFrame* focused = toLocalFrame(focusedWebCoreFrame());
2010 if (!focused || !m_imeAcceptEvents)
2013 if (WebPlugin* plugin = focusedPluginIfInputMethodSupported(focused))
2014 return plugin->setComposition(text, underlines, selectionStart, selectionEnd);
2016 // The input focus has been moved to another WebWidget object.
2017 // We should use this |editor| object only to complete the ongoing
2019 InputMethodController& inputMethodController = focused->inputMethodController();
2020 if (!focused->editor().canEdit() && !inputMethodController.hasComposition())
2023 // We should verify the parent node of this IME composition node are
2024 // editable because JavaScript may delete a parent node of the composition
2025 // node. In this case, WebKit crashes while deleting texts from the parent
2026 // node, which doesn't exist any longer.
2027 RefPtrWillBeRawPtr<Range> range = inputMethodController.compositionRange();
2029 Node* node = range->startContainer();
2030 if (!node || !node->isContentEditable())
2034 // If we're not going to fire a keypress event, then the keydown event was
2035 // canceled. In that case, cancel any existing composition.
2036 if (text.isEmpty() || m_suppressNextKeypressEvent) {
2037 // A browser process sent an IPC message which does not contain a valid
2038 // string, which means an ongoing composition has been canceled.
2039 // If the ongoing composition has been canceled, replace the ongoing
2040 // composition string with an empty string and complete it.
2042 Vector<CompositionUnderline> emptyUnderlines;
2043 inputMethodController.setComposition(emptyString, emptyUnderlines, 0, 0);
2044 return text.isEmpty();
2047 // When the range of composition underlines overlap with the range between
2048 // selectionStart and selectionEnd, WebKit somehow won't paint the selection
2049 // at all (see InlineTextBox::paint() function in InlineTextBox.cpp).
2050 // But the selection range actually takes effect.
2051 inputMethodController.setComposition(String(text),
2052 CompositionUnderlineVectorBuilder(underlines),
2053 selectionStart, selectionEnd);
2055 return inputMethodController.hasComposition();
2058 bool WebViewImpl::confirmComposition()
2060 return confirmComposition(DoNotKeepSelection);
2063 bool WebViewImpl::confirmComposition(ConfirmCompositionBehavior selectionBehavior)
2065 return confirmComposition(WebString(), selectionBehavior);
2068 bool WebViewImpl::confirmComposition(const WebString& text)
2070 return confirmComposition(text, DoNotKeepSelection);
2073 bool WebViewImpl::confirmComposition(const WebString& text, ConfirmCompositionBehavior selectionBehavior)
2075 LocalFrame* focused = toLocalFrame(focusedWebCoreFrame());
2076 if (!focused || !m_imeAcceptEvents)
2079 if (WebPlugin* plugin = focusedPluginIfInputMethodSupported(focused))
2080 return plugin->confirmComposition(text, selectionBehavior);
2082 return focused->inputMethodController().confirmCompositionOrInsertText(text, selectionBehavior == KeepSelection ? InputMethodController::KeepSelection : InputMethodController::DoNotKeepSelection);
2085 bool WebViewImpl::compositionRange(size_t* location, size_t* length)
2087 LocalFrame* focused = toLocalFrame(focusedWebCoreFrame());
2088 if (!focused || !m_imeAcceptEvents)
2091 RefPtrWillBeRawPtr<Range> range = focused->inputMethodController().compositionRange();
2095 Element* editable = focused->selection().rootEditableElementOrDocumentElement();
2097 PlainTextRange plainTextRange(PlainTextRange::create(*editable, *range.get()));
2098 if (plainTextRange.isNull())
2100 *location = plainTextRange.start();
2101 *length = plainTextRange.length();
2105 WebTextInputInfo WebViewImpl::textInputInfo()
2107 WebTextInputInfo info;
2109 LocalFrame* focused = toLocalFrame(focusedWebCoreFrame());
2113 FrameSelection& selection = focused->selection();
2114 Node* node = selection.selection().rootEditableElement();
2118 info.inputMode = inputModeOfFocusedElement();
2120 info.type = textInputType();
2121 if (info.type == WebTextInputTypeNone)
2124 if (!focused->editor().canEdit())
2127 // Emits an object replacement character for each replaced element so that
2128 // it is exposed to IME and thus could be deleted by IME on android.
2129 info.value = plainText(rangeOfContents(node).get(), TextIteratorEmitsObjectReplacementCharacter);
2131 if (info.value.isEmpty())
2134 if (RefPtrWillBeRawPtr<Range> range = selection.selection().firstRange()) {
2135 PlainTextRange plainTextRange(PlainTextRange::create(*node, *range.get()));
2136 if (plainTextRange.isNotNull()) {
2137 info.selectionStart = plainTextRange.start();
2138 info.selectionEnd = plainTextRange.end();
2142 if (RefPtrWillBeRawPtr<Range> range = focused->inputMethodController().compositionRange()) {
2143 PlainTextRange plainTextRange(PlainTextRange::create(*node, *range.get()));
2144 if (plainTextRange.isNotNull()) {
2145 info.compositionStart = plainTextRange.start();
2146 info.compositionEnd = plainTextRange.end();
2153 WebTextInputType WebViewImpl::textInputType()
2155 Element* element = focusedElement();
2157 return WebTextInputTypeNone;
2159 if (isHTMLInputElement(*element)) {
2160 HTMLInputElement& input = toHTMLInputElement(*element);
2162 if (input.isDisabledOrReadOnly())
2163 return WebTextInputTypeNone;
2165 if (input.isPasswordField())
2166 return WebTextInputTypePassword;
2167 if (input.isSearchField())
2168 return WebTextInputTypeSearch;
2169 if (input.isEmailField())
2170 return WebTextInputTypeEmail;
2171 if (input.isNumberField())
2172 return WebTextInputTypeNumber;
2173 if (input.isTelephoneField())
2174 return WebTextInputTypeTelephone;
2175 if (input.isURLField())
2176 return WebTextInputTypeURL;
2177 if (input.isDateField())
2178 return WebTextInputTypeDate;
2179 if (input.isDateTimeLocalField())
2180 return WebTextInputTypeDateTimeLocal;
2181 if (input.isMonthField())
2182 return WebTextInputTypeMonth;
2183 if (input.isTimeField())
2184 return WebTextInputTypeTime;
2185 if (input.isWeekField())
2186 return WebTextInputTypeWeek;
2187 if (input.isTextField())
2188 return WebTextInputTypeText;
2190 return WebTextInputTypeNone;
2193 if (isHTMLTextAreaElement(*element)) {
2194 if (toHTMLTextAreaElement(*element).isDisabledOrReadOnly())
2195 return WebTextInputTypeNone;
2196 return WebTextInputTypeTextArea;
2199 #if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
2200 if (element->isHTMLElement()) {
2201 if (toHTMLElement(element)->isDateTimeFieldElement())
2202 return WebTextInputTypeDateTimeField;
2206 if (element->shouldUseInputMethod())
2207 return WebTextInputTypeContentEditable;
2209 return WebTextInputTypeNone;
2212 WebString WebViewImpl::inputModeOfFocusedElement()
2214 if (!RuntimeEnabledFeatures::inputModeAttributeEnabled())
2217 Element* element = focusedElement();
2221 if (isHTMLInputElement(*element)) {
2222 const HTMLInputElement& input = toHTMLInputElement(*element);
2223 if (input.supportsInputModeAttribute())
2224 return input.fastGetAttribute(HTMLNames::inputmodeAttr).lower();
2227 if (isHTMLTextAreaElement(*element)) {
2228 const HTMLTextAreaElement& textarea = toHTMLTextAreaElement(*element);
2229 return textarea.fastGetAttribute(HTMLNames::inputmodeAttr).lower();
2235 bool WebViewImpl::selectionBounds(WebRect& anchor, WebRect& focus) const
2237 const LocalFrame* frame = toLocalFrame(focusedWebCoreFrame());
2240 FrameSelection& selection = frame->selection();
2242 if (selection.isCaret()) {
2243 anchor = focus = selection.absoluteCaretBounds();
2245 RefPtrWillBeRawPtr<Range> selectedRange = selection.toNormalizedRange();
2249 RefPtrWillBeRawPtr<Range> range(Range::create(selectedRange->startContainer()->document(),
2250 selectedRange->startContainer(),
2251 selectedRange->startOffset(),
2252 selectedRange->startContainer(),
2253 selectedRange->startOffset()));
2254 anchor = frame->editor().firstRectForRange(range.get());
2256 range = Range::create(selectedRange->endContainer()->document(),
2257 selectedRange->endContainer(),
2258 selectedRange->endOffset(),
2259 selectedRange->endContainer(),
2260 selectedRange->endOffset());
2261 focus = frame->editor().firstRectForRange(range.get());
2264 IntRect scaledAnchor(frame->view()->contentsToWindow(anchor));
2265 IntRect scaledFocus(frame->view()->contentsToWindow(focus));
2267 if (pinchVirtualViewportEnabled()) {
2268 // FIXME(http://crbug.com/371902) - We shouldn't have to do this
2269 // manually, the contentsToWindow methods above should be fixed to do
2271 IntPoint pinchViewportOffset =
2272 roundedIntPoint(page()->frameHost().pinchViewport().visibleRect().location());
2273 scaledAnchor.moveBy(-pinchViewportOffset);
2274 scaledFocus.moveBy(-pinchViewportOffset);
2277 scaledAnchor.scale(pageScaleFactor());
2278 scaledFocus.scale(pageScaleFactor());
2279 anchor = scaledAnchor;
2280 focus = scaledFocus;
2282 if (!selection.selection().isBaseFirst())
2283 std::swap(anchor, focus);
2287 InputMethodContext* WebViewImpl::inputMethodContext()
2289 if (!m_imeAcceptEvents)
2292 LocalFrame* focusedFrame = toLocalFrame(focusedWebCoreFrame());
2296 Element* target = focusedFrame->document()->focusedElement();
2297 if (target && target->hasInputMethodContext())
2298 return &target->inputMethodContext();
2303 WebPlugin* WebViewImpl::focusedPluginIfInputMethodSupported(LocalFrame* frame)
2305 WebPluginContainerImpl* container = WebLocalFrameImpl::pluginContainerFromNode(frame, WebNode(focusedElement()));
2306 if (container && container->supportsInputMethod())
2307 return container->plugin();
2311 void WebViewImpl::didShowCandidateWindow()
2313 if (InputMethodContext* context = inputMethodContext())
2314 context->dispatchCandidateWindowShowEvent();
2317 void WebViewImpl::didUpdateCandidateWindow()
2319 if (InputMethodContext* context = inputMethodContext())
2320 context->dispatchCandidateWindowUpdateEvent();
2323 void WebViewImpl::didHideCandidateWindow()
2325 if (InputMethodContext* context = inputMethodContext())
2326 context->dispatchCandidateWindowHideEvent();
2329 bool WebViewImpl::selectionTextDirection(WebTextDirection& start, WebTextDirection& end) const
2331 const LocalFrame* frame = toLocalFrame(focusedWebCoreFrame());
2334 FrameSelection& selection = frame->selection();
2335 if (!selection.toNormalizedRange())
2337 start = selection.start().primaryDirection() == RTL ? WebTextDirectionRightToLeft : WebTextDirectionLeftToRight;
2338 end = selection.end().primaryDirection() == RTL ? WebTextDirectionRightToLeft : WebTextDirectionLeftToRight;
2342 bool WebViewImpl::isSelectionAnchorFirst() const
2344 if (const LocalFrame* frame = toLocalFrame(focusedWebCoreFrame()))
2345 return frame->selection().selection().isBaseFirst();
2349 WebVector<WebCompositionUnderline> WebViewImpl::compositionUnderlines() const
2351 const LocalFrame* focused = toLocalFrame(focusedWebCoreFrame());
2353 return WebVector<WebCompositionUnderline>();
2354 const Vector<CompositionUnderline>& underlines = focused->inputMethodController().customCompositionUnderlines();
2355 WebVector<WebCompositionUnderline> results(underlines.size());
2356 for (size_t index = 0; index < underlines.size(); ++index) {
2357 CompositionUnderline underline = underlines[index];
2358 results[index] = WebCompositionUnderline(underline.startOffset, underline.endOffset, static_cast<WebColor>(underline.color.rgb()), underline.thick, static_cast<WebColor>(underline.backgroundColor.rgb()));
2363 WebColor WebViewImpl::backgroundColor() const
2365 if (isTransparent())
2366 return Color::transparent;
2368 return m_baseBackgroundColor;
2369 if (!m_page->mainFrame())
2370 return m_baseBackgroundColor;
2371 if (!m_page->mainFrame()->isLocalFrame())
2372 return m_baseBackgroundColor;
2373 FrameView* view = m_page->deprecatedLocalMainFrame()->view();
2374 return view->documentBackgroundColor().rgb();
2377 bool WebViewImpl::caretOrSelectionRange(size_t* location, size_t* length)
2379 const LocalFrame* focused = toLocalFrame(focusedWebCoreFrame());
2383 PlainTextRange selectionOffsets = focused->inputMethodController().getSelectionOffsets();
2384 if (selectionOffsets.isNull())
2387 *location = selectionOffsets.start();
2388 *length = selectionOffsets.length();
2392 void WebViewImpl::setTextDirection(WebTextDirection direction)
2394 // The Editor::setBaseWritingDirection() function checks if we can change
2395 // the text direction of the selected node and updates its DOM "dir"
2396 // attribute and its CSS "direction" property.
2397 // So, we just call the function as Safari does.
2398 const LocalFrame* focused = toLocalFrame(focusedWebCoreFrame());
2402 Editor& editor = focused->editor();
2403 if (!editor.canEdit())
2406 switch (direction) {
2407 case WebTextDirectionDefault:
2408 editor.setBaseWritingDirection(NaturalWritingDirection);
2411 case WebTextDirectionLeftToRight:
2412 editor.setBaseWritingDirection(LeftToRightWritingDirection);
2415 case WebTextDirectionRightToLeft:
2416 editor.setBaseWritingDirection(RightToLeftWritingDirection);
2425 bool WebViewImpl::isAcceleratedCompositingActive() const
2427 return m_isAcceleratedCompositingActive;
2430 void WebViewImpl::willCloseLayerTreeView()
2432 setIsAcceleratedCompositingActive(false);
2433 m_layerTreeView = 0;
2436 void WebViewImpl::didAcquirePointerLock()
2439 page()->pointerLockController().didAcquirePointerLock();
2442 void WebViewImpl::didNotAcquirePointerLock()
2445 page()->pointerLockController().didNotAcquirePointerLock();
2448 void WebViewImpl::didLosePointerLock()
2451 page()->pointerLockController().didLosePointerLock();
2454 void WebViewImpl::didChangeWindowResizerRect()
2456 if (mainFrameImpl()->frameView())
2457 mainFrameImpl()->frameView()->windowResizerRectChanged();
2460 // WebView --------------------------------------------------------------------
2462 WebSettingsImpl* WebViewImpl::settingsImpl()
2465 m_webSettings = adoptPtr(new WebSettingsImpl(&m_page->settings(), &m_page->inspectorController()));
2466 ASSERT(m_webSettings);
2467 return m_webSettings.get();
2470 WebSettings* WebViewImpl::settings()
2472 return settingsImpl();
2475 WebString WebViewImpl::pageEncoding() const
2480 if (!m_page->mainFrame()->isLocalFrame())
2483 // FIXME: Is this check needed?
2484 if (!m_page->deprecatedLocalMainFrame()->document()->loader())
2487 return m_page->deprecatedLocalMainFrame()->document()->encodingName();
2490 void WebViewImpl::setPageEncoding(const WebString& encodingName)
2495 if (!m_page->mainFrame()->isLocalFrame())
2498 // Only change override encoding, don't change default encoding.
2499 // Note that the new encoding must be 0 if it isn't supposed to be set.
2500 AtomicString newEncodingName;
2501 if (!encodingName.isEmpty())
2502 newEncodingName = encodingName;
2503 m_page->deprecatedLocalMainFrame()->loader().reload(NormalReload, KURL(), newEncodingName);
2506 WebFrame* WebViewImpl::mainFrame()
2508 return WebFrame::fromFrame(m_page ? m_page->mainFrame() : 0);
2511 WebFrame* WebViewImpl::findFrameByName(
2512 const WebString& name, WebFrame* relativeToFrame)
2514 // FIXME: Either this should only deal with WebLocalFrames or it should move to WebFrame.
2515 if (!relativeToFrame)
2516 relativeToFrame = mainFrame();
2517 Frame* frame = toWebLocalFrameImpl(relativeToFrame)->frame();
2518 frame = frame->tree().find(name);
2519 if (!frame || !frame->isLocalFrame())
2521 return WebLocalFrameImpl::fromFrame(toLocalFrame(frame));
2524 WebFrame* WebViewImpl::focusedFrame()
2526 return WebLocalFrameImpl::fromFrame(toLocalFrame(focusedWebCoreFrame()));
2529 void WebViewImpl::setFocusedFrame(WebFrame* frame)
2532 // Clears the focused frame if any.
2533 Frame* focusedFrame = focusedWebCoreFrame();
2534 if (focusedFrame && focusedFrame->isLocalFrame())
2535 toLocalFrame(focusedFrame)->selection().setFocused(false);
2538 LocalFrame* webcoreFrame = toWebLocalFrameImpl(frame)->frame();
2539 webcoreFrame->page()->focusController().setFocusedFrame(webcoreFrame);
2542 void WebViewImpl::setInitialFocus(bool reverse)
2546 Frame* frame = page()->focusController().focusedOrMainFrame();
2547 if (frame->isLocalFrame()) {
2548 if (Document* document = toLocalFrame(frame)->document())
2549 document->setFocusedElement(nullptr);
2551 page()->focusController().setInitialFocus(reverse ? FocusTypeBackward : FocusTypeForward);
2554 void WebViewImpl::clearFocusedElement()
2556 RefPtr<Frame> frame = focusedWebCoreFrame();
2557 if (!frame || !frame->isLocalFrame())
2560 LocalFrame* localFrame = toLocalFrame(frame.get());
2562 RefPtrWillBeRawPtr<Document> document = localFrame->document();
2566 RefPtrWillBeRawPtr<Element> oldFocusedElement = document->focusedElement();
2568 // Clear the focused node.
2569 document->setFocusedElement(nullptr);
2571 if (!oldFocusedElement)
2574 // If a text field has focus, we need to make sure the selection controller
2575 // knows to remove selection from it. Otherwise, the text field is still
2576 // processing keyboard events even though focus has been moved to the page and
2577 // keystrokes get eaten as a result.
2578 if (oldFocusedElement->isContentEditable() || oldFocusedElement->isTextFormControl())
2579 localFrame->selection().clear();
2582 void WebViewImpl::scrollFocusedNodeIntoRect(const WebRect& rect)
2584 LocalFrame* frame = page()->mainFrame() && page()->mainFrame()->isLocalFrame()
2585 ? page()->deprecatedLocalMainFrame() : 0;
2586 Element* element = focusedElement();
2587 if (!frame || !frame->view() || !element)
2590 if (!m_webSettings->autoZoomFocusedNodeToLegibleScale()) {
2591 frame->view()->scrollElementToRect(element, IntRect(rect.x, rect.y, rect.width, rect.height));
2598 computeScaleAndScrollForFocusedNode(element, scale, scroll, needAnimation);
2600 startPageScaleAnimation(scroll, false, scale, scrollAndScaleAnimationDurationInSeconds);
2603 void WebViewImpl::computeScaleAndScrollForFocusedNode(Node* focusedNode, float& newScale, IntPoint& newScroll, bool& needAnimation)
2605 focusedNode->document().updateLayoutIgnorePendingStylesheets();
2607 // 'caret' is rect encompassing the blinking cursor.
2608 IntRect textboxRect = focusedNode->document().view()->contentsToWindow(pixelSnappedIntRect(focusedNode->Node::boundingBox()));
2609 WebRect caret, unusedEnd;
2610 selectionBounds(caret, unusedEnd);
2611 IntRect unscaledCaret = caret;
2612 unscaledCaret.scale(1 / pageScaleFactor());
2613 caret = unscaledCaret;
2615 // Pick a scale which is reasonably readable. This is the scale at which
2616 // the caret height will become minReadableCaretHeight (adjusted for dpi
2617 // and font scale factor).
2618 newScale = clampPageScaleFactorToLimits(legibleScale() * minReadableCaretHeight / caret.height);
2619 const float deltaScale = newScale / pageScaleFactor();
2621 // Convert the rects to absolute space in the new scale.
2622 IntRect textboxRectInDocumentCoordinates = textboxRect;
2623 textboxRectInDocumentCoordinates.move(mainFrame()->scrollOffset());
2624 IntRect caretInDocumentCoordinates = caret;
2625 caretInDocumentCoordinates.move(mainFrame()->scrollOffset());
2627 int viewWidth = m_size.width / newScale;
2628 int viewHeight = m_size.height / newScale;
2630 if (textboxRectInDocumentCoordinates.width() <= viewWidth) {
2631 // Field is narrower than screen. Try to leave padding on left so field's
2632 // label is visible, but it's more important to ensure entire field is
2634 int idealLeftPadding = viewWidth * leftBoxRatio;
2635 int maxLeftPaddingKeepingBoxOnscreen = viewWidth - textboxRectInDocumentCoordinates.width();
2636 newScroll.setX(textboxRectInDocumentCoordinates.x() - std::min<int>(idealLeftPadding, maxLeftPaddingKeepingBoxOnscreen));
2638 // Field is wider than screen. Try to left-align field, unless caret would
2639 // be offscreen, in which case right-align the caret.
2640 newScroll.setX(std::max<int>(textboxRectInDocumentCoordinates.x(), caretInDocumentCoordinates.x() + caretInDocumentCoordinates.width() + caretPadding - viewWidth));
2642 if (textboxRectInDocumentCoordinates.height() <= viewHeight) {
2643 // Field is shorter than screen. Vertically center it.
2644 newScroll.setY(textboxRectInDocumentCoordinates.y() - (viewHeight - textboxRectInDocumentCoordinates.height()) / 2);
2646 // Field is taller than screen. Try to top align field, unless caret would
2647 // be offscreen, in which case bottom-align the caret.
2648 newScroll.setY(std::max<int>(textboxRectInDocumentCoordinates.y(), caretInDocumentCoordinates.y() + caretInDocumentCoordinates.height() + caretPadding - viewHeight));
2651 needAnimation = false;
2652 // If we are at less than the target zoom level, zoom in.
2653 if (deltaScale > minScaleChangeToTriggerZoom)
2654 needAnimation = true;
2655 // If the caret is offscreen, then animate.
2656 IntRect sizeRect(0, 0, viewWidth, viewHeight);
2657 if (!sizeRect.contains(caret))
2658 needAnimation = true;
2659 // If the box is partially offscreen and it's possible to bring it fully
2660 // onscreen, then animate.
2661 if (sizeRect.contains(textboxRectInDocumentCoordinates.width(), textboxRectInDocumentCoordinates.height()) && !sizeRect.contains(textboxRect))
2662 needAnimation = true;
2665 void WebViewImpl::advanceFocus(bool reverse)
2667 page()->focusController().advanceFocus(reverse ? FocusTypeBackward : FocusTypeForward);
2670 double WebViewImpl::zoomLevel()
2675 double WebViewImpl::setZoomLevel(double zoomLevel)
2677 if (zoomLevel < m_minimumZoomLevel)
2678 m_zoomLevel = m_minimumZoomLevel;
2679 else if (zoomLevel > m_maximumZoomLevel)
2680 m_zoomLevel = m_maximumZoomLevel;
2682 m_zoomLevel = zoomLevel;
2684 LocalFrame* frame = mainFrameImpl()->frame();
2685 WebPluginContainerImpl* pluginContainer = WebLocalFrameImpl::pluginContainerFromFrame(frame);
2686 if (pluginContainer)
2687 pluginContainer->plugin()->setZoomLevel(m_zoomLevel, false);
2689 float zoomFactor = m_zoomFactorOverride ? m_zoomFactorOverride : static_cast<float>(zoomLevelToZoomFactor(m_zoomLevel));
2690 frame->setPageZoomFactor(zoomFactor);
2696 void WebViewImpl::zoomLimitsChanged(double minimumZoomLevel,
2697 double maximumZoomLevel)
2699 m_minimumZoomLevel = minimumZoomLevel;
2700 m_maximumZoomLevel = maximumZoomLevel;
2701 m_client->zoomLimitsChanged(m_minimumZoomLevel, m_maximumZoomLevel);
2704 float WebViewImpl::textZoomFactor()
2706 return mainFrameImpl()->frame()->textZoomFactor();
2709 float WebViewImpl::setTextZoomFactor(float textZoomFactor)
2711 LocalFrame* frame = mainFrameImpl()->frame();
2712 if (WebLocalFrameImpl::pluginContainerFromFrame(frame))
2715 frame->setTextZoomFactor(textZoomFactor);
2717 return textZoomFactor;
2720 void WebViewImpl::fullFramePluginZoomLevelChanged(double zoomLevel)
2722 if (zoomLevel == m_zoomLevel)
2725 m_zoomLevel = std::max(std::min(zoomLevel, m_maximumZoomLevel), m_minimumZoomLevel);
2726 m_client->zoomLevelChanged();
2729 double WebView::zoomLevelToZoomFactor(double zoomLevel)
2731 return pow(textSizeMultiplierRatio, zoomLevel);
2734 double WebView::zoomFactorToZoomLevel(double factor)
2736 // Since factor = 1.2^level, level = log(factor) / log(1.2)
2737 return log(factor) / log(textSizeMultiplierRatio);
2740 float WebViewImpl::pageScaleFactor() const
2745 if (!pinchVirtualViewportEnabled())
2746 return page()->pageScaleFactor();
2748 return page()->frameHost().pinchViewport().scale();
2751 float WebViewImpl::clampPageScaleFactorToLimits(float scaleFactor) const
2753 return m_pageScaleConstraintsSet.finalConstraints().clampToConstraints(scaleFactor);
2756 IntPoint WebViewImpl::clampOffsetAtScale(const IntPoint& offset, float scale)
2758 FrameView* view = mainFrameImpl()->frameView();
2762 return view->clampOffsetAtScale(offset, scale);
2765 bool WebViewImpl::pinchVirtualViewportEnabled() const
2768 return page()->settings().pinchVirtualViewportEnabled();
2771 void WebViewImpl::setPinchViewportOffset(const WebFloatPoint& offset)
2775 if (!pinchVirtualViewportEnabled())
2778 page()->frameHost().pinchViewport().setLocation(offset);
2781 WebFloatPoint WebViewImpl::pinchViewportOffset() const
2785 if (!pinchVirtualViewportEnabled())
2786 return WebFloatPoint();
2788 return page()->frameHost().pinchViewport().visibleRect().location();
2791 void WebViewImpl::setPageScaleFactor(float scaleFactor)
2795 scaleFactor = clampPageScaleFactorToLimits(scaleFactor);
2796 if (scaleFactor == pageScaleFactor())
2799 // TODO(bokan): Old-style pinch path. Remove when we're migrated to
2800 // virtual viewport pinch.
2801 if (!pinchVirtualViewportEnabled()) {
2802 IntPoint scrollOffset(mainFrame()->scrollOffset().width, mainFrame()->scrollOffset().height);
2803 setPageScaleFactor(scaleFactor, scrollOffset);
2807 page()->frameHost().pinchViewport().setScale(scaleFactor);
2808 deviceOrPageScaleFactorChanged();
2811 void WebViewImpl::setMainFrameScrollOffset(const WebPoint& origin)
2813 updateMainFrameScrollPosition(origin, false);
2816 void WebViewImpl::setPageScaleFactor(float scaleFactor, const WebPoint& origin)
2821 IntPoint newScrollOffset = origin;
2822 scaleFactor = clampPageScaleFactorToLimits(scaleFactor);
2823 newScrollOffset = clampOffsetAtScale(newScrollOffset, scaleFactor);
2825 if (pinchVirtualViewportEnabled())
2826 setPageScaleFactor(scaleFactor);
2827 // Note, we don't set the offset in the new path. This method is going
2828 // away for the new pinch model so that's ok.
2830 page()->setPageScaleFactor(scaleFactor, newScrollOffset);
2834 float WebViewImpl::deviceScaleFactor() const
2839 return page()->deviceScaleFactor();
2842 void WebViewImpl::setDeviceScaleFactor(float scaleFactor)
2847 page()->setDeviceScaleFactor(scaleFactor);
2849 if (m_layerTreeView)
2850 updateLayerTreeDeviceScaleFactor();
2853 void WebViewImpl::enableAutoResizeMode(const WebSize& minSize, const WebSize& maxSize)
2855 m_shouldAutoResize = true;
2856 m_minAutoSize = minSize;
2857 m_maxAutoSize = maxSize;
2858 configureAutoResizeMode();
2861 void WebViewImpl::disableAutoResizeMode()
2863 m_shouldAutoResize = false;
2864 configureAutoResizeMode();
2867 void WebViewImpl::setUserAgentPageScaleConstraints(PageScaleConstraints newConstraints)
2869 if (newConstraints == m_pageScaleConstraintsSet.userAgentConstraints())
2872 m_pageScaleConstraintsSet.setUserAgentConstraints(newConstraints);
2874 if (!mainFrameImpl() || !mainFrameImpl()->frameView())
2877 mainFrameImpl()->frameView()->setNeedsLayout();
2880 void WebViewImpl::setInitialPageScaleOverride(float initialPageScaleFactorOverride)
2882 PageScaleConstraints constraints = m_pageScaleConstraintsSet.userAgentConstraints();
2883 constraints.initialScale = initialPageScaleFactorOverride;
2885 if (constraints == m_pageScaleConstraintsSet.userAgentConstraints())
2888 m_pageScaleConstraintsSet.setNeedsReset(true);
2889 setUserAgentPageScaleConstraints(constraints);
2892 void WebViewImpl::setPageScaleFactorLimits(float minPageScale, float maxPageScale)
2894 PageScaleConstraints constraints = m_pageScaleConstraintsSet.userAgentConstraints();
2895 constraints.minimumScale = minPageScale;
2896 constraints.maximumScale = maxPageScale;
2897 setUserAgentPageScaleConstraints(constraints);
2900 void WebViewImpl::setIgnoreViewportTagScaleLimits(bool ignore)
2902 PageScaleConstraints constraints = m_pageScaleConstraintsSet.userAgentConstraints();
2904 constraints.minimumScale = m_pageScaleConstraintsSet.defaultConstraints().minimumScale;
2905 constraints.maximumScale = m_pageScaleConstraintsSet.defaultConstraints().maximumScale;
2907 constraints.minimumScale = -1;
2908 constraints.maximumScale = -1;
2910 setUserAgentPageScaleConstraints(constraints);
2913 void WebViewImpl::refreshPageScaleFactorAfterLayout()
2915 if (!mainFrame() || !page() || !page()->mainFrame() || !page()->mainFrame()->isLocalFrame() || !page()->deprecatedLocalMainFrame()->view())
2917 FrameView* view = page()->deprecatedLocalMainFrame()->view();
2919 updatePageDefinedViewportConstraints(mainFrameImpl()->frame()->document()->viewportDescription());
2920 m_pageScaleConstraintsSet.computeFinalConstraints();
2922 if (settings()->shrinksViewportContentToFit() && !m_fixedLayoutSizeLock) {
2923 int verticalScrollbarWidth = 0;
2924 if (view->verticalScrollbar() && !view->verticalScrollbar()->isOverlayScrollbar())
2925 verticalScrollbarWidth = view->verticalScrollbar()->width();
2926 m_pageScaleConstraintsSet.adjustFinalConstraintsToContentsSize(contentsSize(), verticalScrollbarWidth);
2929 if (pinchVirtualViewportEnabled())
2930 mainFrameImpl()->frameView()->resize(m_pageScaleConstraintsSet.mainFrameSize(contentsSize()));
2932 float newPageScaleFactor = pageScaleFactor();
2933 if (m_pageScaleConstraintsSet.needsReset() && m_pageScaleConstraintsSet.finalConstraints().initialScale != -1) {
2934 newPageScaleFactor = m_pageScaleConstraintsSet.finalConstraints().initialScale;
2935 m_pageScaleConstraintsSet.setNeedsReset(false);
2937 setPageScaleFactor(newPageScaleFactor);
2939 updateLayerTreeViewport();
2941 // Relayout immediately to avoid violating the rule that needsLayout()
2942 // isn't set at the end of a layout.
2943 if (view->needsLayout())
2947 void WebViewImpl::updatePageDefinedViewportConstraints(const ViewportDescription& description)
2949 if (!settings()->viewportEnabled() || !page() || (!m_size.width && !m_size.height) || !page()->mainFrame()->isLocalFrame())
2952 Document* document = page()->deprecatedLocalMainFrame()->document();
2954 if (settingsImpl()->useExpandedHeuristicsForGpuRasterization()) {
2955 m_matchesHeuristicsForGpuRasterization = description.maxWidth == Length(DeviceWidth)
2956 && description.minZoom == 1.0
2957 && description.minZoomIsExplicit;
2959 m_matchesHeuristicsForGpuRasterization = description.maxWidth == Length(DeviceWidth)
2960 && description.minZoom == 1.0
2961 && description.minZoomIsExplicit
2962 && description.zoom == 1.0
2963 && description.zoomIsExplicit
2964 && description.userZoom
2965 && description.userZoomIsExplicit;
2967 if (m_layerTreeView)
2968 m_layerTreeView->heuristicsForGpuRasterizationUpdated(m_matchesHeuristicsForGpuRasterization);
2970 Length defaultMinWidth = document->viewportDefaultMinWidth();
2971 if (defaultMinWidth.isAuto())
2972 defaultMinWidth = Length(ExtendToZoom);
2974 ViewportDescription adjustedDescription = description;
2975 if (settingsImpl()->viewportMetaLayoutSizeQuirk() && adjustedDescription.type == ViewportDescription::ViewportMeta) {
2976 const int legacyWidthSnappingMagicNumber = 320;
2977 if (adjustedDescription.maxWidth.isFixed() && adjustedDescription.maxWidth.value() <= legacyWidthSnappingMagicNumber)
2978 adjustedDescription.maxWidth = Length(DeviceWidth);
2979 if (adjustedDescription.maxHeight.isFixed() && adjustedDescription.maxHeight.value() <= m_size.height)
2980 adjustedDescription.maxHeight = Length(DeviceHeight);
2981 adjustedDescription.minWidth = adjustedDescription.maxWidth;
2982 adjustedDescription.minHeight = adjustedDescription.maxHeight;
2985 float oldInitialScale = m_pageScaleConstraintsSet.pageDefinedConstraints().initialScale;
2986 m_pageScaleConstraintsSet.updatePageDefinedConstraints(adjustedDescription, defaultMinWidth);
2988 if (settingsImpl()->clobberUserAgentInitialScaleQuirk()
2989 && m_pageScaleConstraintsSet.userAgentConstraints().initialScale != -1
2990 && m_pageScaleConstraintsSet.userAgentConstraints().initialScale * deviceScaleFactor() <= 1) {
2991 if (description.maxWidth == Length(DeviceWidth)
2992 || (description.maxWidth.type() == Auto && m_pageScaleConstraintsSet.pageDefinedConstraints().initialScale == 1.0f))
2993 setInitialPageScaleOverride(-1);
2996 m_pageScaleConstraintsSet.adjustForAndroidWebViewQuirks(adjustedDescription, defaultMinWidth.intValue(), deviceScaleFactor(), settingsImpl()->supportDeprecatedTargetDensityDPI(), page()->settings().wideViewportQuirkEnabled(), page()->settings().useWideViewport(), page()->settings().loadWithOverviewMode(), settingsImpl()->viewportMetaNonUserScalableQuirk());
2997 float newInitialScale = m_pageScaleConstraintsSet.pageDefinedConstraints().initialScale;
2998 if (oldInitialScale != newInitialScale && newInitialScale != -1) {
2999 m_pageScaleConstraintsSet.setNeedsReset(true);
3000 if (mainFrameImpl() && mainFrameImpl()->frameView())
3001 mainFrameImpl()->frameView()->setNeedsLayout();
3004 updateMainFrameLayoutSize();
3006 if (LocalFrame* frame = page()->deprecatedLocalMainFrame()) {
3007 if (FastTextAutosizer* textAutosizer = frame->document()->fastTextAutosizer())
3008 textAutosizer->updatePageInfoInAllFrames();
3012 void WebViewImpl::updateMainFrameLayoutSize()
3014 if (m_fixedLayoutSizeLock || m_shouldAutoResize || !mainFrameImpl())
3017 RefPtr<FrameView> view = mainFrameImpl()->frameView();
3021 WebSize layoutSize = m_size;
3023 if (settings()->viewportEnabled()) {
3024 layoutSize = flooredIntSize(m_pageScaleConstraintsSet.pageDefinedConstraints().layoutSize);
3026 bool textAutosizingEnabled = page()->settings().textAutosizingEnabled();
3027 if (textAutosizingEnabled && layoutSize.width != view->layoutSize().width()) {
3028 if (TextAutosizer* textAutosizer = page()->deprecatedLocalMainFrame()->document()->textAutosizer())
3029 textAutosizer->recalculateMultipliers();
3033 view->setLayoutSize(layoutSize);
3036 IntSize WebViewImpl::contentsSize() const
3038 if (!page()->mainFrame()->isLocalFrame())
3040 RenderView* root = page()->deprecatedLocalMainFrame()->contentRenderer();
3043 return root->documentRect().size();
3046 WebSize WebViewImpl::contentsPreferredMinimumSize()
3048 Document* document = m_page->mainFrame()->isLocalFrame() ? m_page->deprecatedLocalMainFrame()->document() : 0;
3049 if (!document || !document->renderView() || !document->documentElement())
3053 FontCachePurgePreventer fontCachePurgePreventer; // Required by minPreferredLogicalWidth().
3054 IntSize preferredMinimumSize(document->renderView()->minPreferredLogicalWidth(), document->documentElement()->scrollHeight());
3055 preferredMinimumSize.scale(zoomLevelToZoomFactor(zoomLevel()));
3056 return preferredMinimumSize;
3059 float WebViewImpl::minimumPageScaleFactor() const
3061 return m_pageScaleConstraintsSet.finalConstraints().minimumScale;
3064 float WebViewImpl::maximumPageScaleFactor() const
3066 return m_pageScaleConstraintsSet.finalConstraints().maximumScale;
3069 void WebViewImpl::resetScrollAndScaleState()
3071 // TODO: This is done by the pinchViewport().reset() call below and can be removed when
3072 // the new pinch path is the only one.
3073 setPageScaleFactor(1);
3074 updateMainFrameScrollPosition(IntPoint(), true);
3075 page()->frameHost().pinchViewport().reset();
3077 if (!page()->mainFrame()->isLocalFrame())
3080 // Clear out the values for the current history item. This will prevent the history item from clobbering the
3081 // value determined during page scale initialization, which may be less than 1.
3082 page()->deprecatedLocalMainFrame()->loader().clearScrollPositionAndViewState();
3083 m_pageScaleConstraintsSet.setNeedsReset(true);
3085 // Clobber saved scales and scroll offsets.
3086 if (FrameView* view = page()->deprecatedLocalMainFrame()->document()->view())
3087 view->cacheCurrentScrollPosition();
3090 void WebViewImpl::setFixedLayoutSize(const WebSize& layoutSize)
3092 if (!page() || !page()->mainFrame()->isLocalFrame())
3095 LocalFrame* frame = page()->deprecatedLocalMainFrame();
3099 RefPtr<FrameView> view = frame->view();
3103 m_fixedLayoutSizeLock = layoutSize.width || layoutSize.height;
3105 if (m_fixedLayoutSizeLock)
3106 view->setLayoutSize(layoutSize);
3108 updateMainFrameLayoutSize();
3111 void WebViewImpl::performMediaPlayerAction(const WebMediaPlayerAction& action,
3112 const WebPoint& location)
3114 HitTestResult result = hitTestResultForWindowPos(location);
3115 RefPtrWillBeRawPtr<Node> node = result.innerNonSharedNode();
3116 if (!isHTMLVideoElement(*node) && !isHTMLAudioElement(*node))
3119 RefPtrWillBeRawPtr<HTMLMediaElement> mediaElement = static_pointer_cast<HTMLMediaElement>(node);
3120 switch (action.type) {
3121 case WebMediaPlayerAction::Play:
3123 mediaElement->play();
3125 mediaElement->pause();
3127 case WebMediaPlayerAction::Mute:
3128 mediaElement->setMuted(action.enable);
3130 case WebMediaPlayerAction::Loop:
3131 mediaElement->setLoop(action.enable);
3133 case WebMediaPlayerAction::Controls:
3134 mediaElement->setControls(action.enable);
3137 ASSERT_NOT_REACHED();
3141 void WebViewImpl::performPluginAction(const WebPluginAction& action,
3142 const WebPoint& location)
3144 HitTestResult result = hitTestResultForWindowPos(location);
3145 RefPtrWillBeRawPtr<Node> node = result.innerNonSharedNode();
3146 if (!isHTMLObjectElement(*node) && !isHTMLEmbedElement(*node))
3149 RenderObject* object = node->renderer();
3150 if (object && object->isWidget()) {
3151 Widget* widget = toRenderWidget(object)->widget();
3152 if (widget && widget->isPluginContainer()) {
3153 WebPluginContainerImpl* plugin = toWebPluginContainerImpl(widget);
3154 switch (action.type) {
3155 case WebPluginAction::Rotate90Clockwise:
3156 plugin->plugin()->rotateView(WebPlugin::RotationType90Clockwise);
3158 case WebPluginAction::Rotate90Counterclockwise:
3159 plugin->plugin()->rotateView(WebPlugin::RotationType90Counterclockwise);
3162 ASSERT_NOT_REACHED();
3168 WebHitTestResult WebViewImpl::hitTestResultAt(const WebPoint& point)
3170 IntPoint scaledPoint = point;
3171 scaledPoint.scale(1 / pageScaleFactor(), 1 / pageScaleFactor());
3172 return hitTestResultForWindowPos(scaledPoint);
3175 void WebViewImpl::copyImageAt(const WebPoint& point)
3180 HitTestResult result = hitTestResultForWindowPos(point);
3182 if (result.absoluteImageURLIncludingCanvasDataURL().isEmpty()) {
3183 // There isn't actually an image at these coordinates. Might be because
3184 // the window scrolled while the context menu was open or because the page
3185 // changed itself between when we thought there was an image here and when
3186 // we actually tried to retreive the image.
3188 // FIXME: implement a cache of the most recent HitTestResult to avoid having
3189 // to do two hit tests.
3193 m_page->deprecatedLocalMainFrame()->editor().copyImage(result);
3196 void WebViewImpl::saveImageAt(const WebPoint& point)
3201 KURL url = hitTestResultForWindowPos(point).absoluteImageURLIncludingCanvasDataURL();
3206 ResourceRequest request(url);
3207 m_page->deprecatedLocalMainFrame()->loader().client()->loadURLExternally(
3208 request, NavigationPolicyDownloadTo, WebString());
3211 void WebViewImpl::dragSourceEndedAt(
3212 const WebPoint& clientPoint,
3213 const WebPoint& screenPoint,
3214 WebDragOperation operation)
3216 PlatformMouseEvent pme(clientPoint,
3218 LeftButton, PlatformEvent::MouseMoved, 0, false, false, false,
3220 m_page->deprecatedLocalMainFrame()->eventHandler().dragSourceEndedAt(pme,
3221 static_cast<DragOperation>(operation));
3224 void WebViewImpl::dragSourceSystemDragEnded()
3226 // It's possible for us to get this callback while not doing a drag if
3227 // it's from a previous page that got unloaded.
3228 if (m_doingDragAndDrop) {
3229 m_page->dragController().dragEnded();
3230 m_doingDragAndDrop = false;
3234 WebDragOperation WebViewImpl::dragTargetDragEnter(
3235 const WebDragData& webDragData,
3236 const WebPoint& clientPoint,
3237 const WebPoint& screenPoint,
3238 WebDragOperationsMask operationsAllowed,
3241 ASSERT(!m_currentDragData);
3243 m_currentDragData = webDragData.getValue();
3244 m_operationsAllowed = operationsAllowed;
3246 return dragTargetDragEnterOrOver(clientPoint, screenPoint, DragEnter, keyModifiers);
3249 WebDragOperation WebViewImpl::dragTargetDragOver(
3250 const WebPoint& clientPoint,
3251 const WebPoint& screenPoint,
3252 WebDragOperationsMask operationsAllowed,
3255 m_operationsAllowed = operationsAllowed;
3257 return dragTargetDragEnterOrOver(clientPoint, screenPoint, DragOver, keyModifiers);
3260 void WebViewImpl::dragTargetDragLeave()
3262 ASSERT(m_currentDragData);
3265 m_currentDragData.get(),
3268 static_cast<DragOperation>(m_operationsAllowed));
3270 m_page->dragController().dragExited(&dragData);
3272 // FIXME: why is the drag scroll timer not stopped here?
3274 m_dragOperation = WebDragOperationNone;
3275 m_currentDragData = nullptr;
3278 void WebViewImpl::dragTargetDrop(const WebPoint& clientPoint,
3279 const WebPoint& screenPoint,
3282 ASSERT(m_currentDragData);
3284 UserGestureNotifier notifier(m_autofillClient, &m_userGestureObserved);
3286 // If this webview transitions from the "drop accepting" state to the "not
3287 // accepting" state, then our IPC message reply indicating that may be in-
3288 // flight, or else delayed by javascript processing in this webview. If a
3289 // drop happens before our IPC reply has reached the browser process, then
3290 // the browser forwards the drop to this webview. So only allow a drop to
3291 // proceed if our webview m_dragOperation state is not DragOperationNone.
3293 if (m_dragOperation == WebDragOperationNone) { // IPC RACE CONDITION: do not allow this drop.
3294 dragTargetDragLeave();
3298 m_currentDragData->setModifierKeyState(webInputEventKeyStateToPlatformEventKeyState(keyModifiers));
3300 m_currentDragData.get(),
3303 static_cast<DragOperation>(m_operationsAllowed));
3305 UserGestureIndicator gesture(DefinitelyProcessingNewUserGesture);
3306 m_page->dragController().performDrag(&dragData);
3308 m_dragOperation = WebDragOperationNone;
3309 m_currentDragData = nullptr;
3312 void WebViewImpl::spellingMarkers(WebVector<uint32_t>* markers)
3314 Vector<uint32_t> result;
3315 for (Frame* frame = m_page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
3316 if (!frame->isLocalFrame())
3318 const WillBeHeapVector<DocumentMarker*>& documentMarkers = toLocalFrame(frame)->document()->markers().markers();
3319 for (size_t i = 0; i < documentMarkers.size(); ++i)
3320 result.append(documentMarkers[i]->hash());
3322 markers->assign(result);
3325 WebDragOperation WebViewImpl::dragTargetDragEnterOrOver(const WebPoint& clientPoint, const WebPoint& screenPoint, DragAction dragAction, int keyModifiers)
3327 ASSERT(m_currentDragData);
3329 m_currentDragData->setModifierKeyState(webInputEventKeyStateToPlatformEventKeyState(keyModifiers));
3331 m_currentDragData.get(),
3334 static_cast<DragOperation>(m_operationsAllowed));
3336 DragSession dragSession;
3337 if (dragAction == DragEnter)
3338 dragSession = m_page->dragController().dragEntered(&dragData);
3340 dragSession = m_page->dragController().dragUpdated(&dragData);
3342 DragOperation dropEffect = dragSession.operation;
3344 // Mask the drop effect operation against the drag source's allowed operations.
3345 if (!(dropEffect & dragData.draggingSourceOperationMask()))
3346 dropEffect = DragOperationNone;
3348 m_dragOperation = static_cast<WebDragOperation>(dropEffect);
3350 return m_dragOperation;
3353 void WebViewImpl::sendResizeEventAndRepaint()
3355 // FIXME: This is wrong. The FrameView is responsible sending a resizeEvent
3356 // as part of layout. Layout is also responsible for sending invalidations
3357 // to the embedder. This method and all callers may be wrong. -- eseidel.
3358 if (mainFrameImpl()->frameView()) {
3359 // Enqueues the resize event.
3360 mainFrameImpl()->frame()->document()->enqueueResizeEvent();
3364 if (isAcceleratedCompositingActive()) {
3365 updateLayerTreeViewport();
3367 WebRect damagedRect(0, 0, m_size.width, m_size.height);
3368 m_client->didInvalidateRect(damagedRect);
3372 m_pageOverlays->update();
3375 void WebViewImpl::configureAutoResizeMode()
3377 if (!mainFrameImpl() || !mainFrameImpl()->frame() || !mainFrameImpl()->frame()->view())
3380 mainFrameImpl()->frame()->view()->enableAutoSizeMode(m_shouldAutoResize, m_minAutoSize, m_maxAutoSize);
3383 unsigned long WebViewImpl::createUniqueIdentifierForRequest()
3385 return createUniqueIdentifier();
3388 void WebViewImpl::inspectElementAt(const WebPoint& point)
3393 if (point.x == -1 || point.y == -1) {
3394 m_page->inspectorController().inspect(0);
3396 HitTestRequest::HitTestRequestType hitType = HitTestRequest::Move | HitTestRequest::ReadOnly | HitTestRequest::AllowChildFrameContent;
3397 HitTestRequest request(hitType);
3399 WebMouseEvent dummyEvent;
3400 dummyEvent.type = WebInputEvent::MouseDown;
3401 dummyEvent.x = point.x;
3402 dummyEvent.y = point.y;
3403 IntPoint transformedPoint = PlatformMouseEventBuilder(m_page->deprecatedLocalMainFrame()->view(), dummyEvent).position();
3404 HitTestResult result(m_page->deprecatedLocalMainFrame()->view()->windowToContents(transformedPoint));
3405 m_page->deprecatedLocalMainFrame()->contentRenderer()->hitTest(request, result);
3406 Node* node = result.innerNode();
3407 if (!node && m_page->deprecatedLocalMainFrame()->document())
3408 node = m_page->deprecatedLocalMainFrame()->document()->documentElement();
3409 m_page->inspectorController().inspect(node);
3413 WebString WebViewImpl::inspectorSettings() const
3415 return m_inspectorSettings;
3418 void WebViewImpl::setInspectorSettings(const WebString& settings)
3420 m_inspectorSettings = settings;
3423 bool WebViewImpl::inspectorSetting(const WebString& key, WebString* value) const
3425 if (!m_inspectorSettingsMap->contains(key))
3427 *value = m_inspectorSettingsMap->get(key);
3431 void WebViewImpl::setInspectorSetting(const WebString& key,
3432 const WebString& value)
3434 m_inspectorSettingsMap->set(key, value);
3435 client()->didUpdateInspectorSetting(key, value);
3438 void WebViewImpl::setCompositorDeviceScaleFactorOverride(float deviceScaleFactor)
3440 if (m_compositorDeviceScaleFactorOverride == deviceScaleFactor)
3442 m_compositorDeviceScaleFactorOverride = deviceScaleFactor;
3443 if (page() && m_layerTreeView)
3444 updateLayerTreeDeviceScaleFactor();
3447 void WebViewImpl::setRootLayerTransform(const WebSize& rootLayerOffset, float rootLayerScale)
3449 if (m_rootLayerScale == rootLayerScale && m_rootLayerOffset == rootLayerOffset)
3451 m_rootLayerScale = rootLayerScale;
3452 m_rootLayerOffset = rootLayerOffset;
3453 if (mainFrameImpl())
3454 mainFrameImpl()->setInputEventsTransformForEmulation(m_rootLayerOffset, m_rootLayerScale);
3455 updateRootLayerTransform();
3458 WebDevToolsAgent* WebViewImpl::devToolsAgent()
3460 return m_devToolsAgent.get();
3463 WebAXObject WebViewImpl::accessibilityObject()
3465 if (!mainFrameImpl())
3466 return WebAXObject();
3468 Document* document = mainFrameImpl()->frame()->document();
3470 document->axObjectCache()->getOrCreate(document->renderView()));
3473 void WebViewImpl::performCustomContextMenuAction(unsigned action)
3477 ContextMenu* menu = m_page->contextMenuController().contextMenu();
3480 const ContextMenuItem* item = menu->itemWithAction(static_cast<ContextMenuAction>(ContextMenuItemBaseCustomTag + action));
3482 m_page->contextMenuController().contextMenuItemSelected(item);
3483 m_page->contextMenuController().clearContextMenu();
3486 void WebViewImpl::showContextMenu()
3491 page()->contextMenuController().clearContextMenu();
3492 m_contextMenuAllowed = true;
3493 if (LocalFrame* focusedFrame = toLocalFrame(page()->focusController().focusedOrMainFrame()))
3494 focusedFrame->eventHandler().sendContextMenuEventForKey();
3495 m_contextMenuAllowed = false;
3498 WebString WebViewImpl::getSmartClipData(WebRect rect)
3500 LocalFrame* frame = toLocalFrame(focusedWebCoreFrame());
3503 return WebCore::SmartClip(frame).dataForRect(rect).toString();
3506 void WebViewImpl::hidePopups()
3510 closePagePopup(m_pagePopup.get());
3513 void WebViewImpl::setIsTransparent(bool isTransparent)
3515 // Set any existing frames to be transparent.
3516 Frame* frame = m_page->mainFrame();
3518 if (frame->isLocalFrame())
3519 toLocalFrame(frame)->view()->setTransparent(isTransparent);
3520 frame = frame->tree().traverseNext();
3523 // Future frames check this to know whether to be transparent.
3524 m_isTransparent = isTransparent;
3527 bool WebViewImpl::isTransparent() const
3529 return m_isTransparent;
3532 void WebViewImpl::setBaseBackgroundColor(WebColor color)
3536 if (m_baseBackgroundColor == color)
3539 m_baseBackgroundColor = color;
3541 if (m_page->mainFrame() && m_page->mainFrame()->isLocalFrame())
3542 m_page->deprecatedLocalMainFrame()->view()->setBaseBackgroundColor(color);
3544 updateLayerTreeBackgroundColor();
3547 void WebViewImpl::setIsActive(bool active)
3550 page()->focusController().setActive(active);
3553 bool WebViewImpl::isActive() const
3555 return page() ? page()->focusController().isActive() : false;
3558 void WebViewImpl::setDomainRelaxationForbidden(bool forbidden, const WebString& scheme)
3560 SchemeRegistry::setDomainRelaxationForbiddenForURLScheme(forbidden, String(scheme));
3563 void WebViewImpl::setWindowFeatures(const WebWindowFeatures& features)
3565 m_page->chrome().setWindowFeatures(features);
3568 void WebViewImpl::setOpenedByDOM()
3570 m_page->setOpenedByDOM();
3573 void WebViewImpl::setSelectionColors(unsigned activeBackgroundColor,
3574 unsigned activeForegroundColor,
3575 unsigned inactiveBackgroundColor,
3576 unsigned inactiveForegroundColor) {
3577 #if USE(DEFAULT_RENDER_THEME)
3578 RenderThemeChromiumDefault::setSelectionColors(activeBackgroundColor, activeForegroundColor, inactiveBackgroundColor, inactiveForegroundColor);
3579 RenderTheme::theme().platformColorsDidChange();
3583 void WebView::injectStyleSheet(const WebString& sourceCode, const WebVector<WebString>& patternsIn, WebView::StyleInjectionTarget injectIn)
3585 Vector<String> patterns;
3586 for (size_t i = 0; i < patternsIn.size(); ++i)
3587 patterns.append(patternsIn[i]);
3589 InjectedStyleSheets::instance().add(sourceCode, patterns, static_cast<WebCore::StyleInjectionTarget>(injectIn));
3592 void WebView::removeInjectedStyleSheets()
3594 InjectedStyleSheets::instance().removeAll();
3597 void WebViewImpl::didCommitLoad(bool isNewNavigation, bool isNavigationWithinPage)
3599 if (isNewNavigation && !isNavigationWithinPage)
3600 m_pageScaleConstraintsSet.setNeedsReset(true);
3602 // Make sure link highlight from previous page is cleared.
3603 m_linkHighlights.clear();
3604 endActiveFlingAnimation();
3605 m_userGestureObserved = false;
3608 void WebViewImpl::willInsertBody(WebLocalFrameImpl* webframe)
3610 if (webframe != mainFrameImpl())
3613 if (!m_page->mainFrame()->isLocalFrame())
3616 // If we get to the <body> tag and we have no pending stylesheet and import load, we
3617 // can be fairly confident we'll have something sensible to paint soon and
3618 // can turn off deferred commits.
3619 if (m_page->deprecatedLocalMainFrame()->document()->isRenderingReady())
3620 resumeTreeViewCommits();
3623 void WebViewImpl::resumeTreeViewCommits()
3625 if (m_layerTreeViewCommitsDeferred) {
3626 if (m_layerTreeView)
3627 m_layerTreeView->setDeferCommits(false);
3628 m_layerTreeViewCommitsDeferred = false;
3632 void WebViewImpl::layoutUpdated(WebLocalFrameImpl* webframe)
3634 if (!m_client || webframe != mainFrameImpl())
3637 // If we finished a layout while in deferred commit mode,
3638 // that means it's time to start producing frames again so un-defer.
3639 resumeTreeViewCommits();
3641 if (m_shouldAutoResize && mainFrameImpl()->frame() && mainFrameImpl()->frame()->view()) {
3642 WebSize frameSize = mainFrameImpl()->frame()->view()->frameRect().size();
3643 if (frameSize != m_size) {
3646 page()->frameHost().pinchViewport().setSize(m_size);
3647 m_pageScaleConstraintsSet.didChangeViewSize(m_size);
3649 m_client->didAutoResize(m_size);
3650 sendResizeEventAndRepaint();
3654 if (m_pageScaleConstraintsSet.constraintsDirty())
3655 refreshPageScaleFactorAfterLayout();
3657 m_client->didUpdateLayout();
3660 void WebViewImpl::didChangeContentsSize()
3662 m_pageScaleConstraintsSet.didChangeContentsSize(contentsSize(), pageScaleFactor());
3665 void WebViewImpl::deviceOrPageScaleFactorChanged()
3667 m_pageScaleConstraintsSet.setNeedsReset(false);
3668 updateLayerTreeViewport();
3671 bool WebViewImpl::useExternalPopupMenus()
3673 return shouldUseExternalPopupMenus;
3676 void WebViewImpl::startDragging(LocalFrame* frame,
3677 const WebDragData& dragData,
3678 WebDragOperationsMask mask,
3679 const WebImage& dragImage,
3680 const WebPoint& dragImageOffset)
3684 ASSERT(!m_doingDragAndDrop);
3685 m_doingDragAndDrop = true;
3686 m_client->startDragging(WebLocalFrameImpl::fromFrame(frame), dragData, mask, dragImage, dragImageOffset);
3689 void WebViewImpl::setIgnoreInputEvents(bool newValue)
3691 ASSERT(m_ignoreInputEvents != newValue);
3692 m_ignoreInputEvents = newValue;
3695 void WebViewImpl::setBackgroundColorOverride(WebColor color)
3697 m_backgroundColorOverride = color;
3698 updateLayerTreeBackgroundColor();
3701 void WebViewImpl::setZoomFactorOverride(float zoomFactor)
3703 m_zoomFactorOverride = zoomFactor;
3704 setZoomLevel(zoomLevel());
3707 void WebViewImpl::addPageOverlay(WebPageOverlay* overlay, int zOrder)
3709 if (!m_pageOverlays)
3710 m_pageOverlays = PageOverlayList::create(this);
3712 m_pageOverlays->add(overlay, zOrder);
3715 void WebViewImpl::removePageOverlay(WebPageOverlay* overlay)
3717 if (m_pageOverlays && m_pageOverlays->remove(overlay) && m_pageOverlays->empty())
3718 m_pageOverlays = nullptr;
3721 void WebViewImpl::setOverlayLayer(WebCore::GraphicsLayer* layer)
3723 if (!m_rootGraphicsLayer)
3726 if (!m_page->mainFrame()->isLocalFrame())
3729 if (pinchVirtualViewportEnabled()) {
3730 m_page->deprecatedLocalMainFrame()->view()->renderView()->compositor()->setOverlayLayer(layer);
3734 // FIXME(bokan): This path goes away after virtual viewport pinch is enabled everywhere.
3735 if (!m_rootTransformLayer)
3736 m_rootTransformLayer = m_page->deprecatedLocalMainFrame()->view()->renderView()->compositor()->ensureRootTransformLayer();
3738 if (m_rootTransformLayer) {
3739 if (layer->parent() != m_rootTransformLayer)
3740 m_rootTransformLayer->addChild(layer);
3744 Element* WebViewImpl::focusedElement() const
3746 Frame* frame = m_page->focusController().focusedFrame();
3747 if (!frame || !frame->isLocalFrame())
3750 Document* document = toLocalFrame(frame)->document();
3754 return document->focusedElement();
3757 HitTestResult WebViewImpl::hitTestResultForWindowPos(const IntPoint& pos)
3759 if (!m_page->mainFrame()->isLocalFrame())
3760 return HitTestResult();
3761 IntPoint docPoint(m_page->deprecatedLocalMainFrame()->view()->windowToContents(pos));
3762 return m_page->deprecatedLocalMainFrame()->eventHandler().hitTestResultAtPoint(docPoint, HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
3765 void WebViewImpl::setTabsToLinks(bool enable)
3767 m_tabsToLinks = enable;
3770 bool WebViewImpl::tabsToLinks() const
3772 return m_tabsToLinks;
3775 void WebViewImpl::suppressInvalidations(bool enable)
3778 m_client->suppressCompositorScheduling(enable);
3781 void WebViewImpl::setRootGraphicsLayer(GraphicsLayer* layer)
3783 suppressInvalidations(true);
3785 if (pinchVirtualViewportEnabled()) {
3786 PinchViewport& pinchViewport = page()->frameHost().pinchViewport();
3787 pinchViewport.attachToLayerTree(layer, graphicsLayerFactory());
3789 m_rootGraphicsLayer = pinchViewport.rootGraphicsLayer();
3790 m_rootLayer = pinchViewport.rootGraphicsLayer()->platformLayer();
3791 m_rootTransformLayer = pinchViewport.rootGraphicsLayer();
3793 m_rootGraphicsLayer = 0;
3795 m_rootTransformLayer = 0;
3798 m_rootGraphicsLayer = layer;
3799 m_rootLayer = layer ? layer->platformLayer() : 0;
3800 m_rootTransformLayer = 0;
3803 setIsAcceleratedCompositingActive(layer);
3805 updateRootLayerTransform();
3807 if (m_layerTreeView) {
3809 m_layerTreeView->setRootLayer(*m_rootLayer);
3810 // We register viewport layers here since there may not be a layer
3811 // tree view prior to this point.
3812 if (pinchVirtualViewportEnabled()) {
3813 page()->frameHost().pinchViewport().registerLayersWithTreeView(m_layerTreeView);
3815 GraphicsLayer* rootScrollLayer = compositor()->scrollLayer();
3816 ASSERT(rootScrollLayer);
3817 WebLayer* pageScaleLayer = rootScrollLayer->parent() ? rootScrollLayer->parent()->platformLayer() : 0;
3818 m_layerTreeView->registerViewportLayers(pageScaleLayer, rootScrollLayer->platformLayer(), 0);
3821 m_layerTreeView->clearRootLayer();
3822 if (pinchVirtualViewportEnabled())
3823 page()->frameHost().pinchViewport().clearLayersForTreeView(m_layerTreeView);
3825 m_layerTreeView->clearViewportLayers();
3829 suppressInvalidations(false);
3832 void WebViewImpl::scheduleCompositingLayerSync()
3834 m_layerTreeView->setNeedsAnimate();
3837 void WebViewImpl::scrollRootLayer()
3839 updateLayerTreeViewport();
3842 void WebViewImpl::invalidateRect(const IntRect& rect)
3844 if (m_isAcceleratedCompositingActive) {
3845 ASSERT(m_layerTreeView);
3846 updateLayerTreeViewport();
3847 } else if (m_client)
3848 m_client->didInvalidateRect(rect);
3851 WebCore::GraphicsLayerFactory* WebViewImpl::graphicsLayerFactory() const
3853 return m_graphicsLayerFactory.get();
3856 WebCore::RenderLayerCompositor* WebViewImpl::compositor() const
3859 || !page()->mainFrame()
3860 || !page()->mainFrame()->isLocalFrame()
3861 || !page()->deprecatedLocalMainFrame()->document()
3862 || !page()->deprecatedLocalMainFrame()->document()->renderView())
3864 return page()->deprecatedLocalMainFrame()->document()->renderView()->compositor();
3867 void WebViewImpl::registerForAnimations(WebLayer* layer)
3869 if (m_layerTreeView)
3870 m_layerTreeView->registerForAnimations(layer);
3873 WebCore::GraphicsLayer* WebViewImpl::rootGraphicsLayer()
3875 return m_rootGraphicsLayer;
3878 void WebViewImpl::scheduleAnimation()
3880 if (isAcceleratedCompositingActive()) {
3881 ASSERT(m_layerTreeView);
3882 m_layerTreeView->setNeedsAnimate();
3886 m_client->scheduleAnimation();
3889 void WebViewImpl::setIsAcceleratedCompositingActive(bool active)
3891 blink::Platform::current()->histogramEnumeration("GPU.setIsAcceleratedCompositingActive", active * 2 + m_isAcceleratedCompositingActive, 4);
3893 if (m_isAcceleratedCompositingActive == active)
3900 m_isAcceleratedCompositingActive = false;
3901 if (!m_layerTreeViewCommitsDeferred
3902 && blink::Platform::current()->isThreadedCompositingEnabled()) {
3903 ASSERT(m_layerTreeView);
3904 // In threaded compositing mode, force compositing mode is always on so setIsAcceleratedCompositingActive(false)
3905 // means that we're transitioning to a new page. Suppress commits until WebKit generates invalidations so
3906 // we don't attempt to paint too early in the next page load.
3907 m_layerTreeView->setDeferCommits(true);
3908 m_layerTreeViewCommitsDeferred = true;
3910 } else if (m_layerTreeView) {
3911 m_isAcceleratedCompositingActive = true;
3912 updateLayerTreeViewport();
3914 m_pageOverlays->update();
3916 TRACE_EVENT0("webkit", "WebViewImpl::setIsAcceleratedCompositingActive(true)");
3918 m_client->initializeLayerTreeView();
3919 m_layerTreeView = m_client->layerTreeView();
3920 if (m_layerTreeView) {
3921 m_layerTreeView->setRootLayer(*m_rootLayer);
3923 bool visible = page()->visibilityState() == PageVisibilityStateVisible;
3924 m_layerTreeView->setVisible(visible);
3925 updateLayerTreeDeviceScaleFactor();
3926 m_layerTreeView->setPageScaleFactorAndLimits(pageScaleFactor(), minimumPageScaleFactor(), maximumPageScaleFactor());
3927 updateLayerTreeBackgroundColor();
3928 m_layerTreeView->setHasTransparentBackground(isTransparent());
3929 #if USE(RUBBER_BANDING)
3930 RefPtr<Image> overhangImage = OverscrollTheme::theme()->getOverhangImage();
3931 if (overhangImage && overhangImage->nativeImageForCurrentFrame())
3932 m_layerTreeView->setOverhangBitmap(overhangImage->nativeImageForCurrentFrame()->bitmap());
3934 updateLayerTreeViewport();
3935 m_isAcceleratedCompositingActive = true;
3937 m_pageOverlays->update();
3938 m_layerTreeView->setShowFPSCounter(m_showFPSCounter);
3939 m_layerTreeView->setShowPaintRects(m_showPaintRects);
3940 m_layerTreeView->setShowDebugBorders(m_showDebugBorders);
3941 m_layerTreeView->setContinuousPaintingEnabled(m_continuousPaintingEnabled);
3942 m_layerTreeView->setShowScrollBottleneckRects(m_showScrollBottleneckRects);
3943 m_layerTreeView->heuristicsForGpuRasterizationUpdated(m_matchesHeuristicsForGpuRasterization);
3945 // FIXME: It appears that only unittests, <webview> and android webview
3946 // printing can hit this code. We should make them not hit this code and
3947 // then delete this else clause and allowsBrokenNullLayerTreeView.
3948 // crbug.com/322276 and crbug.com/364716.
3949 ASSERT(m_client->allowsBrokenNullLayerTreeView());
3950 m_isAcceleratedCompositingActive = false;
3951 m_page->settings().setAcceleratedCompositingEnabled(false);
3952 m_page->updateAcceleratedCompositingSettings();
3955 if (page() && page()->mainFrame()->isLocalFrame())
3956 page()->deprecatedLocalMainFrame()->view()->setClipsRepaints(!m_isAcceleratedCompositingActive);
3959 void WebViewImpl::updateMainFrameScrollPosition(const IntPoint& scrollPosition, bool programmaticScroll)
3961 if (!page()->mainFrame()->isLocalFrame())
3964 FrameView* frameView = page()->deprecatedLocalMainFrame()->view();
3968 if (frameView->scrollPosition() == scrollPosition)
3971 bool oldProgrammaticScroll = frameView->inProgrammaticScroll();
3972 frameView->setInProgrammaticScroll(programmaticScroll);
3973 frameView->notifyScrollPositionChanged(scrollPosition);
3974 frameView->setInProgrammaticScroll(oldProgrammaticScroll);
3977 void WebViewImpl::applyScrollAndScale(const WebSize& scrollDelta, float pageScaleDelta)
3979 if (!mainFrameImpl() || !mainFrameImpl()->frameView())
3982 if (pinchVirtualViewportEnabled()) {
3983 if (pageScaleDelta != 1) {
3984 // When the virtual viewport is enabled, offsets are already set for us.
3985 setPageScaleFactor(pageScaleFactor() * pageScaleDelta);
3986 m_doubleTapZoomPending = false;
3992 // TODO(bokan): Old pinch path only - virtual viewport pinch scrolls are automatically updated via GraphicsLayer::DidScroll.
3993 // this should be removed once old pinch is removed.
3994 if (pageScaleDelta == 1) {
3995 TRACE_EVENT_INSTANT2("webkit", "WebViewImpl::applyScrollAndScale::scrollBy", "x", scrollDelta.width, "y", scrollDelta.height);
3996 WebSize webScrollOffset = mainFrame()->scrollOffset();
3997 IntPoint scrollOffset(webScrollOffset.width + scrollDelta.width, webScrollOffset.height + scrollDelta.height);
3998 updateMainFrameScrollPosition(scrollOffset, false);
4000 // The page scale changed, so apply a scale and scroll in a single
4002 WebSize scrollOffset = mainFrame()->scrollOffset();
4003 scrollOffset.width += scrollDelta.width;
4004 scrollOffset.height += scrollDelta.height;
4006 WebPoint scrollPoint(scrollOffset.width, scrollOffset.height);
4007 setPageScaleFactor(pageScaleFactor() * pageScaleDelta, scrollPoint);
4008 m_doubleTapZoomPending = false;
4012 void WebViewImpl::updateLayerTreeViewport()
4014 if (!page() || !m_layerTreeView)
4017 m_layerTreeView->setPageScaleFactorAndLimits(pageScaleFactor(), minimumPageScaleFactor(), maximumPageScaleFactor());
4020 void WebViewImpl::updateLayerTreeBackgroundColor()
4022 if (!m_layerTreeView)
4025 m_layerTreeView->setBackgroundColor(alphaChannel(m_backgroundColorOverride) ? m_backgroundColorOverride : backgroundColor());
4028 void WebViewImpl::updateLayerTreeDeviceScaleFactor()
4031 ASSERT(m_layerTreeView);
4033 float deviceScaleFactor = m_compositorDeviceScaleFactorOverride ? m_compositorDeviceScaleFactorOverride : page()->deviceScaleFactor();
4034 m_layerTreeView->setDeviceScaleFactor(deviceScaleFactor);
4037 void WebViewImpl::updateRootLayerTransform()
4039 // If we don't have a root graphics layer, we won't bother trying to find
4040 // or update the transform layer.
4041 if (!m_rootGraphicsLayer)
4044 // FIXME(bokan): m_rootTransformLayer is always set here in pinch virtual viewport. This can go away once
4045 // that's default everywhere.
4046 if (!m_rootTransformLayer && m_page->mainFrame()->isLocalFrame())
4047 m_rootTransformLayer = m_page->deprecatedLocalMainFrame()->view()->renderView()->compositor()->ensureRootTransformLayer();
4049 if (m_rootTransformLayer) {
4050 WebCore::TransformationMatrix transform;
4051 transform.translate(m_rootLayerOffset.width, m_rootLayerOffset.height);
4052 transform = transform.scale(m_rootLayerScale);
4053 m_rootTransformLayer->setTransform(transform);
4057 bool WebViewImpl::detectContentOnTouch(const WebPoint& position)
4059 HitTestResult touchHit = hitTestResultForWindowPos(position);
4061 if (touchHit.isContentEditable())
4064 Node* node = touchHit.innerNode();
4065 if (!node || !node->isTextNode())
4068 // Ignore when tapping on links or nodes listening to click events, unless the click event is on the
4069 // body element, in which case it's unlikely that the original node itself was intended to be clickable.
4070 for (; node && !isHTMLBodyElement(*node); node = node->parentNode()) {
4071 if (node->isLink() || node->willRespondToTouchEvents() || node->willRespondToMouseClickEvents())
4075 WebContentDetectionResult content = m_client->detectContentAround(touchHit);
4076 if (!content.isValid())
4079 m_client->scheduleContentIntent(content.intent());
4083 void WebViewImpl::setVisibilityState(WebPageVisibilityState visibilityState,
4084 bool isInitialState) {
4088 ASSERT(visibilityState == WebPageVisibilityStateVisible || visibilityState == WebPageVisibilityStateHidden || visibilityState == WebPageVisibilityStatePrerender);
4089 m_page->setVisibilityState(static_cast<PageVisibilityState>(static_cast<int>(visibilityState)), isInitialState);
4091 if (m_layerTreeView) {
4092 bool visible = visibilityState == WebPageVisibilityStateVisible;
4093 m_layerTreeView->setVisible(visible);
4097 bool WebViewImpl::requestPointerLock()
4099 return m_client && m_client->requestPointerLock();
4102 void WebViewImpl::requestPointerUnlock()
4105 m_client->requestPointerUnlock();
4108 bool WebViewImpl::isPointerLocked()
4110 return m_client && m_client->isPointerLocked();
4113 void WebViewImpl::pointerLockMouseEvent(const WebInputEvent& event)
4115 AtomicString eventType;
4116 switch (event.type) {
4117 case WebInputEvent::MouseDown:
4118 eventType = EventTypeNames::mousedown;
4120 case WebInputEvent::MouseUp:
4121 eventType = EventTypeNames::mouseup;
4123 case WebInputEvent::MouseMove:
4124 eventType = EventTypeNames::mousemove;
4127 ASSERT_NOT_REACHED();
4130 const WebMouseEvent& mouseEvent = static_cast<const WebMouseEvent&>(event);
4133 page()->pointerLockController().dispatchLockedMouseEvent(
4134 PlatformMouseEventBuilder(mainFrameImpl()->frameView(), mouseEvent),
4138 bool WebViewImpl::shouldDisableDesktopWorkarounds()
4140 if (!settings()->viewportEnabled())
4143 // A document is considered adapted to small screen UAs if one of these holds:
4144 // 1. The author specified viewport has a constrained width that is equal to
4145 // the initial viewport width.
4146 // 2. The author has disabled viewport zoom.
4148 const PageScaleConstraints& constraints = m_pageScaleConstraintsSet.pageDefinedConstraints();
4150 if (!mainFrameImpl() || !mainFrameImpl()->frameView())
4153 return mainFrameImpl()->frameView()->layoutSize().width() == m_size.width
4154 || (constraints.minimumScale == constraints.maximumScale && constraints.minimumScale != -1);
4157 } // namespace blink