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