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