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