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