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