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