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