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