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