diff options
author | Allan Sandfeld Jensen <allan.jensen@digia.com> | 2013-09-13 12:51:20 +0200 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-09-19 20:50:05 +0200 |
commit | d441d6f39bb846989d95bcf5caf387b42414718d (patch) | |
tree | e367e64a75991c554930278175d403c072de6bb8 /Source/WebKit/chromium/src/WebViewImpl.cpp | |
parent | 0060b2994c07842f4c59de64b5e3e430525c4b90 (diff) | |
download | qtwebkit-d441d6f39bb846989d95bcf5caf387b42414718d.tar.gz |
Import Qt5x2 branch of QtWebkit for Qt 5.2
Importing a new snapshot of webkit.
Change-Id: I2d01ad12cdc8af8cb015387641120a9d7ea5f10c
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@digia.com>
Diffstat (limited to 'Source/WebKit/chromium/src/WebViewImpl.cpp')
-rw-r--r-- | Source/WebKit/chromium/src/WebViewImpl.cpp | 4346 |
1 files changed, 0 insertions, 4346 deletions
diff --git a/Source/WebKit/chromium/src/WebViewImpl.cpp b/Source/WebKit/chromium/src/WebViewImpl.cpp deleted file mode 100644 index f66ae48c4..000000000 --- a/Source/WebKit/chromium/src/WebViewImpl.cpp +++ /dev/null @@ -1,4346 +0,0 @@ -/* - * Copyright (C) 2011, 2012 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "WebViewImpl.h" - -#include "AXObjectCache.h" -#include "AutofillPopupMenuClient.h" -#include "BackForwardListChromium.h" -#include "BatteryClientImpl.h" -#include "BatteryController.h" -#include "CSSValueKeywords.h" -#include "Chrome.h" -#include "Color.h" -#include "ColorSpace.h" -#include "CompositionUnderlineVectorBuilder.h" -#include "CompositorHUDFontAtlas.h" -#include "ContextFeaturesClientImpl.h" -#include "ContextMenu.h" -#include "ContextMenuController.h" -#include "ContextMenuItem.h" -#include "Cursor.h" -#include "DOMUtilitiesPrivate.h" -#include "DeviceOrientationClientProxy.h" -#include "Document.h" -#include "DocumentLoader.h" -#include "DragController.h" -#include "DragData.h" -#include "DragScrollTimer.h" -#include "DragSession.h" -#include "Editor.h" -#include "EventHandler.h" -#include "Extensions3D.h" -#include "FocusController.h" -#include "FontDescription.h" -#include "Frame.h" -#include "FrameLoader.h" -#include "FrameSelection.h" -#include "FrameTree.h" -#include "FrameView.h" -#include "GeolocationClientProxy.h" -#include "GeolocationController.h" -#include "GraphicsContext.h" -#include "GraphicsContext3D.h" -#include "GraphicsContext3DPrivate.h" -#include "HTMLInputElement.h" -#include "HTMLMediaElement.h" -#include "HTMLNames.h" -#include "HTMLTextAreaElement.h" -#include "HitTestResult.h" -#include "Image.h" -#include "ImageBuffer.h" -#include "InspectorController.h" -#include "InspectorInstrumentation.h" -#include "KeyboardCodes.h" -#include "KeyboardEvent.h" -#include "LayerPainterChromium.h" -#include "LinkHighlight.h" -#include "MIMETypeRegistry.h" -#include "NodeRenderStyle.h" -#include "NonCompositedContentHost.h" -#include "Page.h" -#include "PageGroup.h" -#include "PageGroupLoadDeferrer.h" -#include "PagePopupClient.h" -#include "PageWidgetDelegate.h" -#include "PlatformContextSkia.h" -#include "PlatformKeyboardEvent.h" -#include "PlatformMouseEvent.h" -#include "PlatformWheelEvent.h" -#include "PointerLockController.h" -#include "PopupContainer.h" -#include "PopupMenuClient.h" -#include "PrerendererClientImpl.h" -#include "ProgressTracker.h" -#include "RenderLayerCompositor.h" -#include "RenderView.h" -#include "RenderWidget.h" -#include "ResourceHandle.h" -#include "SchemeRegistry.h" -#include "SecurityOrigin.h" -#include "SecurityPolicy.h" -#include "Settings.h" -#include "SharedGraphicsContext3D.h" -#include "SpeechInputClientImpl.h" -#include "SpeechRecognitionClientProxy.h" -#include "StyleResolver.h" -#include "Text.h" -#include "TextFieldDecoratorImpl.h" -#include "TextIterator.h" -#include "Timer.h" -#include "TraceEvent.h" -#include "ValidationMessageClientImpl.h" -#include "WebAccessibilityObject.h" -#include "WebActiveWheelFlingParameters.h" -#include "WebAutofillClient.h" -#include "WebCompositorInputHandlerImpl.h" -#include "WebDevToolsAgentImpl.h" -#include "WebDevToolsAgentPrivate.h" -#include "WebFrameImpl.h" -#include "WebHelperPluginImpl.h" -#include "WebHitTestResult.h" -#include "WebInputElement.h" -#include "WebInputEvent.h" -#include "WebInputEventConversion.h" -#include "WebMediaPlayerAction.h" -#include "WebNode.h" -#include "WebPagePopupImpl.h" -#include "WebPlugin.h" -#include "WebPluginAction.h" -#include "WebPluginContainerImpl.h" -#include "WebPopupMenuImpl.h" -#include "WebRange.h" -#include "WebRuntimeFeatures.h" -#include "WebSettingsImpl.h" -#include "WebTextInputInfo.h" -#include "WebViewClient.h" -#include "WheelEvent.h" -#include "painting/GraphicsContextBuilder.h" -#include "src/WebActiveGestureAnimation.h" -#include <public/Platform.h> -#include <public/WebCompositorOutputSurface.h> -#include <public/WebCompositorSupport.h> -#include <public/WebDragData.h> -#include <public/WebFloatPoint.h> -#include <public/WebGraphicsContext3D.h> -#include <public/WebImage.h> -#include <public/WebLayer.h> -#include <public/WebLayerTreeView.h> -#include <public/WebPoint.h> -#include <public/WebRect.h> -#include <public/WebString.h> -#include <public/WebVector.h> -#include <wtf/CurrentTime.h> -#include <wtf/MainThread.h> -#include <wtf/RefPtr.h> -#include <wtf/TemporaryChange.h> -#include <wtf/Uint8ClampedArray.h> - -#if ENABLE(DEFAULT_RENDER_THEME) -#include "PlatformThemeChromiumDefault.h" -#include "RenderThemeChromiumDefault.h" -#endif - -#if ENABLE(GESTURE_EVENTS) -#include "PlatformGestureEvent.h" -#include "TouchDisambiguation.h" -#endif - -#if OS(WINDOWS) -#if !ENABLE(DEFAULT_RENDER_THEME) -#include "RenderThemeChromiumWin.h" -#endif -#else -#if OS(UNIX) && !OS(DARWIN) && !ENABLE(DEFAULT_RENDER_THEME) -#include "PlatformThemeChromiumLinux.h" -#include "RenderThemeChromiumLinux.h" -#endif -#include "RenderTheme.h" -#endif - -// Get rid of WTF's pow define so we can use std::pow. -#undef pow -#include <cmath> // for std::pow - -using namespace WebCore; -using namespace std; - -// The following constants control parameters for automated scaling of webpages -// (such as due to a double tap gesture or find in page etc.). These are -// experimentally determined. -static const int touchPointPadding = 32; -static const int nonUserInitiatedPointPadding = 11; -static const float minScaleDifference = 0.01f; -static const float doubleTapZoomContentDefaultMargin = 5; -static const float doubleTapZoomContentMinimumMargin = 2; -static const double doubleTapZoomAnimationDurationInSeconds = 0.25; -static const float doubleTapZoomAlreadyLegibleRatio = 1.2f; - -// Constants for zooming in on a focused text field. -static const double scrollAndScaleAnimationDurationInSeconds = 0.2; -static const int minReadableCaretHeight = 18; -static const float minScaleChangeToTriggerZoom = 1.05f; -static const float leftBoxRatio = 0.3f; -static const int caretPadding = 10; - -namespace WebKit { - -// Change the text zoom level by kTextSizeMultiplierRatio each time the user -// zooms text in or out (ie., change by 20%). The min and max values limit -// text zoom to half and 3x the original text size. These three values match -// those in Apple's port in WebKit/WebKit/WebView/WebView.mm -const double WebView::textSizeMultiplierRatio = 1.2; -const double WebView::minTextSizeMultiplier = 0.5; -const double WebView::maxTextSizeMultiplier = 3.0; -const float WebView::minPageScaleFactor = 0.25f; -const float WebView::maxPageScaleFactor = 4.0f; - - -// The group name identifies a namespace of pages. Page group is used on PLATFORM(MAC) -// for some programs that use HTML views to display things that don't seem like -// web pages to the user (so shouldn't have visited link coloring). We only use -// one page group. -const char* pageGroupName = "default"; - -// Used to defer all page activity in cases where the embedder wishes to run -// a nested event loop. Using a stack enables nesting of message loop invocations. -static Vector<PageGroupLoadDeferrer*>& pageGroupLoadDeferrerStack() -{ - DEFINE_STATIC_LOCAL(Vector<PageGroupLoadDeferrer*>, deferrerStack, ()); - return deferrerStack; -} - -// Ensure that the WebDragOperation enum values stay in sync with the original -// DragOperation constants. -#define COMPILE_ASSERT_MATCHING_ENUM(coreName) \ - COMPILE_ASSERT(int(coreName) == int(Web##coreName), dummy##coreName) -COMPILE_ASSERT_MATCHING_ENUM(DragOperationNone); -COMPILE_ASSERT_MATCHING_ENUM(DragOperationCopy); -COMPILE_ASSERT_MATCHING_ENUM(DragOperationLink); -COMPILE_ASSERT_MATCHING_ENUM(DragOperationGeneric); -COMPILE_ASSERT_MATCHING_ENUM(DragOperationPrivate); -COMPILE_ASSERT_MATCHING_ENUM(DragOperationMove); -COMPILE_ASSERT_MATCHING_ENUM(DragOperationDelete); -COMPILE_ASSERT_MATCHING_ENUM(DragOperationEvery); - -static const PopupContainerSettings autofillPopupSettings = { - false, // setTextOnIndexChange - false, // acceptOnAbandon - true, // loopSelectionNavigation - false // restrictWidthOfListBox (For security reasons show the entire entry - // so the user doesn't enter information he did not intend to.) -}; - -static bool shouldUseExternalPopupMenus = false; - -static int webInputEventKeyStateToPlatformEventKeyState(int webInputEventKeyState) -{ - int platformEventKeyState = 0; - if (webInputEventKeyState & WebInputEvent::ShiftKey) - platformEventKeyState = platformEventKeyState | WebCore::PlatformEvent::ShiftKey; - if (webInputEventKeyState & WebInputEvent::ControlKey) - platformEventKeyState = platformEventKeyState | WebCore::PlatformEvent::CtrlKey; - if (webInputEventKeyState & WebInputEvent::AltKey) - platformEventKeyState = platformEventKeyState | WebCore::PlatformEvent::AltKey; - if (webInputEventKeyState & WebInputEvent::MetaKey) - platformEventKeyState = platformEventKeyState | WebCore::PlatformEvent::MetaKey; - return platformEventKeyState; -} - -// WebView ---------------------------------------------------------------- - -WebView* WebView::create(WebViewClient* client) -{ - // Pass the WebViewImpl's self-reference to the caller. - return adoptRef(new WebViewImpl(client)).leakRef(); -} - -void WebView::setUseExternalPopupMenus(bool useExternalPopupMenus) -{ - shouldUseExternalPopupMenus = useExternalPopupMenus; -} - -void WebView::updateVisitedLinkState(unsigned long long linkHash) -{ - Page::visitedStateChanged(PageGroup::pageGroup(pageGroupName), linkHash); -} - -void WebView::resetVisitedLinkState() -{ - Page::allVisitedStateChanged(PageGroup::pageGroup(pageGroupName)); -} - -void WebView::willEnterModalLoop() -{ - PageGroup* pageGroup = PageGroup::pageGroup(pageGroupName); - ASSERT(pageGroup); - - if (pageGroup->pages().isEmpty()) - pageGroupLoadDeferrerStack().append(static_cast<PageGroupLoadDeferrer*>(0)); - else { - // Pick any page in the page group since we are deferring all pages. - pageGroupLoadDeferrerStack().append(new PageGroupLoadDeferrer(*pageGroup->pages().begin(), true)); - } -} - -void WebView::didExitModalLoop() -{ - ASSERT(pageGroupLoadDeferrerStack().size()); - - delete pageGroupLoadDeferrerStack().last(); - pageGroupLoadDeferrerStack().removeLast(); -} - -void WebViewImpl::initializeMainFrame(WebFrameClient* frameClient) -{ - // NOTE: The WebFrameImpl takes a reference to itself within InitMainFrame - // and releases that reference once the corresponding Frame is destroyed. - RefPtr<WebFrameImpl> frame = WebFrameImpl::create(frameClient); - - frame->initializeAsMainFrame(page()); - - // Restrict the access to the local file system - // (see WebView.mm WebView::_commonInitializationWithFrameName). - SecurityPolicy::setLocalLoadPolicy(SecurityPolicy::AllowLocalLoadsForLocalOnly); -} - -void WebViewImpl::initializeHelperPluginFrame(WebFrameClient* client) -{ - RefPtr<WebFrameImpl> frame = WebFrameImpl::create(client); -} - -void WebViewImpl::setAutofillClient(WebAutofillClient* autofillClient) -{ - m_autofillClient = autofillClient; -} - -void WebViewImpl::setDevToolsAgentClient(WebDevToolsAgentClient* devToolsClient) -{ - if (devToolsClient) - m_devToolsAgent = adoptPtr(new WebDevToolsAgentImpl(this, devToolsClient)); - else - m_devToolsAgent.clear(); -} - -void WebViewImpl::setPermissionClient(WebPermissionClient* permissionClient) -{ - m_permissionClient = permissionClient; - m_featureSwitchClient->setPermissionClient(permissionClient); -} - -void WebViewImpl::setPrerendererClient(WebPrerendererClient* prerendererClient) -{ - providePrerendererClientTo(m_page.get(), new PrerendererClientImpl(prerendererClient)); -} - -void WebViewImpl::setSpellCheckClient(WebSpellCheckClient* spellCheckClient) -{ - m_spellCheckClient = spellCheckClient; -} - -void WebViewImpl::addTextFieldDecoratorClient(WebTextFieldDecoratorClient* client) -{ - ASSERT(client); - // We limit the number of decorators because it affects performance of text - // field creation. If you'd like to add more decorators, consider moving - // your decorator or existing decorators to WebCore. - const unsigned maximumNumberOfDecorators = 8; - if (m_textFieldDecorators.size() >= maximumNumberOfDecorators) - CRASH(); - m_textFieldDecorators.append(TextFieldDecoratorImpl::create(client)); -} - -WebViewImpl::WebViewImpl(WebViewClient* client) - : m_client(client) - , m_autofillClient(0) - , m_permissionClient(0) - , m_spellCheckClient(0) - , m_chromeClientImpl(this) - , m_contextMenuClientImpl(this) - , m_dragClientImpl(this) - , m_editorClientImpl(this) - , m_inspectorClientImpl(this) - , m_shouldAutoResize(false) - , m_observedNewNavigation(false) -#ifndef NDEBUG - , m_newNavigationLoader(0) -#endif - , m_zoomLevel(0) - , m_minimumZoomLevel(zoomFactorToZoomLevel(minTextSizeMultiplier)) - , m_maximumZoomLevel(zoomFactorToZoomLevel(maxTextSizeMultiplier)) - , m_pageDefinedMinimumPageScaleFactor(-1) - , m_pageDefinedMaximumPageScaleFactor(-1) - , m_minimumPageScaleFactor(minPageScaleFactor) - , m_maximumPageScaleFactor(maxPageScaleFactor) - , m_ignoreViewportTagMaximumScale(false) - , m_pageScaleFactorIsSet(false) - , m_savedPageScaleFactor(0) - , m_doubleTapZoomInEffect(false) - , m_shouldUseDoubleTapTimeZero(false) - , m_contextMenuAllowed(false) - , m_doingDragAndDrop(false) - , m_ignoreInputEvents(false) - , m_suppressNextKeypressEvent(false) - , m_initialNavigationPolicy(WebNavigationPolicyIgnore) - , m_imeAcceptEvents(true) - , m_operationsAllowed(WebDragOperationNone) - , m_dragOperation(WebDragOperationNone) - , m_featureSwitchClient(adoptPtr(new ContextFeaturesClientImpl())) - , m_autofillPopupShowing(false) - , m_autofillPopup(0) - , m_isTransparent(false) - , m_tabsToLinks(false) - , m_dragScrollTimer(adoptPtr(new DragScrollTimer)) - , m_isCancelingFullScreen(false) - , m_benchmarkSupport(this) -#if USE(ACCELERATED_COMPOSITING) - , m_rootLayer(0) - , m_rootGraphicsLayer(0) - , m_isAcceleratedCompositingActive(false) - , m_layerTreeViewCommitsDeferred(false) - , m_compositorCreationFailed(false) - , m_recreatingGraphicsContext(false) - , m_compositorSurfaceReady(false) - , m_deviceScaleInCompositor(1) - , m_inputHandlerIdentifier(-1) - , m_isFontAtlasLoaded(false) -#endif -#if ENABLE(INPUT_SPEECH) - , m_speechInputClient(SpeechInputClientImpl::create(client)) -#endif -#if ENABLE(SCRIPTED_SPEECH) - , m_speechRecognitionClient(SpeechRecognitionClientProxy::create(client ? client->speechRecognizer() : 0)) -#endif - , m_deviceOrientationClientProxy(adoptPtr(new DeviceOrientationClientProxy(client ? client->deviceOrientationClient() : 0))) - , m_geolocationClientProxy(adoptPtr(new GeolocationClientProxy(client ? client->geolocationClient() : 0))) -#if ENABLE(BATTERY_STATUS) - , m_batteryClient(adoptPtr(new BatteryClientImpl(client ? client->batteryStatusClient() : 0))) -#endif - , m_emulatedTextZoomFactor(1) -#if ENABLE(MEDIA_STREAM) - , m_userMediaClientImpl(this) -#endif -#if ENABLE(NAVIGATOR_CONTENT_UTILS) - , m_navigatorContentUtilsClient(NavigatorContentUtilsClientImpl::create(this)) -#endif - , m_flingModifier(0) - , m_validationMessage(ValidationMessageClientImpl::create(*client)) - , m_suppressInvalidations(false) -{ - // WebKit/win/WebView.cpp does the same thing, except they call the - // KJS specific wrapper around this method. We need to have threading - // initialized because CollatorICU requires it. - WTF::initializeThreading(); - WTF::initializeMainThread(); - - Page::PageClients pageClients; - pageClients.chromeClient = &m_chromeClientImpl; - pageClients.contextMenuClient = &m_contextMenuClientImpl; - pageClients.editorClient = &m_editorClientImpl; - pageClients.dragClient = &m_dragClientImpl; - pageClients.inspectorClient = &m_inspectorClientImpl; - pageClients.backForwardClient = BackForwardListChromium::create(this); - // FIXME: Set pageClients.validationMessageClient when Chromium-side implementation is done. - - m_page = adoptPtr(new Page(pageClients)); -#if ENABLE(MEDIA_STREAM) - provideUserMediaTo(m_page.get(), &m_userMediaClientImpl); -#endif -#if ENABLE(INPUT_SPEECH) - provideSpeechInputTo(m_page.get(), m_speechInputClient.get()); -#endif -#if ENABLE(SCRIPTED_SPEECH) - provideSpeechRecognitionTo(m_page.get(), m_speechRecognitionClient.get()); -#endif -#if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS) - provideNotification(m_page.get(), notificationPresenterImpl()); -#endif -#if ENABLE(NAVIGATOR_CONTENT_UTILS) - provideNavigatorContentUtilsTo(m_page.get(), m_navigatorContentUtilsClient.get()); -#endif - - provideContextFeaturesTo(m_page.get(), m_featureSwitchClient.get()); - provideDeviceOrientationTo(m_page.get(), m_deviceOrientationClientProxy.get()); - provideGeolocationTo(m_page.get(), m_geolocationClientProxy.get()); - m_geolocationClientProxy->setController(GeolocationController::from(m_page.get())); - -#if ENABLE(BATTERY_STATUS) - provideBatteryTo(m_page.get(), m_batteryClient.get()); - m_batteryClient->setController(BatteryController::from(m_page.get())); -#endif - - m_page->setGroupName(pageGroupName); - - unsigned layoutMilestones = DidFirstLayout | DidFirstVisuallyNonEmptyLayout; - m_page->addLayoutMilestones(static_cast<LayoutMilestones>(layoutMilestones)); - -#if ENABLE(PAGE_VISIBILITY_API) - if (m_client) - setVisibilityState(m_client->visibilityState(), true); -#endif - - m_inspectorSettingsMap = adoptPtr(new SettingsMap); -} - -WebViewImpl::~WebViewImpl() -{ - ASSERT(!m_page); -} - -RenderTheme* WebViewImpl::theme() const -{ - return m_page ? m_page->theme() : RenderTheme::defaultTheme().get(); -} - -WebFrameImpl* WebViewImpl::mainFrameImpl() -{ - return m_page ? WebFrameImpl::fromFrame(m_page->mainFrame()) : 0; -} - -bool WebViewImpl::tabKeyCyclesThroughElements() const -{ - ASSERT(m_page); - return m_page->tabKeyCyclesThroughElements(); -} - -void WebViewImpl::setTabKeyCyclesThroughElements(bool value) -{ - if (m_page) - m_page->setTabKeyCyclesThroughElements(value); -} - -void WebViewImpl::handleMouseLeave(Frame& mainFrame, const WebMouseEvent& event) -{ - m_client->setMouseOverURL(WebURL()); - PageWidgetEventHandler::handleMouseLeave(mainFrame, event); -} - -void WebViewImpl::handleMouseDown(Frame& mainFrame, const WebMouseEvent& event) -{ - // If there is a popup open, close it as the user is clicking on the page (outside of the - // popup). We also save it so we can prevent a click on an element from immediately - // reopening the same popup. - RefPtr<WebCore::PopupContainer> selectPopup; -#if ENABLE(PAGE_POPUP) - RefPtr<WebPagePopupImpl> pagePopup; -#endif - if (event.button == WebMouseEvent::ButtonLeft) { - selectPopup = m_selectPopup; -#if ENABLE(PAGE_POPUP) - pagePopup = m_pagePopup; -#endif - hidePopups(); - ASSERT(!m_selectPopup); -#if ENABLE(PAGE_POPUP) - ASSERT(!m_pagePopup); -#endif - } - - m_lastMouseDownPoint = WebPoint(event.x, event.y); - - if (event.button == WebMouseEvent::ButtonLeft) { - IntPoint point(event.x, event.y); - point = m_page->mainFrame()->view()->windowToContents(point); - HitTestResult result(m_page->mainFrame()->eventHandler()->hitTestResultAtPoint(point, false)); - Node* hitNode = result.innerNonSharedNode(); - - // Take capture on a mouse down on a plugin so we can send it mouse events. - if (hitNode && hitNode->renderer() && hitNode->renderer()->isEmbeddedObject()) - m_mouseCaptureNode = hitNode; - } - - PageWidgetEventHandler::handleMouseDown(mainFrame, event); - - if (m_selectPopup && m_selectPopup == selectPopup) { - // That click triggered a select popup which is the same as the one that - // was showing before the click. It means the user clicked the select - // while the popup was showing, and as a result we first closed then - // immediately reopened the select popup. It needs to be closed. - hideSelectPopup(); - } - -#if ENABLE(PAGE_POPUP) - if (m_pagePopup && pagePopup && m_pagePopup->hasSamePopupClient(pagePopup.get())) { - // That click triggered a page popup that is the same as the one we just closed. - // It needs to be closed. - closePagePopup(m_pagePopup.get()); - } -#endif - - // Dispatch the contextmenu event regardless of if the click was swallowed. - // On Windows, we handle it on mouse up, not down. -#if OS(DARWIN) - if (event.button == WebMouseEvent::ButtonRight - || (event.button == WebMouseEvent::ButtonLeft - && event.modifiers & WebMouseEvent::ControlKey)) - mouseContextMenu(event); -#elif OS(UNIX) || OS(ANDROID) - if (event.button == WebMouseEvent::ButtonRight) - mouseContextMenu(event); -#endif -} - -void WebViewImpl::mouseContextMenu(const WebMouseEvent& event) -{ - if (!mainFrameImpl() || !mainFrameImpl()->frameView()) - return; - - m_page->contextMenuController()->clearContextMenu(); - - PlatformMouseEventBuilder pme(mainFrameImpl()->frameView(), event); - - // Find the right target frame. See issue 1186900. - HitTestResult result = hitTestResultForWindowPos(pme.position()); - Frame* targetFrame; - if (result.innerNonSharedNode()) - targetFrame = result.innerNonSharedNode()->document()->frame(); - else - targetFrame = m_page->focusController()->focusedOrMainFrame(); - -#if OS(WINDOWS) - targetFrame->view()->setCursor(pointerCursor()); -#endif - - m_contextMenuAllowed = true; - targetFrame->eventHandler()->sendContextMenuEvent(pme); - m_contextMenuAllowed = false; - // Actually showing the context menu is handled by the ContextMenuClient - // implementation... -} - -void WebViewImpl::handleMouseUp(Frame& mainFrame, const WebMouseEvent& event) -{ - PageWidgetEventHandler::handleMouseUp(mainFrame, event); - -#if OS(WINDOWS) - // Dispatch the contextmenu event regardless of if the click was swallowed. - // On Mac/Linux, we handle it on mouse down, not up. - if (event.button == WebMouseEvent::ButtonRight) - mouseContextMenu(event); -#endif -} - -void WebViewImpl::scrollBy(const WebPoint& delta) -{ - WebMouseWheelEvent syntheticWheel; - const float tickDivisor = WebCore::WheelEvent::tickMultiplier; - - syntheticWheel.deltaX = delta.x; - syntheticWheel.deltaY = delta.y; - syntheticWheel.wheelTicksX = delta.x / tickDivisor; - syntheticWheel.wheelTicksY = delta.y / tickDivisor; - syntheticWheel.hasPreciseScrollingDeltas = true; - syntheticWheel.x = m_lastWheelPosition.x; - syntheticWheel.y = m_lastWheelPosition.y; - syntheticWheel.globalX = m_lastWheelGlobalPosition.x; - syntheticWheel.globalY = m_lastWheelGlobalPosition.y; - syntheticWheel.modifiers = m_flingModifier; - - if (m_page && m_page->mainFrame() && m_page->mainFrame()->view()) - handleMouseWheel(*m_page->mainFrame(), syntheticWheel); -} - -#if ENABLE(GESTURE_EVENTS) -bool WebViewImpl::handleGestureEvent(const WebGestureEvent& event) -{ - bool eventSwallowed = false; - - // Handle link highlighting outside the main switch to avoid getting lost in the - // complicated set of cases handled below. - switch (event.type) { - case WebInputEvent::GestureTapDown: - // Queue a highlight animation, then hand off to regular handler. -#if OS(LINUX) - if (settingsImpl()->gestureTapHighlightEnabled()) - enableTouchHighlight(event); -#endif - break; - case WebInputEvent::GestureTapCancel: - case WebInputEvent::GestureTap: - case WebInputEvent::GestureLongPress: - if (m_linkHighlight) - m_linkHighlight->startHighlightAnimationIfNeeded(); - break; - default: - break; - } - - switch (event.type) { - case WebInputEvent::GestureFlingStart: { - if (mainFrameImpl()->frame()->eventHandler()->isScrollbarHandlingGestures()) - break; - m_client->cancelScheduledContentIntents(); - m_lastWheelPosition = WebPoint(event.x, event.y); - m_lastWheelGlobalPosition = WebPoint(event.globalX, event.globalY); - m_flingModifier = event.modifiers; - OwnPtr<WebGestureCurve> flingCurve = adoptPtr(Platform::current()->createFlingAnimationCurve(event.data.flingStart.sourceDevice, WebFloatPoint(event.data.flingStart.velocityX, event.data.flingStart.velocityY), WebSize())); - m_gestureAnimation = WebActiveGestureAnimation::createAtAnimationStart(flingCurve.release(), this); - scheduleAnimation(); - eventSwallowed = true; - break; - } - case WebInputEvent::GestureFlingCancel: - if (m_gestureAnimation) { - m_gestureAnimation.clear(); - eventSwallowed = true; - } - break; - case WebInputEvent::GestureTap: { - m_client->cancelScheduledContentIntents(); - if (detectContentOnTouch(WebPoint(event.x, event.y))) { - eventSwallowed = true; - break; - } - - RefPtr<WebCore::PopupContainer> selectPopup; - selectPopup = m_selectPopup; - hideSelectPopup(); - ASSERT(!m_selectPopup); - - if (event.data.tap.width > 0) { - IntRect boundingBox(event.x - event.data.tap.width / 2, event.y - event.data.tap.height / 2, event.data.tap.width, event.data.tap.height); - Vector<IntRect> goodTargets; - findGoodTouchTargets(boundingBox, mainFrameImpl()->frame(), pageScaleFactor(), goodTargets); - // FIXME: replace touch adjustment code when numberOfGoodTargets == 1? - // Single candidate case is currently handled by: https://bugs.webkit.org/show_bug.cgi?id=85101 - if (goodTargets.size() >= 2 && m_client && m_client->didTapMultipleTargets(event, goodTargets)) { - eventSwallowed = true; - break; - } - } - - PlatformGestureEventBuilder platformEvent(mainFrameImpl()->frameView(), event); - eventSwallowed = mainFrameImpl()->frame()->eventHandler()->handleGestureEvent(platformEvent); - - if (m_selectPopup && m_selectPopup == selectPopup) { - // That tap triggered a select popup which is the same as the one that - // was showing before the tap. It means the user tapped the select - // while the popup was showing, and as a result we first closed then - // immediately reopened the select popup. It needs to be closed. - hideSelectPopup(); - } - - break; - } - case WebInputEvent::GestureTwoFingerTap: - case WebInputEvent::GestureLongPress: - case WebInputEvent::GestureLongTap: { - if (!mainFrameImpl() || !mainFrameImpl()->frameView()) - break; - - m_client->cancelScheduledContentIntents(); - m_page->contextMenuController()->clearContextMenu(); - m_contextMenuAllowed = true; - PlatformGestureEventBuilder platformEvent(mainFrameImpl()->frameView(), event); - eventSwallowed = mainFrameImpl()->frame()->eventHandler()->handleGestureEvent(platformEvent); - m_contextMenuAllowed = false; - - break; - } - case WebInputEvent::GestureTapDown: { - m_client->cancelScheduledContentIntents(); - PlatformGestureEventBuilder platformEvent(mainFrameImpl()->frameView(), event); - eventSwallowed = mainFrameImpl()->frame()->eventHandler()->handleGestureEvent(platformEvent); - break; - } - case WebInputEvent::GestureDoubleTap: - if (m_webSettings->doubleTapToZoomEnabled()) { - m_client->cancelScheduledContentIntents(); - animateZoomAroundPoint(WebPoint(event.x, event.y), DoubleTap); - eventSwallowed = true; - break; - } - case WebInputEvent::GestureScrollBegin: - case WebInputEvent::GesturePinchBegin: - m_client->cancelScheduledContentIntents(); - case WebInputEvent::GestureScrollEnd: - case WebInputEvent::GestureScrollUpdate: - case WebInputEvent::GestureTapCancel: - case WebInputEvent::GesturePinchEnd: - case WebInputEvent::GesturePinchUpdate: { - PlatformGestureEventBuilder platformEvent(mainFrameImpl()->frameView(), event); - eventSwallowed = mainFrameImpl()->frame()->eventHandler()->handleGestureEvent(platformEvent); - break; - } - default: - ASSERT_NOT_REACHED(); - } - m_client->didHandleGestureEvent(event, eventSwallowed); - return eventSwallowed; -} - -void WebViewImpl::transferActiveWheelFlingAnimation(const WebActiveWheelFlingParameters& parameters) -{ - TRACE_EVENT0("webkit", "WebViewImpl::transferActiveWheelFlingAnimation"); - ASSERT(!m_gestureAnimation); - m_lastWheelPosition = parameters.point; - m_lastWheelGlobalPosition = parameters.globalPoint; - m_flingModifier = parameters.modifiers; - OwnPtr<WebGestureCurve> curve = adoptPtr(Platform::current()->createFlingAnimationCurve(parameters.sourceDevice, WebFloatPoint(parameters.delta), parameters.cumulativeScroll)); - m_gestureAnimation = WebActiveGestureAnimation::createWithTimeOffset(curve.release(), this, parameters.startTime); - scheduleAnimation(); -} - -void WebViewImpl::renderingStats(WebRenderingStats& stats) const -{ - if (m_layerTreeView) - m_layerTreeView->renderingStats(stats); -} - -void WebViewImpl::startPageScaleAnimation(const IntPoint& targetPosition, bool useAnchor, float newScale, double durationInSeconds) -{ - WebPoint clampedPoint = targetPosition; - if (!useAnchor) - clampedPoint = clampOffsetAtScale(targetPosition, newScale); - if ((!durationInSeconds && !useAnchor) || m_shouldUseDoubleTapTimeZero) { - setPageScaleFactor(newScale, clampedPoint); - return; - } - if (!m_layerTreeView) - return; - - m_layerTreeView->startPageScaleAnimation(targetPosition, useAnchor, newScale, durationInSeconds); -} -#endif - -WebViewBenchmarkSupport* WebViewImpl::benchmarkSupport() -{ - return &m_benchmarkSupport; -} - -void WebViewImpl::setShowFPSCounter(bool show) -{ - if (isAcceleratedCompositingActive()) { - TRACE_EVENT0("webkit", "WebViewImpl::setShowFPSCounter"); -#if USE(ACCELERATED_COMPOSITING) - loadFontAtlasIfNecessary(); -#endif - m_layerTreeView->setShowFPSCounter(show); - } - settingsImpl()->setShowFPSCounter(show); -} - -void WebViewImpl::setShowPaintRects(bool show) -{ - if (isAcceleratedCompositingActive()) { - TRACE_EVENT0("webkit", "WebViewImpl::setShowPaintRects"); - m_layerTreeView->setShowPaintRects(show); - } - settingsImpl()->setShowPaintRects(show); -} - -bool WebViewImpl::handleKeyEvent(const WebKeyboardEvent& event) -{ - ASSERT((event.type == WebInputEvent::RawKeyDown) - || (event.type == WebInputEvent::KeyDown) - || (event.type == WebInputEvent::KeyUp)); - - // Halt an in-progress fling on a key event. - if (m_gestureAnimation) - m_gestureAnimation.clear(); - - // Please refer to the comments explaining the m_suppressNextKeypressEvent - // member. - // The m_suppressNextKeypressEvent is set if the KeyDown is handled by - // Webkit. A keyDown event is typically associated with a keyPress(char) - // event and a keyUp event. We reset this flag here as this is a new keyDown - // event. - m_suppressNextKeypressEvent = false; - - // If there is a select popup, it should be the one processing the event, - // not the page. - if (m_selectPopup) - return m_selectPopup->handleKeyEvent(PlatformKeyboardEventBuilder(event)); -#if ENABLE(PAGE_POPUP) - if (m_pagePopup) { - m_pagePopup->handleKeyEvent(PlatformKeyboardEventBuilder(event)); - // We need to ignore the next Char event after this otherwise pressing - // enter when selecting an item in the popup will go to the page. - if (WebInputEvent::RawKeyDown == event.type) - m_suppressNextKeypressEvent = true; - return true; - } -#endif - - // Give Autocomplete a chance to consume the key events it is interested in. - if (autocompleteHandleKeyEvent(event)) - return true; - - RefPtr<Frame> frame = focusedWebCoreFrame(); - if (!frame) - return false; - - EventHandler* handler = frame->eventHandler(); - if (!handler) - return keyEventDefault(event); - -#if !OS(DARWIN) - const WebInputEvent::Type contextMenuTriggeringEventType = -#if OS(WINDOWS) - WebInputEvent::KeyUp; -#elif OS(UNIX) - WebInputEvent::RawKeyDown; -#endif - - bool isUnmodifiedMenuKey = !(event.modifiers & WebInputEvent::InputModifiers) && event.windowsKeyCode == VKEY_APPS; - bool isShiftF10 = event.modifiers == WebInputEvent::ShiftKey && event.windowsKeyCode == VKEY_F10; - if ((isUnmodifiedMenuKey || isShiftF10) && event.type == contextMenuTriggeringEventType) { - sendContextMenuEvent(event); - return true; - } -#endif // !OS(DARWIN) - - PlatformKeyboardEventBuilder evt(event); - - if (handler->keyEvent(evt)) { - if (WebInputEvent::RawKeyDown == event.type) { - // Suppress the next keypress event unless the focused node is a plug-in node. - // (Flash needs these keypress events to handle non-US keyboards.) - Node* node = focusedWebCoreNode(); - if (!node || !node->renderer() || !node->renderer()->isEmbeddedObject()) - m_suppressNextKeypressEvent = true; - } - return true; - } - - return keyEventDefault(event); -} - -bool WebViewImpl::autocompleteHandleKeyEvent(const WebKeyboardEvent& event) -{ - if (!m_autofillPopupShowing - // Home and End should be left to the text field to process. - || event.windowsKeyCode == VKEY_HOME - || event.windowsKeyCode == VKEY_END) - return false; - - // Pressing delete triggers the removal of the selected suggestion from the DB. - if (event.windowsKeyCode == VKEY_DELETE - && m_autofillPopup->selectedIndex() != -1) { - Node* node = focusedWebCoreNode(); - if (!node || (node->nodeType() != Node::ELEMENT_NODE)) { - ASSERT_NOT_REACHED(); - return false; - } - Element* element = static_cast<Element*>(node); - if (!element->hasLocalName(HTMLNames::inputTag)) { - ASSERT_NOT_REACHED(); - return false; - } - - int selectedIndex = m_autofillPopup->selectedIndex(); - - if (!m_autofillPopupClient->canRemoveSuggestionAtIndex(selectedIndex)) - return false; - - WebString name = WebInputElement(static_cast<HTMLInputElement*>(element)).nameForAutofill(); - WebString value = m_autofillPopupClient->itemText(selectedIndex); - m_autofillClient->removeAutocompleteSuggestion(name, value); - // Update the entries in the currently showing popup to reflect the - // deletion. - m_autofillPopupClient->removeSuggestionAtIndex(selectedIndex); - refreshAutofillPopup(); - return false; - } - - if (!m_autofillPopup->isInterestedInEventForKey(event.windowsKeyCode)) - return false; - - if (m_autofillPopup->handleKeyEvent(PlatformKeyboardEventBuilder(event))) { - // We need to ignore the next Char event after this otherwise pressing - // enter when selecting an item in the menu will go to the page. - if (WebInputEvent::RawKeyDown == event.type) - m_suppressNextKeypressEvent = true; - return true; - } - - return false; -} - -bool WebViewImpl::handleCharEvent(const WebKeyboardEvent& event) -{ - ASSERT(event.type == WebInputEvent::Char); - - // Please refer to the comments explaining the m_suppressNextKeypressEvent - // member. The m_suppressNextKeypressEvent is set if the KeyDown is - // handled by Webkit. A keyDown event is typically associated with a - // keyPress(char) event and a keyUp event. We reset this flag here as it - // only applies to the current keyPress event. - bool suppress = m_suppressNextKeypressEvent; - m_suppressNextKeypressEvent = false; - - // If there is a select popup, it should be the one processing the event, - // not the page. - if (m_selectPopup) - return m_selectPopup->handleKeyEvent(PlatformKeyboardEventBuilder(event)); -#if ENABLE(PAGE_POPUP) - if (m_pagePopup) - return m_pagePopup->handleKeyEvent(PlatformKeyboardEventBuilder(event)); -#endif - - Frame* frame = focusedWebCoreFrame(); - if (!frame) - return suppress; - - EventHandler* handler = frame->eventHandler(); - if (!handler) - return suppress || keyEventDefault(event); - - PlatformKeyboardEventBuilder evt(event); - if (!evt.isCharacterKey()) - return true; - - // Accesskeys are triggered by char events and can't be suppressed. - if (handler->handleAccessKey(evt)) - return true; - - // Safari 3.1 does not pass off windows system key messages (WM_SYSCHAR) to - // the eventHandler::keyEvent. We mimic this behavior on all platforms since - // for now we are converting other platform's key events to windows key - // events. - if (evt.isSystemKey()) - return false; - - if (!suppress && !handler->keyEvent(evt)) - return keyEventDefault(event); - - return true; -} - -#if ENABLE(GESTURE_EVENTS) -WebRect WebViewImpl::computeBlockBounds(const WebRect& rect, AutoZoomType zoomType) -{ - if (!mainFrameImpl()) - return WebRect(); - - // Use the rect-based hit test to find the node. - IntPoint point = mainFrameImpl()->frameView()->windowToContents(IntPoint(rect.x, rect.y)); - HitTestResult result = mainFrameImpl()->frame()->eventHandler()->hitTestResultAtPoint(point, - false, zoomType == FindInPage, DontHitTestScrollbars, HitTestRequest::Active | HitTestRequest::ReadOnly, - IntSize(rect.width, rect.height)); - - Node* node = result.innerNonSharedNode(); - if (!node) - return WebRect(); - - // Find the block type node based on the hit node. - while (node && (!node->renderer() || node->renderer()->isInline())) - node = node->parentNode(); - - // Return the bounding box in the window coordinate system. - if (node) { - IntRect rect = node->Node::pixelSnappedBoundingBox(); - Frame* frame = node->document()->frame(); - return frame->view()->contentsToWindow(rect); - } - return WebRect(); -} - -WebRect WebViewImpl::widenRectWithinPageBounds(const WebRect& source, int targetMargin, int minimumMargin) -{ - WebSize maxSize; - if (mainFrame()) - maxSize = mainFrame()->contentsSize(); - IntSize scrollOffset; - if (mainFrame()) - scrollOffset = mainFrame()->scrollOffset(); - int leftMargin = targetMargin; - int rightMargin = targetMargin; - - const int absoluteSourceX = source.x + scrollOffset.width(); - if (leftMargin > absoluteSourceX) { - leftMargin = absoluteSourceX; - rightMargin = max(leftMargin, minimumMargin); - } - - const int maximumRightMargin = maxSize.width - (source.width + absoluteSourceX); - if (rightMargin > maximumRightMargin) { - rightMargin = maximumRightMargin; - leftMargin = min(leftMargin, max(rightMargin, minimumMargin)); - } - - const int newWidth = source.width + leftMargin + rightMargin; - const int newX = source.x - leftMargin; - - ASSERT(newWidth >= 0); - ASSERT(scrollOffset.width() + newX + newWidth <= maxSize.width); - - return WebRect(newX, source.y, newWidth, source.height); -} - -void WebViewImpl::shouldUseAnimateDoubleTapTimeZeroForTesting(bool setToZero) -{ - m_shouldUseDoubleTapTimeZero = setToZero; -} - -void WebViewImpl::computeScaleAndScrollForHitRect(const WebRect& hitRect, AutoZoomType zoomType, float& scale, WebPoint& scroll, bool& isAnchor) -{ - scale = pageScaleFactor(); - scroll.x = scroll.y = 0; - WebRect targetRect = hitRect; - // Padding only depends on page scale when triggered by manually tapping - int padding = (zoomType == DoubleTap) ? touchPointPadding : nonUserInitiatedPointPadding; - if (targetRect.isEmpty()) - targetRect.width = targetRect.height = padding; - WebRect rect = computeBlockBounds(targetRect, zoomType); - if (zoomType == FindInPage && rect.isEmpty()) { - // Keep current scale (no need to scroll as x,y will normally already - // be visible). FIXME: Revisit this if it isn't always true. - return; - } - - bool scaleUnchanged = true; - if (!rect.isEmpty()) { - // Pages should be as legible as on desktop when at dpi scale, so no - // need to zoom in further when automatically determining zoom level - // (after double tap, find in page, etc), though the user should still - // be allowed to manually pinch zoom in further if they desire. - const float defaultScaleWhenAlreadyLegible = m_minimumPageScaleFactor * doubleTapZoomAlreadyLegibleRatio; - float legibleScale = deviceScaleFactor(); - if (legibleScale < defaultScaleWhenAlreadyLegible) - legibleScale = (scale == m_minimumPageScaleFactor) ? defaultScaleWhenAlreadyLegible : m_minimumPageScaleFactor; - - const float defaultMargin = doubleTapZoomContentDefaultMargin * deviceScaleFactor(); - const float minimumMargin = doubleTapZoomContentMinimumMargin * deviceScaleFactor(); - // We want the margins to have the same physical size, which means we - // need to express them in post-scale size. To do that we'd need to know - // the scale we're scaling to, but that depends on the margins. Instead - // we express them as a fraction of the target rectangle: this will be - // correct if we end up fully zooming to it, and won't matter if we - // don't. - rect = widenRectWithinPageBounds(rect, - static_cast<int>(defaultMargin * rect.width / m_size.width), - static_cast<int>(minimumMargin * rect.width / m_size.width)); - // Fit block to screen, respecting limits. - scale *= static_cast<float>(m_size.width) / rect.width; - scale = min(scale, legibleScale); - scale = clampPageScaleFactorToLimits(scale); - - scaleUnchanged = fabs(pageScaleFactor() - scale) < minScaleDifference; - } - - if (zoomType == DoubleTap && (rect.isEmpty() || scaleUnchanged || m_doubleTapZoomInEffect)) { - // Zoom out to minimum scale. - scale = m_minimumPageScaleFactor; - scroll = WebPoint(hitRect.x, hitRect.y); - isAnchor = true; - m_doubleTapZoomInEffect = false; - } else { - if (zoomType == DoubleTap && scale != m_minimumPageScaleFactor) - m_doubleTapZoomInEffect = true; - else - m_doubleTapZoomInEffect = false; - // FIXME: If this is being called for auto zoom during find in page, - // then if the user manually zooms in it'd be nice to preserve the - // relative increase in zoom they caused (if they zoom out then it's ok - // to zoom them back in again). This isn't compatible with our current - // double-tap zoom strategy (fitting the containing block to the screen) - // though. - - float screenHeight = m_size.height / scale * pageScaleFactor(); - float screenWidth = m_size.width / scale * pageScaleFactor(); - - // Scroll to vertically align the block. - if (rect.height < screenHeight) { - // Vertically center short blocks. - rect.y -= 0.5 * (screenHeight - rect.height); - } else { - // Ensure position we're zooming to (+ padding) isn't off the bottom of - // the screen. - rect.y = max<float>(rect.y, hitRect.y + padding - screenHeight); - } // Otherwise top align the block. - - // Do the same thing for horizontal alignment. - if (rect.width < screenWidth) - rect.x -= 0.5 * (screenWidth - rect.width); - else - rect.x = max<float>(rect.x, hitRect.x + padding - screenWidth); - scroll.x = rect.x; - scroll.y = rect.y; - isAnchor = false; - } - - scale = clampPageScaleFactorToLimits(scale); - scroll = mainFrameImpl()->frameView()->windowToContents(scroll); - float scaleDelta = scale / pageScaleFactor(); - scroll = WebPoint(scroll.x * scaleDelta, scroll.y * scaleDelta); - if (!isAnchor) - scroll = clampOffsetAtScale(scroll, scale); -} - -static bool invokesHandCursor(Node* node, bool shiftKey, Frame* frame) -{ - if (!node || !node->renderer()) - return false; - - ECursor cursor = node->renderer()->style()->cursor(); - return cursor == CURSOR_POINTER - || (cursor == CURSOR_AUTO && frame->eventHandler()->useHandCursor(node, node->isLink(), shiftKey)); -} - -Node* WebViewImpl::bestTouchLinkNode(const WebGestureEvent& touchEvent) -{ - if (!m_page || !m_page->mainFrame()) - return 0; - - Node* bestTouchNode = 0; - - // FIXME: Should accept a search region from the caller instead of hard-coding the size. - IntSize touchEventSearchRegionSize(4, 2); - IntPoint touchEventLocation(touchEvent.x, touchEvent.y); - m_page->mainFrame()->eventHandler()->bestClickableNodeForTouchPoint(touchEventLocation, touchEventSearchRegionSize, touchEventLocation, bestTouchNode); - // bestClickableNodeForTouchPoint() doesn't always return a node that is a link, so let's try and find - // a link to highlight. - bool shiftKey = touchEvent.modifiers & WebGestureEvent::ShiftKey; - while (bestTouchNode && !invokesHandCursor(bestTouchNode, shiftKey, m_page->mainFrame())) - bestTouchNode = bestTouchNode->parentNode(); - - return bestTouchNode; -} - -void WebViewImpl::enableTouchHighlight(const WebGestureEvent& touchEvent) -{ - // Always clear any existing highlight when this is invoked, even if we don't get a new target to highlight. - m_linkHighlight.clear(); - - Node* touchNode = bestTouchLinkNode(touchEvent); - - if (!touchNode || !touchNode->renderer() || !touchNode->renderer()->enclosingLayer()) - return; - - Color highlightColor = touchNode->renderer()->style()->tapHighlightColor(); - // Safari documentation for -webkit-tap-highlight-color says if the specified color has 0 alpha, - // then tap highlighting is disabled. - // http://developer.apple.com/library/safari/#documentation/appleapplications/reference/safaricssref/articles/standardcssproperties.html - if (!highlightColor.alpha()) - return; - - m_linkHighlight = LinkHighlight::create(touchNode, this); -} - -#endif - -void WebViewImpl::animateZoomAroundPoint(const IntPoint& point, AutoZoomType zoomType) -{ -#if ENABLE(GESTURE_EVENTS) - if (!mainFrameImpl()) - return; - - float scale; - WebPoint scroll; - bool isAnchor; - WebPoint webPoint = point; - computeScaleAndScrollForHitRect(WebRect(webPoint.x, webPoint.y, 0, 0), zoomType, scale, scroll, isAnchor); - - bool isDoubleTap = (zoomType == DoubleTap); - double durationInSeconds = (isDoubleTap && !m_shouldUseDoubleTapTimeZero) ? doubleTapZoomAnimationDurationInSeconds : 0; - startPageScaleAnimation(scroll, isAnchor, scale, durationInSeconds); -#endif -} - -void WebViewImpl::zoomToFindInPageRect(const WebRect& rect) -{ - animateZoomAroundPoint(IntRect(rect).center(), FindInPage); -} - -void WebViewImpl::numberOfWheelEventHandlersChanged(unsigned numberOfWheelHandlers) -{ - if (m_client) - m_client->numberOfWheelEventHandlersChanged(numberOfWheelHandlers); -} - -void WebViewImpl::hasTouchEventHandlers(bool hasTouchHandlers) -{ - if (m_client) - m_client->hasTouchEventHandlers(hasTouchHandlers); -} - -bool WebViewImpl::hasTouchEventHandlersAt(const WebPoint& point) -{ - return true; -} - -#if !OS(DARWIN) -// Mac has no way to open a context menu based on a keyboard event. -bool WebViewImpl::sendContextMenuEvent(const WebKeyboardEvent& event) -{ - // The contextMenuController() holds onto the last context menu that was - // popped up on the page until a new one is created. We need to clear - // this menu before propagating the event through the DOM so that we can - // detect if we create a new menu for this event, since we won't create - // a new menu if the DOM swallows the event and the defaultEventHandler does - // not run. - page()->contextMenuController()->clearContextMenu(); - - m_contextMenuAllowed = true; - Frame* focusedFrame = page()->focusController()->focusedOrMainFrame(); - bool handled = focusedFrame->eventHandler()->sendContextMenuEventForKey(); - m_contextMenuAllowed = false; - return handled; -} -#endif - -bool WebViewImpl::keyEventDefault(const WebKeyboardEvent& event) -{ - Frame* frame = focusedWebCoreFrame(); - if (!frame) - return false; - - switch (event.type) { - case WebInputEvent::Char: - if (event.windowsKeyCode == VKEY_SPACE) { - int keyCode = ((event.modifiers & WebInputEvent::ShiftKey) ? VKEY_PRIOR : VKEY_NEXT); - return scrollViewWithKeyboard(keyCode, event.modifiers); - } - break; - case WebInputEvent::RawKeyDown: - if (event.modifiers == WebInputEvent::ControlKey) { - switch (event.windowsKeyCode) { -#if !OS(DARWIN) - case 'A': - focusedFrame()->executeCommand(WebString::fromUTF8("SelectAll")); - return true; - case VKEY_INSERT: - case 'C': - focusedFrame()->executeCommand(WebString::fromUTF8("Copy")); - return true; -#endif - // Match FF behavior in the sense that Ctrl+home/end are the only Ctrl - // key combinations which affect scrolling. Safari is buggy in the - // sense that it scrolls the page for all Ctrl+scrolling key - // combinations. For e.g. Ctrl+pgup/pgdn/up/down, etc. - case VKEY_HOME: - case VKEY_END: - break; - default: - return false; - } - } - if (!event.isSystemKey && !(event.modifiers & WebInputEvent::ShiftKey)) - return scrollViewWithKeyboard(event.windowsKeyCode, event.modifiers); - break; - default: - break; - } - return false; -} - -bool WebViewImpl::scrollViewWithKeyboard(int keyCode, int modifiers) -{ - ScrollDirection scrollDirection; - ScrollGranularity scrollGranularity; -#if OS(DARWIN) - // Control-Up/Down should be PageUp/Down on Mac. - if (modifiers & WebMouseEvent::ControlKey) { - if (keyCode == VKEY_UP) - keyCode = VKEY_PRIOR; - else if (keyCode == VKEY_DOWN) - keyCode = VKEY_NEXT; - } -#endif - if (!mapKeyCodeForScroll(keyCode, &scrollDirection, &scrollGranularity)) - return false; - return propagateScroll(scrollDirection, scrollGranularity); -} - -bool WebViewImpl::mapKeyCodeForScroll(int keyCode, - WebCore::ScrollDirection* scrollDirection, - WebCore::ScrollGranularity* scrollGranularity) -{ - switch (keyCode) { - case VKEY_LEFT: - *scrollDirection = ScrollLeft; - *scrollGranularity = ScrollByLine; - break; - case VKEY_RIGHT: - *scrollDirection = ScrollRight; - *scrollGranularity = ScrollByLine; - break; - case VKEY_UP: - *scrollDirection = ScrollUp; - *scrollGranularity = ScrollByLine; - break; - case VKEY_DOWN: - *scrollDirection = ScrollDown; - *scrollGranularity = ScrollByLine; - break; - case VKEY_HOME: - *scrollDirection = ScrollUp; - *scrollGranularity = ScrollByDocument; - break; - case VKEY_END: - *scrollDirection = ScrollDown; - *scrollGranularity = ScrollByDocument; - break; - case VKEY_PRIOR: // page up - *scrollDirection = ScrollUp; - *scrollGranularity = ScrollByPage; - break; - case VKEY_NEXT: // page down - *scrollDirection = ScrollDown; - *scrollGranularity = ScrollByPage; - break; - default: - return false; - } - - return true; -} - -void WebViewImpl::hideSelectPopup() -{ - if (m_selectPopup) - m_selectPopup->hidePopup(); -} - -bool WebViewImpl::propagateScroll(ScrollDirection scrollDirection, - ScrollGranularity scrollGranularity) -{ - Frame* frame = focusedWebCoreFrame(); - if (!frame) - return false; - - bool scrollHandled = frame->eventHandler()->scrollOverflow(scrollDirection, scrollGranularity); - Frame* currentFrame = frame; - while (!scrollHandled && currentFrame) { - scrollHandled = currentFrame->view()->scroll(scrollDirection, scrollGranularity); - currentFrame = currentFrame->tree()->parent(); - } - return scrollHandled; -} - -void WebViewImpl::popupOpened(WebCore::PopupContainer* popupContainer) -{ - if (popupContainer->popupType() == WebCore::PopupContainer::Select) { - ASSERT(!m_selectPopup); - m_selectPopup = popupContainer; - } -} - -void WebViewImpl::popupClosed(WebCore::PopupContainer* popupContainer) -{ - if (popupContainer->popupType() == WebCore::PopupContainer::Select) { - ASSERT(m_selectPopup); - m_selectPopup = 0; - } -} - -#if ENABLE(PAGE_POPUP) -PagePopup* WebViewImpl::openPagePopup(PagePopupClient* client, const IntRect& originBoundsInRootView) -{ - ASSERT(client); - if (hasOpenedPopup()) - hidePopups(); - ASSERT(!m_pagePopup); - - WebWidget* popupWidget = m_client->createPopupMenu(WebPopupTypePage); - ASSERT(popupWidget); - m_pagePopup = static_cast<WebPagePopupImpl*>(popupWidget); - if (!m_pagePopup->init(this, client, originBoundsInRootView)) { - m_pagePopup->closePopup(); - m_pagePopup = 0; - } - return m_pagePopup.get(); -} - -void WebViewImpl::closePagePopup(PagePopup* popup) -{ - ASSERT(popup); - WebPagePopupImpl* popupImpl = static_cast<WebPagePopupImpl*>(popup); - ASSERT(m_pagePopup.get() == popupImpl); - if (m_pagePopup.get() != popupImpl) - return; - m_pagePopup->closePopup(); - m_pagePopup = 0; -} -#endif - -void WebViewImpl::hideAutofillPopup() -{ - if (m_autofillPopupShowing) { - m_autofillPopup->hidePopup(); - m_autofillPopupShowing = false; - } -} - -WebHelperPluginImpl* WebViewImpl::createHelperPlugin(const String& pluginType) -{ - WebWidget* popupWidget = m_client->createPopupMenu(WebPopupTypeHelperPlugin); - ASSERT(popupWidget); - WebHelperPluginImpl* helperPlugin = static_cast<WebHelperPluginImpl*>(popupWidget); - - if (!helperPlugin->init(this, pluginType)) { - helperPlugin->closeHelperPlugin(); - helperPlugin = 0; - } - return helperPlugin; -} - -Frame* WebViewImpl::focusedWebCoreFrame() const -{ - return m_page ? m_page->focusController()->focusedOrMainFrame() : 0; -} - -WebViewImpl* WebViewImpl::fromPage(Page* page) -{ - if (!page) - return 0; - - ChromeClientImpl* chromeClient = static_cast<ChromeClientImpl*>(page->chrome()->client()); - return static_cast<WebViewImpl*>(chromeClient->webView()); -} - -PageGroup* WebViewImpl::defaultPageGroup() -{ - return PageGroup::pageGroup(pageGroupName); -} - -// WebWidget ------------------------------------------------------------------ - -void WebViewImpl::close() -{ - RefPtr<WebFrameImpl> mainFrameImpl; - - if (m_page) { - // Initiate shutdown for the entire frameset. This will cause a lot of - // notifications to be sent. - if (m_page->mainFrame()) { - mainFrameImpl = WebFrameImpl::fromFrame(m_page->mainFrame()); - m_page->mainFrame()->loader()->frameDetached(); - } - m_page.clear(); - } - - // Should happen after m_page.clear(). - if (m_devToolsAgent) - m_devToolsAgent.clear(); - - // Reset the delegate to prevent notifications being sent as we're being - // deleted. - m_client = 0; - - deref(); // Balances ref() acquired in WebView::create -} - -void WebViewImpl::willStartLiveResize() -{ - if (mainFrameImpl() && mainFrameImpl()->frameView()) - mainFrameImpl()->frameView()->willStartLiveResize(); - - Frame* frame = mainFrameImpl()->frame(); - WebPluginContainerImpl* pluginContainer = WebFrameImpl::pluginContainerFromFrame(frame); - if (pluginContainer) - pluginContainer->willStartLiveResize(); -} - -void WebViewImpl::resize(const WebSize& newSize) -{ - if (m_shouldAutoResize || m_size == newSize) - return; - - FrameView* view = mainFrameImpl()->frameView(); - if (!view) - return; - - WebSize oldSize = m_size; - float oldPageScaleFactor = pageScaleFactor(); - IntSize oldScrollOffset = view->scrollOffset(); - int oldFixedLayoutWidth = fixedLayoutSize().width; - - m_size = newSize; - -#if ENABLE(VIEWPORT) - if (settings()->viewportEnabled()) { - // Fallback width is used to layout sites designed for desktop. The - // conventional size used by all mobile browsers is 980. When a mobile - // device has a particularly wide screen (such as a 10" tablet held in - // landscape), it can be larger. - const int standardFallbackWidth = 980; - int dpiIndependentViewportWidth = newSize.width / page()->deviceScaleFactor(); - settings()->setLayoutFallbackWidth(std::max(standardFallbackWidth, dpiIndependentViewportWidth)); - - ViewportArguments viewportArguments = mainFrameImpl()->frame()->document()->viewportArguments(); - m_page->chrome()->client()->dispatchViewportPropertiesDidChange(viewportArguments); - } -#endif - - WebDevToolsAgentPrivate* agentPrivate = devToolsAgentPrivate(); - if (agentPrivate) - agentPrivate->webViewResized(newSize); - if (!agentPrivate || !agentPrivate->metricsOverridden()) { - WebFrameImpl* webFrame = mainFrameImpl(); - if (webFrame->frameView()) - webFrame->frameView()->resize(newSize.width, newSize.height); - } - -#if ENABLE(VIEWPORT) - if (settings()->viewportEnabled()) { - // Relayout immediately to obtain the new content width, which is needed - // to calculate the minimum scale limit. - view->layout(); - computePageScaleFactorLimits(); - // When the device rotates: - // - If the page width is unchanged, then zoom by new width/old width - // such as to keep the same content horizontally onscreen. - // - If the page width stretches proportionally to the change in - // screen width, then don't zoom at all (assuming the content has - // scaled uniformly, then the same content will be horizontally - // onscreen). - // - If the page width partially stretches, then zoom partially to - // make up the difference. - // In all cases try to keep the same content at the top of the screen. - float viewportWidthRatio = !oldSize.width ? 1 : newSize.width / (float) oldSize.width; - float fixedLayoutWidthRatio = !oldFixedLayoutWidth ? 1 : fixedLayoutSize().width / (float) oldFixedLayoutWidth; - float scaleMultiplier = viewportWidthRatio / fixedLayoutWidthRatio; - if (scaleMultiplier != 1) { - IntSize scrollOffsetAtNewScale = oldScrollOffset; - scrollOffsetAtNewScale.scale(scaleMultiplier); - setPageScaleFactor(oldPageScaleFactor * scaleMultiplier, IntPoint(scrollOffsetAtNewScale)); - } - } -#endif - - sendResizeEventAndRepaint(); -} - -void WebViewImpl::willEndLiveResize() -{ - if (mainFrameImpl() && mainFrameImpl()->frameView()) - mainFrameImpl()->frameView()->willEndLiveResize(); - - Frame* frame = mainFrameImpl()->frame(); - WebPluginContainerImpl* pluginContainer = WebFrameImpl::pluginContainerFromFrame(frame); - if (pluginContainer) - pluginContainer->willEndLiveResize(); -} - -void WebViewImpl::willEnterFullScreen() -{ -#if ENABLE(FULLSCREEN_API) - if (!m_provisionalFullScreenElement) - return; - - // Ensure that this element's document is still attached. - Document* doc = m_provisionalFullScreenElement->document(); - if (doc->frame()) { - doc->webkitWillEnterFullScreenForElement(m_provisionalFullScreenElement.get()); - m_fullScreenFrame = doc->frame(); - } - m_provisionalFullScreenElement.clear(); -#endif -} - -void WebViewImpl::didEnterFullScreen() -{ -#if ENABLE(FULLSCREEN_API) - if (!m_fullScreenFrame) - return; - - if (Document* doc = m_fullScreenFrame->document()) { - if (doc->webkitIsFullScreen()) - doc->webkitDidEnterFullScreenForElement(0); - } -#endif -} - -void WebViewImpl::willExitFullScreen() -{ -#if ENABLE(FULLSCREEN_API) - if (!m_fullScreenFrame) - return; - - if (Document* doc = m_fullScreenFrame->document()) { - if (doc->webkitIsFullScreen()) { - // When the client exits from full screen we have to call webkitCancelFullScreen to - // notify the document. While doing that, suppress notifications back to the client. - m_isCancelingFullScreen = true; - doc->webkitCancelFullScreen(); - m_isCancelingFullScreen = false; - doc->webkitWillExitFullScreenForElement(0); - } - } -#endif -} - -void WebViewImpl::didExitFullScreen() -{ -#if ENABLE(FULLSCREEN_API) - if (!m_fullScreenFrame) - return; - - if (Document* doc = m_fullScreenFrame->document()) { - if (doc->webkitIsFullScreen()) - doc->webkitDidExitFullScreenForElement(0); - } - - m_fullScreenFrame.clear(); -#endif -} - -void WebViewImpl::instrumentBeginFrame() -{ - InspectorInstrumentation::didBeginFrame(m_page.get()); -} - -void WebViewImpl::instrumentCancelFrame() -{ - InspectorInstrumentation::didCancelFrame(m_page.get()); -} - -#if ENABLE(BATTERY_STATUS) -void WebViewImpl::updateBatteryStatus(const WebBatteryStatus& status) -{ - m_batteryClient->updateBatteryStatus(status); -} -#endif - -void WebViewImpl::setCompositorSurfaceReady() -{ - m_compositorSurfaceReady = true; - if (m_layerTreeView) - m_layerTreeView->setSurfaceReady(); -} - -void WebViewImpl::animate(double) -{ -#if ENABLE(REQUEST_ANIMATION_FRAME) - double monotonicFrameBeginTime = monotonicallyIncreasingTime(); - -#if USE(ACCELERATED_COMPOSITING) - // In composited mode, we always go through the compositor so it can apply - // appropriate flow-control mechanisms. - if (isAcceleratedCompositingActive()) - m_layerTreeView->updateAnimations(monotonicFrameBeginTime); - else -#endif - updateAnimations(monotonicFrameBeginTime); -#endif -} - -void WebViewImpl::willBeginFrame() -{ - instrumentBeginFrame(); - m_client->willBeginCompositorFrame(); -} - -void WebViewImpl::didBeginFrame() -{ - InspectorInstrumentation::didComposite(m_page.get()); -} - -void WebViewImpl::updateAnimations(double monotonicFrameBeginTime) -{ -#if ENABLE(REQUEST_ANIMATION_FRAME) - TRACE_EVENT0("webkit", "WebViewImpl::updateAnimations"); - - // Create synthetic wheel events as necessary for fling. - if (m_gestureAnimation) { - if (m_gestureAnimation->animate(monotonicFrameBeginTime)) - scheduleAnimation(); - else - m_gestureAnimation.clear(); - } - - if (!m_page) - return; - - PageWidgetDelegate::animate(m_page.get(), monotonicFrameBeginTime); -#endif -} - -void WebViewImpl::layout() -{ - TRACE_EVENT0("webkit", "WebViewImpl::layout"); - PageWidgetDelegate::layout(m_page.get()); - - if (m_linkHighlight) - m_linkHighlight->updateGeometry(); -} - -void WebViewImpl::enterForceCompositingMode(bool enter) -{ - TRACE_EVENT1("webkit", "WebViewImpl::enterForceCompositingMode", "enter", enter); - settingsImpl()->setForceCompositingMode(enter); - if (enter) { - if (!m_page) - return; - Frame* mainFrame = m_page->mainFrame(); - if (!mainFrame) - return; - mainFrame->view()->updateCompositingLayersAfterStyleChange(); - } -} - -#if USE(ACCELERATED_COMPOSITING) -void WebViewImpl::doPixelReadbackToCanvas(WebCanvas* canvas, const IntRect& rect) -{ - ASSERT(m_layerTreeView); - - SkBitmap target; - target.setConfig(SkBitmap::kARGB_8888_Config, rect.width(), rect.height(), rect.width() * 4); - target.allocPixels(); - m_layerTreeView->compositeAndReadback(target.getPixels(), rect); -#if (!SK_R32_SHIFT && SK_B32_SHIFT == 16) - // The compositor readback always gives back pixels in BGRA order, but for - // example Android's Skia uses RGBA ordering so the red and blue channels - // need to be swapped. - uint8_t* pixels = reinterpret_cast<uint8_t*>(target.getPixels()); - for (size_t i = 0; i < target.getSize(); i += 4) - std::swap(pixels[i], pixels[i + 2]); -#endif - canvas->writePixels(target, rect.x(), rect.y()); -} -#endif - -void WebViewImpl::paint(WebCanvas* canvas, const WebRect& rect, PaintOptions option) -{ -#if !OS(ANDROID) - // ReadbackFromCompositorIfAvailable is the only option available on non-Android. - // Ideally, Android would always use ReadbackFromCompositorIfAvailable as well. - ASSERT(option == ReadbackFromCompositorIfAvailable); -#endif - - if (option == ReadbackFromCompositorIfAvailable && isAcceleratedCompositingActive()) { -#if USE(ACCELERATED_COMPOSITING) - // If a canvas was passed in, we use it to grab a copy of the - // freshly-rendered pixels. - if (canvas) { - // Clip rect to the confines of the rootLayerTexture. - IntRect resizeRect(rect); - resizeRect.intersect(IntRect(IntPoint(0, 0), m_layerTreeView->deviceViewportSize())); - doPixelReadbackToCanvas(canvas, resizeRect); - } -#endif - } else { - FrameView* view = page()->mainFrame()->view(); - PaintBehavior oldPaintBehavior = view->paintBehavior(); - if (isAcceleratedCompositingActive()) { - ASSERT(option == ForceSoftwareRenderingAndIgnoreGPUResidentContent); - view->setPaintBehavior(oldPaintBehavior | PaintBehaviorFlattenCompositingLayers); - } - - double paintStart = currentTime(); - PageWidgetDelegate::paint(m_page.get(), pageOverlays(), canvas, rect, isTransparent() ? PageWidgetDelegate::Translucent : PageWidgetDelegate::Opaque, m_webSettings->applyDeviceScaleFactorInCompositor()); - double paintEnd = currentTime(); - double pixelsPerSec = (rect.width * rect.height) / (paintEnd - paintStart); - WebKit::Platform::current()->histogramCustomCounts("Renderer4.SoftwarePaintDurationMS", (paintEnd - paintStart) * 1000, 0, 120, 30); - WebKit::Platform::current()->histogramCustomCounts("Renderer4.SoftwarePaintMegapixPerSecond", pixelsPerSec / 1000000, 10, 210, 30); - - if (isAcceleratedCompositingActive()) { - ASSERT(option == ForceSoftwareRenderingAndIgnoreGPUResidentContent); - view->setPaintBehavior(oldPaintBehavior); - } - } -} - -bool WebViewImpl::isTrackingRepaints() const -{ - if (!page()) - return false; - FrameView* view = page()->mainFrame()->view(); - return view->isTrackingRepaints(); -} - -void WebViewImpl::themeChanged() -{ - if (!page()) - return; - FrameView* view = page()->mainFrame()->view(); - - WebRect damagedRect(0, 0, m_size.width, m_size.height); - view->invalidateRect(damagedRect); -} - -void WebViewImpl::composite(bool) -{ -#if USE(ACCELERATED_COMPOSITING) - if (Platform::current()->compositorSupport()->isThreadingEnabled()) - m_layerTreeView->setNeedsRedraw(); - else { - ASSERT(isAcceleratedCompositingActive()); - if (!page()) - return; - - m_layerTreeView->composite(); - } -#endif -} - -void WebViewImpl::setNeedsRedraw() -{ -#if USE(ACCELERATED_COMPOSITING) - if (m_layerTreeView && isAcceleratedCompositingActive()) - m_layerTreeView->setNeedsRedraw(); -#endif -} - -bool WebViewImpl::isInputThrottled() const -{ -#if USE(ACCELERATED_COMPOSITING) - if (m_layerTreeView && isAcceleratedCompositingActive()) - return m_layerTreeView->commitRequested(); -#endif - return false; -} - -void WebViewImpl::loseCompositorContext(int numTimes) -{ -#if USE(ACCELERATED_COMPOSITING) - if (m_layerTreeView) - m_layerTreeView->loseCompositorContext(numTimes); -#endif -} - -void WebViewImpl::enterFullScreenForElement(WebCore::Element* element) -{ - // We are already transitioning to fullscreen for a different element. - if (m_provisionalFullScreenElement) { - m_provisionalFullScreenElement = element; - return; - } - - // We are already in fullscreen mode. - if (m_fullScreenFrame) { - m_provisionalFullScreenElement = element; - willEnterFullScreen(); - didEnterFullScreen(); - return; - } - -#if USE(NATIVE_FULLSCREEN_VIDEO) - if (element && element->isMediaElement()) { - HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(element); - if (mediaElement->player() && mediaElement->player()->canEnterFullscreen()) { - mediaElement->player()->enterFullscreen(); - m_provisionalFullScreenElement = element; - } - return; - } -#endif - - // We need to transition to fullscreen mode. - if (m_client && m_client->enterFullScreen()) - m_provisionalFullScreenElement = element; -} - -void WebViewImpl::exitFullScreenForElement(WebCore::Element* element) -{ - // The client is exiting full screen, so don't send a notification. - if (m_isCancelingFullScreen) - return; -#if USE(NATIVE_FULLSCREEN_VIDEO) - if (element && element->isMediaElement()) { - HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(element); - if (mediaElement->player()) - mediaElement->player()->exitFullscreen(); - return; - } -#endif - if (m_client) - m_client->exitFullScreen(); -} - -bool WebViewImpl::hasHorizontalScrollbar() -{ - return mainFrameImpl()->frameView()->horizontalScrollbar(); -} - -bool WebViewImpl::hasVerticalScrollbar() -{ - return mainFrameImpl()->frameView()->verticalScrollbar(); -} - -const WebInputEvent* WebViewImpl::m_currentInputEvent = 0; - -bool WebViewImpl::handleInputEvent(const WebInputEvent& inputEvent) -{ - // If we've started a drag and drop operation, ignore input events until - // we're done. - if (m_doingDragAndDrop) - return true; - - // Report the event to be NOT processed by WebKit, so that the browser can handle it appropriately. - if (m_ignoreInputEvents) - return false; - - TemporaryChange<const WebInputEvent*> currentEventChange(m_currentInputEvent, &inputEvent); - -#if ENABLE(POINTER_LOCK) - if (isPointerLocked() && WebInputEvent::isMouseEventType(inputEvent.type)) { - pointerLockMouseEvent(inputEvent); - return true; - } -#endif - - if (m_mouseCaptureNode && WebInputEvent::isMouseEventType(inputEvent.type)) { - // Save m_mouseCaptureNode since mouseCaptureLost() will clear it. - RefPtr<Node> node = m_mouseCaptureNode; - - // Not all platforms call mouseCaptureLost() directly. - if (inputEvent.type == WebInputEvent::MouseUp) - mouseCaptureLost(); - - AtomicString eventType; - switch (inputEvent.type) { - case WebInputEvent::MouseMove: - eventType = eventNames().mousemoveEvent; - break; - case WebInputEvent::MouseLeave: - eventType = eventNames().mouseoutEvent; - break; - case WebInputEvent::MouseDown: - eventType = eventNames().mousedownEvent; - break; - case WebInputEvent::MouseUp: - eventType = eventNames().mouseupEvent; - break; - default: - ASSERT_NOT_REACHED(); - } - - node->dispatchMouseEvent( - PlatformMouseEventBuilder(mainFrameImpl()->frameView(), *static_cast<const WebMouseEvent*>(&inputEvent)), - eventType, static_cast<const WebMouseEvent*>(&inputEvent)->clickCount); - return true; - } - - if (!m_layerTreeView) - return PageWidgetDelegate::handleInputEvent(m_page.get(), *this, inputEvent); - - const WebInputEvent* inputEventTransformed = &inputEvent; - WebMouseEvent mouseEvent; - WebGestureEvent gestureEvent; - if (WebInputEvent::isMouseEventType(inputEvent.type)) { - mouseEvent = *static_cast<const WebMouseEvent*>(&inputEvent); - - IntPoint transformedLocation = roundedIntPoint(m_layerTreeView->adjustEventPointForPinchZoom(WebFloatPoint(mouseEvent.x, mouseEvent.y))); - mouseEvent.x = transformedLocation.x(); - mouseEvent.y = transformedLocation.y(); - inputEventTransformed = static_cast<const WebInputEvent*>(&mouseEvent); - } else if (WebInputEvent::isGestureEventType(inputEvent.type)) { - gestureEvent = *static_cast<const WebGestureEvent*>(&inputEvent); - - IntPoint transformedLocation = roundedIntPoint(m_layerTreeView->adjustEventPointForPinchZoom(WebFloatPoint(gestureEvent.x, gestureEvent.y))); - gestureEvent.x = transformedLocation.x(); - gestureEvent.y = transformedLocation.y(); - inputEventTransformed = static_cast<const WebInputEvent*>(&gestureEvent); - } - - bool handled = PageWidgetDelegate::handleInputEvent(m_page.get(), *this, *inputEventTransformed); - return handled; -} - -void WebViewImpl::mouseCaptureLost() -{ - m_mouseCaptureNode = 0; -} - -void WebViewImpl::setFocus(bool enable) -{ - m_page->focusController()->setFocused(enable); - if (enable) { - m_page->focusController()->setActive(true); - RefPtr<Frame> focusedFrame = m_page->focusController()->focusedFrame(); - if (focusedFrame) { - Node* focusedNode = focusedFrame->document()->focusedNode(); - if (focusedNode && focusedNode->isElementNode() - && focusedFrame->selection()->selection().isNone()) { - // If the selection was cleared while the WebView was not - // focused, then the focus element shows with a focus ring but - // no caret and does respond to keyboard inputs. - Element* element = static_cast<Element*>(focusedNode); - if (element->isTextFormControl()) - element->updateFocusAppearance(true); - else if (focusedNode->isContentEditable()) { - // updateFocusAppearance() selects all the text of - // contentseditable DIVs. So we set the selection explicitly - // instead. Note that this has the side effect of moving the - // caret back to the beginning of the text. - Position position(focusedNode, 0, - Position::PositionIsOffsetInAnchor); - focusedFrame->selection()->setSelection( - VisibleSelection(position, SEL_DEFAULT_AFFINITY)); - } - } - } - m_imeAcceptEvents = true; - } else { - hidePopups(); - - // Clear focus on the currently focused frame if any. - if (!m_page) - return; - - Frame* frame = m_page->mainFrame(); - if (!frame) - return; - - RefPtr<Frame> focusedFrame = m_page->focusController()->focusedFrame(); - if (focusedFrame) { - // Finish an ongoing composition to delete the composition node. - Editor* editor = focusedFrame->editor(); - if (editor && editor->hasComposition()) - editor->confirmComposition(); - m_imeAcceptEvents = false; - } - } -} - -bool WebViewImpl::setComposition( - const WebString& text, - const WebVector<WebCompositionUnderline>& underlines, - int selectionStart, - int selectionEnd) -{ - Frame* focused = focusedWebCoreFrame(); - if (!focused || !m_imeAcceptEvents) - return false; - Editor* editor = focused->editor(); - if (!editor) - return false; - - // The input focus has been moved to another WebWidget object. - // We should use this |editor| object only to complete the ongoing - // composition. - if (!editor->canEdit() && !editor->hasComposition()) - return false; - - // We should verify the parent node of this IME composition node are - // editable because JavaScript may delete a parent node of the composition - // node. In this case, WebKit crashes while deleting texts from the parent - // node, which doesn't exist any longer. - PassRefPtr<Range> range = editor->compositionRange(); - if (range) { - Node* node = range->startContainer(); - if (!node || !node->isContentEditable()) - return false; - } - - // If we're not going to fire a keypress event, then the keydown event was - // canceled. In that case, cancel any existing composition. - if (text.isEmpty() || m_suppressNextKeypressEvent) { - // A browser process sent an IPC message which does not contain a valid - // string, which means an ongoing composition has been canceled. - // If the ongoing composition has been canceled, replace the ongoing - // composition string with an empty string and complete it. - String emptyString; - Vector<CompositionUnderline> emptyUnderlines; - editor->setComposition(emptyString, emptyUnderlines, 0, 0); - return text.isEmpty(); - } - - // When the range of composition underlines overlap with the range between - // selectionStart and selectionEnd, WebKit somehow won't paint the selection - // at all (see InlineTextBox::paint() function in InlineTextBox.cpp). - // But the selection range actually takes effect. - editor->setComposition(String(text), - CompositionUnderlineVectorBuilder(underlines), - selectionStart, selectionEnd); - - return editor->hasComposition(); -} - -bool WebViewImpl::confirmComposition() -{ - return confirmComposition(WebString()); -} - -bool WebViewImpl::confirmComposition(const WebString& text) -{ - Frame* focused = focusedWebCoreFrame(); - if (!focused || !m_imeAcceptEvents) - return false; - Editor* editor = focused->editor(); - if (!editor || (!editor->hasComposition() && !text.length())) - return false; - - // We should verify the parent node of this IME composition node are - // editable because JavaScript may delete a parent node of the composition - // node. In this case, WebKit crashes while deleting texts from the parent - // node, which doesn't exist any longer. - PassRefPtr<Range> range = editor->compositionRange(); - if (range) { - Node* node = range->startContainer(); - if (!node || !node->isContentEditable()) - return false; - } - - if (editor->hasComposition()) { - if (text.length()) - editor->confirmComposition(String(text)); - else - editor->confirmComposition(); - } else - editor->insertText(String(text), 0); - - return true; -} - -bool WebViewImpl::compositionRange(size_t* location, size_t* length) -{ - Frame* focused = focusedWebCoreFrame(); - if (!focused || !focused->selection() || !m_imeAcceptEvents) - return false; - Editor* editor = focused->editor(); - if (!editor || !editor->hasComposition()) - return false; - - RefPtr<Range> range = editor->compositionRange(); - if (!range) - return false; - - if (TextIterator::getLocationAndLengthFromRange(focused->selection()->rootEditableElementOrDocumentElement(), range.get(), *location, *length)) - return true; - return false; -} - -WebTextInputInfo WebViewImpl::textInputInfo() -{ - WebTextInputInfo info; - - Frame* focused = focusedWebCoreFrame(); - if (!focused) - return info; - - Editor* editor = focused->editor(); - if (!editor || !editor->canEdit()) - return info; - - FrameSelection* selection = focused->selection(); - if (!selection) - return info; - - Node* node = selection->selection().rootEditableElement(); - if (!node) - return info; - - info.type = textInputType(); - if (info.type == WebTextInputTypeNone) - return info; - - info.value = plainText(rangeOfContents(node).get()); - - if (info.value.isEmpty()) - return info; - - size_t location; - size_t length; - RefPtr<Range> range = selection->selection().firstRange(); - if (range && TextIterator::getLocationAndLengthFromRange(selection->rootEditableElement(), range.get(), location, length)) { - info.selectionStart = location; - info.selectionEnd = location + length; - } - range = editor->compositionRange(); - if (range && TextIterator::getLocationAndLengthFromRange(selection->rootEditableElement(), range.get(), location, length)) { - info.compositionStart = location; - info.compositionEnd = location + length; - } - - return info; -} - -WebTextInputType WebViewImpl::textInputType() -{ - Node* node = focusedWebCoreNode(); - if (!node) - return WebTextInputTypeNone; - - if (node->hasTagName(HTMLNames::inputTag)) { - HTMLInputElement* input = static_cast<HTMLInputElement*>(node); - - if (input->readOnly() || input->disabled()) - return WebTextInputTypeNone; - - if (input->isPasswordField()) - return WebTextInputTypePassword; - if (input->isSearchField()) - return WebTextInputTypeSearch; - if (input->isEmailField()) - return WebTextInputTypeEmail; - if (input->isNumberField()) - return WebTextInputTypeNumber; - if (input->isTelephoneField()) - return WebTextInputTypeTelephone; - if (input->isURLField()) - return WebTextInputTypeURL; - if (input->isDateField()) - return WebTextInputTypeDate; - if (input->isDateTimeField()) - return WebTextInputTypeDateTime; - if (input->isDateTimeLocalField()) - return WebTextInputTypeDateTimeLocal; - if (input->isMonthField()) - return WebTextInputTypeMonth; - if (input->isTimeField()) - return WebTextInputTypeTime; - if (input->isWeekField()) - return WebTextInputTypeWeek; - if (input->isTextField()) - return WebTextInputTypeText; - - return WebTextInputTypeNone; - } - - if (node->hasTagName(HTMLNames::textareaTag)) { - HTMLTextAreaElement* textarea = static_cast<HTMLTextAreaElement*>(node); - - if (textarea->readOnly() || textarea->disabled()) - return WebTextInputTypeNone; - - return WebTextInputTypeTextArea; - } - - if (node->shouldUseInputMethod()) - return WebTextInputTypeContentEditable; - - return WebTextInputTypeNone; -} - -bool WebViewImpl::selectionBounds(WebRect& anchor, WebRect& focus) const -{ - const Frame* frame = focusedWebCoreFrame(); - if (!frame) - return false; - FrameSelection* selection = frame->selection(); - if (!selection) - return false; - - if (selection->isCaret()) { - anchor = focus = frame->view()->contentsToWindow(selection->absoluteCaretBounds()); - return true; - } - - RefPtr<Range> selectedRange = frame->selection()->toNormalizedRange(); - if (!selectedRange) - return false; - - RefPtr<Range> range(Range::create(selectedRange->startContainer()->document(), - selectedRange->startContainer(), - selectedRange->startOffset(), - selectedRange->startContainer(), - selectedRange->startOffset())); - anchor = frame->editor()->firstRectForRange(range.get()); - - range = Range::create(selectedRange->endContainer()->document(), - selectedRange->endContainer(), - selectedRange->endOffset(), - selectedRange->endContainer(), - selectedRange->endOffset()); - focus = frame->editor()->firstRectForRange(range.get()); - - anchor = frame->view()->contentsToWindow(anchor); - focus = frame->view()->contentsToWindow(focus); - - if (!frame->selection()->selection().isBaseFirst()) - std::swap(anchor, focus); - return true; -} - -bool WebViewImpl::selectionTextDirection(WebTextDirection& start, WebTextDirection& end) const -{ - const Frame* frame = focusedWebCoreFrame(); - if (!frame) - return false; - FrameSelection* selection = frame->selection(); - if (!selection) - return false; - if (!selection->toNormalizedRange()) - return false; - start = selection->start().primaryDirection() == RTL ? WebTextDirectionRightToLeft : WebTextDirectionLeftToRight; - end = selection->end().primaryDirection() == RTL ? WebTextDirectionRightToLeft : WebTextDirectionLeftToRight; - return true; -} - -bool WebViewImpl::setEditableSelectionOffsets(int start, int end) -{ - const Frame* focused = focusedWebCoreFrame(); - if (!focused) - return false; - - Editor* editor = focused->editor(); - if (!editor || !editor->canEdit()) - return false; - - return editor->setSelectionOffsets(start, end); -} - -bool WebViewImpl::setCompositionFromExistingText(int compositionStart, int compositionEnd, const WebVector<WebCompositionUnderline>& underlines) -{ - const Frame* focused = focusedWebCoreFrame(); - if (!focused) - return false; - - Editor* editor = focused->editor(); - if (!editor || !editor->canEdit()) - return false; - - editor->cancelComposition(); - - if (compositionStart == compositionEnd) - return true; - - size_t location; - size_t length; - caretOrSelectionRange(&location, &length); - editor->setIgnoreCompositionSelectionChange(true); - editor->setSelectionOffsets(compositionStart, compositionEnd); - String text = editor->selectedText(); - focused->document()->execCommand("delete", true); - editor->setComposition(text, CompositionUnderlineVectorBuilder(underlines), 0, 0); - editor->setSelectionOffsets(location, location + length); - editor->setIgnoreCompositionSelectionChange(false); - - return true; -} - -void WebViewImpl::extendSelectionAndDelete(int before, int after) -{ - const Frame* focused = focusedWebCoreFrame(); - if (!focused) - return; - - Editor* editor = focused->editor(); - if (!editor || !editor->canEdit()) - return; - - FrameSelection* selection = focused->selection(); - if (!selection) - return; - - size_t location; - size_t length; - RefPtr<Range> range = selection->selection().firstRange(); - if (range && TextIterator::getLocationAndLengthFromRange(selection->rootEditableElement(), range.get(), location, length)) { - editor->setSelectionOffsets(max(static_cast<int>(location) - before, 0), location + length + after); - focused->document()->execCommand("delete", true); - } -} - -bool WebViewImpl::isSelectionEditable() const -{ - const Frame* frame = focusedWebCoreFrame(); - if (!frame) - return false; - return frame->selection()->isContentEditable(); -} - -WebColor WebViewImpl::backgroundColor() const -{ - if (!m_page) - return Color::white; - FrameView* view = m_page->mainFrame()->view(); - Color backgroundColor = view->documentBackgroundColor(); - if (!backgroundColor.isValid()) - return Color::white; - return backgroundColor.rgb(); -} - -bool WebViewImpl::caretOrSelectionRange(size_t* location, size_t* length) -{ - const Frame* focused = focusedWebCoreFrame(); - if (!focused) - return false; - - FrameSelection* selection = focused->selection(); - if (!selection) - return false; - - RefPtr<Range> range = selection->selection().firstRange(); - if (!range) - return false; - - if (TextIterator::getLocationAndLengthFromRange(selection->rootEditableElementOrDocumentElement(), range.get(), *location, *length)) - return true; - return false; -} - -void WebViewImpl::setTextDirection(WebTextDirection direction) -{ - // The Editor::setBaseWritingDirection() function checks if we can change - // the text direction of the selected node and updates its DOM "dir" - // attribute and its CSS "direction" property. - // So, we just call the function as Safari does. - const Frame* focused = focusedWebCoreFrame(); - if (!focused) - return; - - Editor* editor = focused->editor(); - if (!editor || !editor->canEdit()) - return; - - switch (direction) { - case WebTextDirectionDefault: - editor->setBaseWritingDirection(NaturalWritingDirection); - break; - - case WebTextDirectionLeftToRight: - editor->setBaseWritingDirection(LeftToRightWritingDirection); - break; - - case WebTextDirectionRightToLeft: - editor->setBaseWritingDirection(RightToLeftWritingDirection); - break; - - default: - notImplemented(); - break; - } -} - -bool WebViewImpl::isAcceleratedCompositingActive() const -{ -#if USE(ACCELERATED_COMPOSITING) - return m_isAcceleratedCompositingActive; -#else - return false; -#endif -} - -void WebViewImpl::didAcquirePointerLock() -{ -#if ENABLE(POINTER_LOCK) - if (page()) - page()->pointerLockController()->didAcquirePointerLock(); -#endif -} - -void WebViewImpl::didNotAcquirePointerLock() -{ -#if ENABLE(POINTER_LOCK) - if (page()) - page()->pointerLockController()->didNotAcquirePointerLock(); -#endif -} - -void WebViewImpl::didLosePointerLock() -{ -#if ENABLE(POINTER_LOCK) - if (page()) - page()->pointerLockController()->didLosePointerLock(); -#endif -} - -void WebViewImpl::didChangeWindowResizerRect() -{ - if (mainFrameImpl()->frameView()) - mainFrameImpl()->frameView()->windowResizerRectChanged(); -} - -// WebView -------------------------------------------------------------------- - -WebSettingsImpl* WebViewImpl::settingsImpl() -{ - if (!m_webSettings) - m_webSettings = adoptPtr(new WebSettingsImpl(m_page->settings())); - ASSERT(m_webSettings); - return m_webSettings.get(); -} - -WebSettings* WebViewImpl::settings() -{ - return settingsImpl(); -} - -WebString WebViewImpl::pageEncoding() const -{ - if (!m_page) - return WebString(); - - // FIXME: Is this check needed? - if (!m_page->mainFrame()->document()->loader()) - return WebString(); - - return m_page->mainFrame()->document()->encoding(); -} - -void WebViewImpl::setPageEncoding(const WebString& encodingName) -{ - if (!m_page) - return; - - // Only change override encoding, don't change default encoding. - // Note that the new encoding must be 0 if it isn't supposed to be set. - String newEncodingName; - if (!encodingName.isEmpty()) - newEncodingName = encodingName; - m_page->mainFrame()->loader()->reloadWithOverrideEncoding(newEncodingName); -} - -bool WebViewImpl::dispatchBeforeUnloadEvent() -{ - // FIXME: This should really cause a recursive depth-first walk of all - // frames in the tree, calling each frame's onbeforeunload. At the moment, - // we're consistent with Safari 3.1, not IE/FF. - Frame* frame = m_page->mainFrame(); - if (!frame) - return true; - - return frame->loader()->shouldClose(); -} - -void WebViewImpl::dispatchUnloadEvent() -{ - // Run unload handlers. - m_page->mainFrame()->loader()->closeURL(); -} - -WebFrame* WebViewImpl::mainFrame() -{ - return mainFrameImpl(); -} - -WebFrame* WebViewImpl::findFrameByName( - const WebString& name, WebFrame* relativeToFrame) -{ - if (!relativeToFrame) - relativeToFrame = mainFrame(); - Frame* frame = static_cast<WebFrameImpl*>(relativeToFrame)->frame(); - frame = frame->tree()->find(name); - return WebFrameImpl::fromFrame(frame); -} - -WebFrame* WebViewImpl::focusedFrame() -{ - return WebFrameImpl::fromFrame(focusedWebCoreFrame()); -} - -void WebViewImpl::setFocusedFrame(WebFrame* frame) -{ - if (!frame) { - // Clears the focused frame if any. - Frame* frame = focusedWebCoreFrame(); - if (frame) - frame->selection()->setFocused(false); - return; - } - WebFrameImpl* frameImpl = static_cast<WebFrameImpl*>(frame); - Frame* webcoreFrame = frameImpl->frame(); - webcoreFrame->page()->focusController()->setFocusedFrame(webcoreFrame); -} - -void WebViewImpl::setInitialFocus(bool reverse) -{ - if (!m_page) - return; - - // Since we don't have a keyboard event, we'll create one. - WebKeyboardEvent keyboardEvent; - keyboardEvent.type = WebInputEvent::RawKeyDown; - if (reverse) - keyboardEvent.modifiers = WebInputEvent::ShiftKey; - - // VK_TAB which is only defined on Windows. - keyboardEvent.windowsKeyCode = 0x09; - PlatformKeyboardEventBuilder platformEvent(keyboardEvent); - RefPtr<KeyboardEvent> webkitEvent = KeyboardEvent::create(platformEvent, 0); - - Frame* frame = page()->focusController()->focusedOrMainFrame(); - if (Document* document = frame->document()) - document->setFocusedNode(0); - page()->focusController()->setInitialFocus( - reverse ? FocusDirectionBackward : FocusDirectionForward, - webkitEvent.get()); -} - -void WebViewImpl::clearFocusedNode() -{ - RefPtr<Frame> frame = focusedWebCoreFrame(); - if (!frame) - return; - - RefPtr<Document> document = frame->document(); - if (!document) - return; - - RefPtr<Node> oldFocusedNode = document->focusedNode(); - - // Clear the focused node. - document->setFocusedNode(0); - - if (!oldFocusedNode) - return; - - // If a text field has focus, we need to make sure the selection controller - // knows to remove selection from it. Otherwise, the text field is still - // processing keyboard events even though focus has been moved to the page and - // keystrokes get eaten as a result. - if (oldFocusedNode->isContentEditable() - || (oldFocusedNode->isElementNode() - && static_cast<Element*>(oldFocusedNode.get())->isTextFormControl())) { - frame->selection()->clear(); - } -} - -void WebViewImpl::scrollFocusedNodeIntoView() -{ - Node* focusedNode = focusedWebCoreNode(); - if (focusedNode && focusedNode->isElementNode()) { - Element* elementNode = static_cast<Element*>(focusedNode); - elementNode->scrollIntoViewIfNeeded(true); - } -} - -void WebViewImpl::scrollFocusedNodeIntoRect(const WebRect& rect) -{ - Frame* frame = page()->mainFrame(); - Node* focusedNode = focusedWebCoreNode(); - if (!frame || !frame->view() || !focusedNode || !focusedNode->isElementNode()) - return; - - if (!m_webSettings->autoZoomFocusedNodeToLegibleScale()) { - Element* elementNode = static_cast<Element*>(focusedNode); - frame->view()->scrollElementToRect(elementNode, IntRect(rect.x, rect.y, rect.width, rect.height)); - return; - } - -#if ENABLE(GESTURE_EVENTS) - focusedNode->document()->updateLayoutIgnorePendingStylesheets(); - - // 'caret' is rect encompassing the blinking cursor. - IntRect textboxRect = focusedNode->document()->view()->contentsToWindow(pixelSnappedIntRect(focusedNode->Node::boundingBox())); - WebRect caret, end; - selectionBounds(caret, end); - - // Pick a scale which is reasonably readable. This is the scale at which - // the caret height will become minReadableCaretHeight (adjusted for dpi - // and font scale factor). - float targetScale = deviceScaleFactor(); -#if ENABLE(TEXT_AUTOSIZING) - if (page() && page()->settings()) - targetScale *= page()->settings()->textAutosizingFontScaleFactor(); -#endif - const float newScale = clampPageScaleFactorToLimits(pageScaleFactor() * minReadableCaretHeight * targetScale / caret.height); - const float deltaScale = newScale / pageScaleFactor(); - - // Convert the rects to absolute space in the new scale. - IntRect textboxRectInDocumentCoordinates = textboxRect; - textboxRectInDocumentCoordinates.move(mainFrame()->scrollOffset()); - textboxRectInDocumentCoordinates.scale(deltaScale); - IntRect caretInDocumentCoordinates = caret; - caretInDocumentCoordinates.move(mainFrame()->scrollOffset()); - caretInDocumentCoordinates.scale(deltaScale); - - IntPoint newOffset; - if (textboxRectInDocumentCoordinates.width() <= m_size.width) { - // Field is narrower than screen. Try to leave padding on left so field's - // label is visible, but it's more important to ensure entire field is - // onscreen. - int idealLeftPadding = m_size.width * leftBoxRatio; - int maxLeftPaddingKeepingBoxOnscreen = m_size.width - textboxRectInDocumentCoordinates.width(); - newOffset.setX(textboxRectInDocumentCoordinates.x() - min<int>(idealLeftPadding, maxLeftPaddingKeepingBoxOnscreen)); - } else { - // Field is wider than screen. Try to left-align field, unless caret would - // be offscreen, in which case right-align the caret. - newOffset.setX(max<int>(textboxRectInDocumentCoordinates.x(), caretInDocumentCoordinates.x() + caretInDocumentCoordinates.width() + caretPadding - m_size.width)); - } - if (textboxRectInDocumentCoordinates.height() <= m_size.height) { - // Field is shorter than screen. Vertically center it. - newOffset.setY(textboxRectInDocumentCoordinates.y() - (m_size.height - textboxRectInDocumentCoordinates.height()) / 2); - } else { - // Field is taller than screen. Try to top align field, unless caret would - // be offscreen, in which case bottom-align the caret. - newOffset.setY(max<int>(textboxRectInDocumentCoordinates.y(), caretInDocumentCoordinates.y() + caretInDocumentCoordinates.height() + caretPadding - m_size.height)); - } - - bool needAnimation = false; - // If we are at less than the target zoom level, zoom in. - if (deltaScale > minScaleChangeToTriggerZoom) - needAnimation = true; - // If the caret is offscreen, then animate. - IntRect sizeRect(0, 0, m_size.width, m_size.height); - if (!sizeRect.contains(caret)) - needAnimation = true; - // If the box is partially offscreen and it's possible to bring it fully - // onscreen, then animate. - if (sizeRect.contains(textboxRectInDocumentCoordinates.width(), textboxRectInDocumentCoordinates.height()) && !sizeRect.contains(textboxRect)) - needAnimation = true; - - if (needAnimation) - startPageScaleAnimation(newOffset, false, newScale, scrollAndScaleAnimationDurationInSeconds); -#endif -} - -void WebViewImpl::advanceFocus(bool reverse) -{ - page()->focusController()->advanceFocus(reverse ? FocusDirectionBackward : FocusDirectionForward, 0); -} - -double WebViewImpl::zoomLevel() -{ - return m_zoomLevel; -} - -double WebViewImpl::setZoomLevel(bool textOnly, double zoomLevel) -{ - if (zoomLevel < m_minimumZoomLevel) - m_zoomLevel = m_minimumZoomLevel; - else if (zoomLevel > m_maximumZoomLevel) - m_zoomLevel = m_maximumZoomLevel; - else - m_zoomLevel = zoomLevel; - - Frame* frame = mainFrameImpl()->frame(); - WebPluginContainerImpl* pluginContainer = WebFrameImpl::pluginContainerFromFrame(frame); - if (pluginContainer) - pluginContainer->plugin()->setZoomLevel(m_zoomLevel, textOnly); - else { - float zoomFactor = static_cast<float>(zoomLevelToZoomFactor(m_zoomLevel)); - if (textOnly) - frame->setPageAndTextZoomFactors(1, zoomFactor * m_emulatedTextZoomFactor); - else - frame->setPageAndTextZoomFactors(zoomFactor, m_emulatedTextZoomFactor); - } - return m_zoomLevel; -} - -void WebViewImpl::zoomLimitsChanged(double minimumZoomLevel, - double maximumZoomLevel) -{ - m_minimumZoomLevel = minimumZoomLevel; - m_maximumZoomLevel = maximumZoomLevel; - m_client->zoomLimitsChanged(m_minimumZoomLevel, m_maximumZoomLevel); -} - -void WebViewImpl::fullFramePluginZoomLevelChanged(double zoomLevel) -{ - if (zoomLevel == m_zoomLevel) - return; - - m_zoomLevel = max(min(zoomLevel, m_maximumZoomLevel), m_minimumZoomLevel); - m_client->zoomLevelChanged(); -} - -double WebView::zoomLevelToZoomFactor(double zoomLevel) -{ - return pow(textSizeMultiplierRatio, zoomLevel); -} - -double WebView::zoomFactorToZoomLevel(double factor) -{ - // Since factor = 1.2^level, level = log(factor) / log(1.2) - return log(factor) / log(textSizeMultiplierRatio); -} - -float WebViewImpl::pageScaleFactor() const -{ - if (!page()) - return 1; - - return page()->pageScaleFactor(); -} - -bool WebViewImpl::isPageScaleFactorSet() const -{ - return m_pageScaleFactorIsSet; -} - -float WebViewImpl::clampPageScaleFactorToLimits(float scaleFactor) -{ - return min(max(scaleFactor, m_minimumPageScaleFactor), m_maximumPageScaleFactor); -} - -WebPoint WebViewImpl::clampOffsetAtScale(const WebPoint& offset, float scale) -{ - // This is the scaled content size. We need to convert it to the new scale factor. - WebSize contentSize = mainFrame()->contentsSize(); - float deltaScale = scale / pageScaleFactor(); - int docWidthAtNewScale = contentSize.width * deltaScale; - int docHeightAtNewScale = contentSize.height * deltaScale; - int viewWidth = m_size.width; - int viewHeight = m_size.height; - - // Enforce the maximum and minimum scroll positions at the new scale. - IntPoint clampedOffset = offset; - clampedOffset = clampedOffset.shrunkTo(IntPoint(docWidthAtNewScale - viewWidth, docHeightAtNewScale - viewHeight)); - clampedOffset.clampNegativeToZero(); - return clampedOffset; -} - -void WebViewImpl::setPageScaleFactorPreservingScrollOffset(float scaleFactor) -{ - // Pick a scale factor that is within the expected limits - scaleFactor = clampPageScaleFactorToLimits(scaleFactor); - - IntPoint scrollOffsetAtNewScale(mainFrame()->scrollOffset().width, mainFrame()->scrollOffset().height); - float deltaScale = scaleFactor / pageScaleFactor(); - scrollOffsetAtNewScale.scale(deltaScale, deltaScale); - - WebPoint clampedOffsetAtNewScale = clampOffsetAtScale(scrollOffsetAtNewScale, scaleFactor); - setPageScaleFactor(scaleFactor, clampedOffsetAtNewScale); -} - -void WebViewImpl::setPageScaleFactor(float scaleFactor, const WebPoint& origin) -{ - if (!page()) - return; - - if (!scaleFactor) - scaleFactor = 1; - - if (m_deviceScaleInCompositor != 1) { - // Don't allow page scaling when compositor scaling is being used, - // as they are currently incompatible. - ASSERT(scaleFactor == 1); - } - - scaleFactor = clampPageScaleFactorToLimits(scaleFactor); - WebPoint scrollOffset; - if (!m_page->settings()->applyPageScaleFactorInCompositor()) { - // If page scale is not applied in the compositor, then the scroll offsets should - // be modified by the scale factor. - scrollOffset = clampOffsetAtScale(origin, scaleFactor); - } else { - IntPoint offset = origin; - WebSize contentSize = mainFrame()->contentsSize(); - offset.shrunkTo(IntPoint(contentSize.width - m_size.width, contentSize.height - m_size.height)); - offset.clampNegativeToZero(); - scrollOffset = offset; - } - - page()->setPageScaleFactor(scaleFactor, scrollOffset); - m_pageScaleFactorIsSet = true; -} - -float WebViewImpl::deviceScaleFactor() const -{ - if (!page()) - return 1; - - return page()->deviceScaleFactor(); -} - -void WebViewImpl::setDeviceScaleFactor(float scaleFactor) -{ - if (!page()) - return; - - page()->setDeviceScaleFactor(scaleFactor); - - if (m_layerTreeView && m_webSettings->applyDeviceScaleFactorInCompositor()) { - m_deviceScaleInCompositor = page()->deviceScaleFactor(); - m_layerTreeView->setDeviceScaleFactor(m_deviceScaleInCompositor); - } - if (m_deviceScaleInCompositor != 1) { - // Don't allow page scaling when compositor scaling is being used, - // as they are currently incompatible. This means the deviceScale - // needs to match the one in the compositor. - ASSERT(scaleFactor == m_deviceScaleInCompositor); - } -} - -bool WebViewImpl::isFixedLayoutModeEnabled() const -{ - if (!page()) - return false; - - Frame* frame = page()->mainFrame(); - if (!frame || !frame->view()) - return false; - - return frame->view()->useFixedLayout(); -} - -void WebViewImpl::enableFixedLayoutMode(bool enable) -{ - if (!page()) - return; - - Frame* frame = page()->mainFrame(); - if (!frame || !frame->view()) - return; - - frame->view()->setUseFixedLayout(enable); - -#if USE(ACCELERATED_COMPOSITING) - // Also notify the base layer, which RenderLayerCompositor does not see. - if (m_nonCompositedContentHost) - updateLayerTreeViewport(); -#endif -} - - -void WebViewImpl::enableAutoResizeMode(const WebSize& minSize, const WebSize& maxSize) -{ - m_shouldAutoResize = true; - m_minAutoSize = minSize; - m_maxAutoSize = maxSize; - configureAutoResizeMode(); -} - -void WebViewImpl::disableAutoResizeMode() -{ - m_shouldAutoResize = false; - configureAutoResizeMode(); -} - -void WebViewImpl::setPageScaleFactorLimits(float minPageScale, float maxPageScale) -{ - m_pageDefinedMinimumPageScaleFactor = minPageScale; - m_pageDefinedMaximumPageScaleFactor = maxPageScale; - computePageScaleFactorLimits(); -} - -void WebViewImpl::setIgnoreViewportTagMaximumScale(bool flag) -{ - m_ignoreViewportTagMaximumScale = flag; - - if (!page() || !page()->mainFrame()) - return; - - m_page->chrome()->client()->dispatchViewportPropertiesDidChange(page()->mainFrame()->document()->viewportArguments()); -} - -static IntSize unscaledContentsSize(Frame* frame) -{ - RenderView* root = frame->contentRenderer(); - if (!root) - return IntSize(); - return root->unscaledDocumentRect().size(); -} - -bool WebViewImpl::computePageScaleFactorLimits() -{ - if (m_pageDefinedMinimumPageScaleFactor == -1 || m_pageDefinedMaximumPageScaleFactor == -1) - return false; - - if (!mainFrame() || !page() || !page()->mainFrame() || !page()->mainFrame()->view()) - return false; - - m_minimumPageScaleFactor = min(max(m_pageDefinedMinimumPageScaleFactor, minPageScaleFactor), maxPageScaleFactor) * (deviceScaleFactor() / m_deviceScaleInCompositor); - m_maximumPageScaleFactor = max(min(m_pageDefinedMaximumPageScaleFactor, maxPageScaleFactor), minPageScaleFactor) * (deviceScaleFactor() / m_deviceScaleInCompositor); - - int viewWidthNotIncludingScrollbars = page()->mainFrame()->view()->visibleContentRect(false).width(); - int unscaledContentsWidth = unscaledContentsSize(page()->mainFrame()).width(); - if (viewWidthNotIncludingScrollbars && unscaledContentsWidth) { - // Limit page scaling down to the document width. - m_minimumPageScaleFactor = max(m_minimumPageScaleFactor, static_cast<float>(viewWidthNotIncludingScrollbars) / unscaledContentsWidth); - m_maximumPageScaleFactor = max(m_minimumPageScaleFactor, m_maximumPageScaleFactor); - } - ASSERT(m_minimumPageScaleFactor <= m_maximumPageScaleFactor); - - float clampedScale = clampPageScaleFactorToLimits(pageScaleFactor()); -#if USE(ACCELERATED_COMPOSITING) - if (m_layerTreeView) - m_layerTreeView->setPageScaleFactorAndLimits(clampedScale, m_minimumPageScaleFactor, m_maximumPageScaleFactor); -#endif - if (clampedScale != pageScaleFactor()) { - setPageScaleFactorPreservingScrollOffset(clampedScale); - return true; - } - - return false; -} - -float WebViewImpl::minimumPageScaleFactor() const -{ - return m_minimumPageScaleFactor; -} - -float WebViewImpl::maximumPageScaleFactor() const -{ - return m_maximumPageScaleFactor; -} - -void WebViewImpl::saveScrollAndScaleState() -{ - m_savedPageScaleFactor = pageScaleFactor(); - m_savedScrollOffset = mainFrame()->scrollOffset(); -} - -void WebViewImpl::restoreScrollAndScaleState() -{ - if (!m_savedPageScaleFactor) - return; - -#if ENABLE(GESTURE_EVENTS) - startPageScaleAnimation(IntPoint(m_savedScrollOffset), false, m_savedPageScaleFactor, scrollAndScaleAnimationDurationInSeconds); -#else - setPageScaleFactor(m_savedPageScaleFactor, WebPoint()); - mainFrame()->setScrollOffset(m_savedScrollOffset); -#endif - - resetSavedScrollAndScaleState(); -} - -void WebViewImpl::resetSavedScrollAndScaleState() -{ - m_savedPageScaleFactor = 0; - m_savedScrollOffset = IntSize(); -} - -void WebViewImpl::resetScrollAndScaleState() -{ - page()->setPageScaleFactor(0, IntPoint()); - m_pageScaleFactorIsSet = false; - - // Clobber saved scales and scroll offsets. - if (FrameView* view = page()->mainFrame()->document()->view()) - view->cacheCurrentScrollPosition(); - resetSavedScrollAndScaleState(); - page()->mainFrame()->loader()->history()->saveDocumentAndScrollState(); -} - -WebSize WebViewImpl::fixedLayoutSize() const -{ - if (!page()) - return WebSize(); - - Frame* frame = page()->mainFrame(); - if (!frame || !frame->view()) - return WebSize(); - - return frame->view()->fixedLayoutSize(); -} - -void WebViewImpl::setFixedLayoutSize(const WebSize& layoutSize) -{ - if (!page()) - return; - - Frame* frame = page()->mainFrame(); - if (!frame || !frame->view()) - return; - - frame->view()->setFixedLayoutSize(layoutSize); -} - -void WebViewImpl::performMediaPlayerAction(const WebMediaPlayerAction& action, - const WebPoint& location) -{ - HitTestResult result = hitTestResultForWindowPos(location); - RefPtr<Node> node = result.innerNonSharedNode(); - if (!node->hasTagName(HTMLNames::videoTag) && !node->hasTagName(HTMLNames::audioTag)) - return; - - RefPtr<HTMLMediaElement> mediaElement = - static_pointer_cast<HTMLMediaElement>(node); - switch (action.type) { - case WebMediaPlayerAction::Play: - if (action.enable) - mediaElement->play(); - else - mediaElement->pause(); - break; - case WebMediaPlayerAction::Mute: - mediaElement->setMuted(action.enable); - break; - case WebMediaPlayerAction::Loop: - mediaElement->setLoop(action.enable); - break; - case WebMediaPlayerAction::Controls: - mediaElement->setControls(action.enable); - break; - default: - ASSERT_NOT_REACHED(); - } -} - -void WebViewImpl::performPluginAction(const WebPluginAction& action, - const WebPoint& location) -{ - HitTestResult result = hitTestResultForWindowPos(location); - RefPtr<Node> node = result.innerNonSharedNode(); - if (!node->hasTagName(HTMLNames::objectTag) && !node->hasTagName(HTMLNames::embedTag)) - return; - - RenderObject* object = node->renderer(); - if (object && object->isWidget()) { - Widget* widget = toRenderWidget(object)->widget(); - if (widget && widget->isPluginContainer()) { - WebPluginContainerImpl* plugin = static_cast<WebPluginContainerImpl*>(widget); - switch (action.type) { - case WebPluginAction::Rotate90Clockwise: - plugin->plugin()->rotateView(WebPlugin::RotationType90Clockwise); - break; - case WebPluginAction::Rotate90Counterclockwise: - plugin->plugin()->rotateView(WebPlugin::RotationType90Counterclockwise); - break; - default: - ASSERT_NOT_REACHED(); - } - } - } -} - -WebHitTestResult WebViewImpl::hitTestResultAt(const WebPoint& point) -{ - return hitTestResultForWindowPos(point); -} - -void WebViewImpl::copyImageAt(const WebPoint& point) -{ - if (!m_page) - return; - - HitTestResult result = hitTestResultForWindowPos(point); - - if (result.absoluteImageURL().isEmpty()) { - // There isn't actually an image at these coordinates. Might be because - // the window scrolled while the context menu was open or because the page - // changed itself between when we thought there was an image here and when - // we actually tried to retreive the image. - // - // FIXME: implement a cache of the most recent HitTestResult to avoid having - // to do two hit tests. - return; - } - - m_page->mainFrame()->editor()->copyImage(result); -} - -void WebViewImpl::dragSourceEndedAt( - const WebPoint& clientPoint, - const WebPoint& screenPoint, - WebDragOperation operation) -{ - PlatformMouseEvent pme(clientPoint, - screenPoint, - LeftButton, PlatformEvent::MouseMoved, 0, false, false, false, - false, 0); - m_page->mainFrame()->eventHandler()->dragSourceEndedAt(pme, - static_cast<DragOperation>(operation)); - m_dragScrollTimer->stop(); -} - -void WebViewImpl::dragSourceMovedTo( - const WebPoint& clientPoint, - const WebPoint& screenPoint, - WebDragOperation operation) -{ - m_dragScrollTimer->triggerScroll(mainFrameImpl()->frameView(), clientPoint); -} - -void WebViewImpl::dragSourceSystemDragEnded() -{ - // It's possible for us to get this callback while not doing a drag if - // it's from a previous page that got unloaded. - if (m_doingDragAndDrop) { - m_page->dragController()->dragEnded(); - m_doingDragAndDrop = false; - } -} - -WebDragOperation WebViewImpl::dragTargetDragEnter( - const WebDragData& webDragData, - const WebPoint& clientPoint, - const WebPoint& screenPoint, - WebDragOperationsMask operationsAllowed, - int keyModifiers) -{ - ASSERT(!m_currentDragData); - - m_currentDragData = webDragData; - m_operationsAllowed = operationsAllowed; - - return dragTargetDragEnterOrOver(clientPoint, screenPoint, DragEnter, keyModifiers); -} - -WebDragOperation WebViewImpl::dragTargetDragOver( - const WebPoint& clientPoint, - const WebPoint& screenPoint, - WebDragOperationsMask operationsAllowed, - int keyModifiers) -{ - m_operationsAllowed = operationsAllowed; - - return dragTargetDragEnterOrOver(clientPoint, screenPoint, DragOver, keyModifiers); -} - -void WebViewImpl::dragTargetDragLeave() -{ - ASSERT(m_currentDragData); - - DragData dragData( - m_currentDragData.get(), - IntPoint(), - IntPoint(), - static_cast<DragOperation>(m_operationsAllowed)); - - m_page->dragController()->dragExited(&dragData); - - // FIXME: why is the drag scroll timer not stopped here? - - m_dragOperation = WebDragOperationNone; - m_currentDragData = 0; -} - -void WebViewImpl::dragTargetDrop(const WebPoint& clientPoint, - const WebPoint& screenPoint, - int keyModifiers) -{ - ASSERT(m_currentDragData); - - // If this webview transitions from the "drop accepting" state to the "not - // accepting" state, then our IPC message reply indicating that may be in- - // flight, or else delayed by javascript processing in this webview. If a - // drop happens before our IPC reply has reached the browser process, then - // the browser forwards the drop to this webview. So only allow a drop to - // proceed if our webview m_dragOperation state is not DragOperationNone. - - if (m_dragOperation == WebDragOperationNone) { // IPC RACE CONDITION: do not allow this drop. - dragTargetDragLeave(); - return; - } - - m_currentDragData->setModifierKeyState(webInputEventKeyStateToPlatformEventKeyState(keyModifiers)); - DragData dragData( - m_currentDragData.get(), - clientPoint, - screenPoint, - static_cast<DragOperation>(m_operationsAllowed)); - - m_page->dragController()->performDrag(&dragData); - - m_dragOperation = WebDragOperationNone; - m_currentDragData = 0; - - m_dragScrollTimer->stop(); -} - -WebDragOperation WebViewImpl::dragTargetDragEnterOrOver(const WebPoint& clientPoint, const WebPoint& screenPoint, DragAction dragAction, int keyModifiers) -{ - ASSERT(m_currentDragData); - - m_currentDragData->setModifierKeyState(webInputEventKeyStateToPlatformEventKeyState(keyModifiers)); - DragData dragData( - m_currentDragData.get(), - clientPoint, - screenPoint, - static_cast<DragOperation>(m_operationsAllowed)); - - DragSession dragSession; - if (dragAction == DragEnter) - dragSession = m_page->dragController()->dragEntered(&dragData); - else - dragSession = m_page->dragController()->dragUpdated(&dragData); - - DragOperation dropEffect = dragSession.operation; - - // Mask the drop effect operation against the drag source's allowed operations. - if (!(dropEffect & dragData.draggingSourceOperationMask())) - dropEffect = DragOperationNone; - - m_dragOperation = static_cast<WebDragOperation>(dropEffect); - - if (dragAction == DragOver) - m_dragScrollTimer->triggerScroll(mainFrameImpl()->frameView(), clientPoint); - else - m_dragScrollTimer->stop(); - - return m_dragOperation; -} - -void WebViewImpl::sendResizeEventAndRepaint() -{ - if (mainFrameImpl()->frameView()) { - // Enqueues the resize event. - mainFrameImpl()->frame()->eventHandler()->sendResizeEvent(); - } - - if (m_client) { - if (isAcceleratedCompositingActive()) { -#if USE(ACCELERATED_COMPOSITING) - updateLayerTreeViewport(); -#endif - } else { - WebRect damagedRect(0, 0, m_size.width, m_size.height); - m_client->didInvalidateRect(damagedRect); - } - } - if (m_pageOverlays) - m_pageOverlays->update(); -} - -void WebViewImpl::configureAutoResizeMode() -{ - if (!mainFrameImpl() || !mainFrameImpl()->frame() || !mainFrameImpl()->frame()->view()) - return; - - mainFrameImpl()->frame()->view()->enableAutoSizeMode(m_shouldAutoResize, m_minAutoSize, m_maxAutoSize); -} - -unsigned long WebViewImpl::createUniqueIdentifierForRequest() -{ - if (m_page) - return m_page->progress()->createUniqueIdentifier(); - return 0; -} - -void WebViewImpl::inspectElementAt(const WebPoint& point) -{ - if (!m_page) - return; - - if (point.x == -1 || point.y == -1) - m_page->inspectorController()->inspect(0); - else { - HitTestResult result = hitTestResultForWindowPos(point); - - if (!result.innerNonSharedNode()) - return; - - m_page->inspectorController()->inspect(result.innerNonSharedNode()); - } -} - -WebString WebViewImpl::inspectorSettings() const -{ - return m_inspectorSettings; -} - -void WebViewImpl::setInspectorSettings(const WebString& settings) -{ - m_inspectorSettings = settings; -} - -bool WebViewImpl::inspectorSetting(const WebString& key, WebString* value) const -{ - if (!m_inspectorSettingsMap->contains(key)) - return false; - *value = m_inspectorSettingsMap->get(key); - return true; -} - -void WebViewImpl::setInspectorSetting(const WebString& key, - const WebString& value) -{ - m_inspectorSettingsMap->set(key, value); - client()->didUpdateInspectorSetting(key, value); -} - -WebDevToolsAgent* WebViewImpl::devToolsAgent() -{ - return m_devToolsAgent.get(); -} - -WebAccessibilityObject WebViewImpl::accessibilityObject() -{ - if (!mainFrameImpl()) - return WebAccessibilityObject(); - - Document* document = mainFrameImpl()->frame()->document(); - return WebAccessibilityObject( - document->axObjectCache()->getOrCreate(document->renderer())); -} - -void WebViewImpl::applyAutofillSuggestions( - const WebNode& node, - const WebVector<WebString>& names, - const WebVector<WebString>& labels, - const WebVector<WebString>& icons, - const WebVector<int>& itemIDs, - int separatorIndex) -{ - ASSERT(names.size() == labels.size()); - ASSERT(names.size() == itemIDs.size()); - - if (names.isEmpty()) { - hideAutofillPopup(); - return; - } - - RefPtr<Node> focusedNode = focusedWebCoreNode(); - // If the node for which we queried the Autofill suggestions is not the - // focused node, then we have nothing to do. FIXME: also check the - // caret is at the end and that the text has not changed. - if (!focusedNode || focusedNode != PassRefPtr<Node>(node)) { - hideAutofillPopup(); - return; - } - - HTMLInputElement* inputElem = focusedNode->toInputElement(); - ASSERT(inputElem); - - // The first time the Autofill popup is shown we'll create the client and - // the popup. - if (!m_autofillPopupClient) - m_autofillPopupClient = adoptPtr(new AutofillPopupMenuClient); - - m_autofillPopupClient->initialize( - inputElem, names, labels, icons, itemIDs, separatorIndex); - - if (!m_autofillPopup) { - PopupContainerSettings popupSettings = autofillPopupSettings; - popupSettings.deviceSupportsTouch = settingsImpl()->deviceSupportsTouch(); - m_autofillPopup = PopupContainer::create(m_autofillPopupClient.get(), - PopupContainer::Suggestion, - popupSettings); - } - - if (m_autofillPopupShowing) { - refreshAutofillPopup(); - } else { - m_autofillPopupShowing = true; - m_autofillPopup->showInRect(focusedNode->pixelSnappedBoundingBox(), focusedNode->ownerDocument()->view(), 0); - } -} - -void WebViewImpl::hidePopups() -{ - hideSelectPopup(); - hideAutofillPopup(); -#if ENABLE(PAGE_POPUP) - if (m_pagePopup) - closePagePopup(m_pagePopup.get()); -#endif -} - -void WebViewImpl::performCustomContextMenuAction(unsigned action) -{ - if (!m_page) - return; - ContextMenu* menu = m_page->contextMenuController()->contextMenu(); - if (!menu) - return; - ContextMenuItem* item = menu->itemWithAction(static_cast<ContextMenuAction>(ContextMenuItemBaseCustomTag + action)); - if (item) - m_page->contextMenuController()->contextMenuItemSelected(item); - m_page->contextMenuController()->clearContextMenu(); -} - -// WebView -------------------------------------------------------------------- - -void WebViewImpl::setIsTransparent(bool isTransparent) -{ - // Set any existing frames to be transparent. - Frame* frame = m_page->mainFrame(); - while (frame) { - frame->view()->setTransparent(isTransparent); - frame = frame->tree()->traverseNext(); - } - - // Future frames check this to know whether to be transparent. - m_isTransparent = isTransparent; - - if (m_nonCompositedContentHost) - m_nonCompositedContentHost->setOpaque(!isTransparent); - - if (m_layerTreeView) - m_layerTreeView->setHasTransparentBackground(isTransparent); -} - -bool WebViewImpl::isTransparent() const -{ - return m_isTransparent; -} - -void WebViewImpl::setIsActive(bool active) -{ - if (page() && page()->focusController()) - page()->focusController()->setActive(active); -} - -bool WebViewImpl::isActive() const -{ - return (page() && page()->focusController()) ? page()->focusController()->isActive() : false; -} - -void WebViewImpl::setDomainRelaxationForbidden(bool forbidden, const WebString& scheme) -{ - SchemeRegistry::setDomainRelaxationForbiddenForURLScheme(forbidden, String(scheme)); -} - -void WebViewImpl::setScrollbarColors(unsigned inactiveColor, - unsigned activeColor, - unsigned trackColor) { -#if ENABLE(DEFAULT_RENDER_THEME) - PlatformThemeChromiumDefault::setScrollbarColors(inactiveColor, activeColor, trackColor); -#elif OS(UNIX) && !OS(DARWIN) && !OS(ANDROID) - PlatformThemeChromiumLinux::setScrollbarColors(inactiveColor, activeColor, trackColor); -#endif -} - -void WebViewImpl::setSelectionColors(unsigned activeBackgroundColor, - unsigned activeForegroundColor, - unsigned inactiveBackgroundColor, - unsigned inactiveForegroundColor) { -#if ENABLE(DEFAULT_RENDER_THEME) - RenderThemeChromiumDefault::setSelectionColors(activeBackgroundColor, activeForegroundColor, inactiveBackgroundColor, inactiveForegroundColor); - theme()->platformColorsDidChange(); -#elif OS(UNIX) && !OS(DARWIN) && !OS(ANDROID) - RenderThemeChromiumLinux::setSelectionColors(activeBackgroundColor, activeForegroundColor, inactiveBackgroundColor, inactiveForegroundColor); - theme()->platformColorsDidChange(); -#endif -} - -void WebView::addUserScript(const WebString& sourceCode, - const WebVector<WebString>& patternsIn, - WebView::UserScriptInjectAt injectAt, - WebView::UserContentInjectIn injectIn) -{ - Vector<String> patterns; - for (size_t i = 0; i < patternsIn.size(); ++i) - patterns.append(patternsIn[i]); - - PageGroup* pageGroup = PageGroup::pageGroup(pageGroupName); - RefPtr<DOMWrapperWorld> world(DOMWrapperWorld::createUninitializedWorld()); - pageGroup->addUserScriptToWorld(world.get(), sourceCode, WebURL(), patterns, Vector<String>(), - static_cast<UserScriptInjectionTime>(injectAt), - static_cast<UserContentInjectedFrames>(injectIn)); -} - -void WebView::addUserStyleSheet(const WebString& sourceCode, - const WebVector<WebString>& patternsIn, - WebView::UserContentInjectIn injectIn, - WebView::UserStyleInjectionTime injectionTime) -{ - Vector<String> patterns; - for (size_t i = 0; i < patternsIn.size(); ++i) - patterns.append(patternsIn[i]); - - PageGroup* pageGroup = PageGroup::pageGroup(pageGroupName); - RefPtr<DOMWrapperWorld> world(DOMWrapperWorld::createUninitializedWorld()); - - // FIXME: Current callers always want the level to be "author". It probably makes sense to let - // callers specify this though, since in other cases the caller will probably want "user" level. - // - // FIXME: It would be nice to populate the URL correctly, instead of passing an empty URL. - pageGroup->addUserStyleSheetToWorld(world.get(), sourceCode, WebURL(), patterns, Vector<String>(), - static_cast<UserContentInjectedFrames>(injectIn), - UserStyleAuthorLevel, - static_cast<WebCore::UserStyleInjectionTime>(injectionTime)); -} - -void WebView::removeAllUserContent() -{ - PageGroup* pageGroup = PageGroup::pageGroup(pageGroupName); - pageGroup->removeAllUserContent(); -} - -void WebViewImpl::didCommitLoad(bool* isNewNavigation, bool isNavigationWithinPage) -{ - if (isNewNavigation) - *isNewNavigation = m_observedNewNavigation; - -#ifndef NDEBUG - ASSERT(!m_observedNewNavigation - || m_page->mainFrame()->loader()->documentLoader() == m_newNavigationLoader); - m_newNavigationLoader = 0; -#endif - m_observedNewNavigation = false; - if (*isNewNavigation && !isNavigationWithinPage) { - m_pageScaleFactorIsSet = false; - m_doubleTapZoomInEffect = false; - } - - // Make sure link highlight from previous page is cleared. - m_linkHighlight.clear(); - m_gestureAnimation.clear(); - resetSavedScrollAndScaleState(); -} - -void WebViewImpl::layoutUpdated(WebFrameImpl* webframe) -{ - if (!m_client || webframe != mainFrameImpl()) - return; - - if (m_shouldAutoResize && mainFrameImpl()->frame() && mainFrameImpl()->frame()->view()) { - WebSize frameSize = mainFrameImpl()->frame()->view()->frameRect().size(); - if (frameSize != m_size) { - m_size = frameSize; - m_client->didAutoResize(m_size); - sendResizeEventAndRepaint(); - } - } - - m_client->didUpdateLayout(); -} - -void WebViewImpl::didChangeContentsSize() -{ -#if ENABLE(VIEWPORT) - if (!settings()->viewportEnabled()) - return; - - bool didChangeScale = false; - if (!isPageScaleFactorSet()) { - // If the viewport tag failed to be processed earlier, we need - // to recompute it now. - ViewportArguments viewportArguments = mainFrameImpl()->frame()->document()->viewportArguments(); - m_page->chrome()->client()->dispatchViewportPropertiesDidChange(viewportArguments); - didChangeScale = true; - } else - didChangeScale = computePageScaleFactorLimits(); - - if (!didChangeScale) - return; - - if (!mainFrameImpl()) - return; - - FrameView* view = mainFrameImpl()->frameView(); - if (view && view->needsLayout()) - view->layout(); -#endif -} - -bool WebViewImpl::useExternalPopupMenus() -{ - return shouldUseExternalPopupMenus; -} - -void WebViewImpl::setEmulatedTextZoomFactor(float textZoomFactor) -{ - m_emulatedTextZoomFactor = textZoomFactor; - Frame* frame = mainFrameImpl()->frame(); - if (frame) - frame->setPageAndTextZoomFactors(frame->pageZoomFactor(), m_emulatedTextZoomFactor); -} - -bool WebViewImpl::navigationPolicyFromMouseEvent(unsigned short button, - bool ctrl, bool shift, - bool alt, bool meta, - WebNavigationPolicy* policy) -{ -#if OS(DARWIN) - const bool newTabModifier = (button == 1) || meta; -#else - const bool newTabModifier = (button == 1) || ctrl; -#endif - if (!newTabModifier && !shift && !alt) - return false; - - ASSERT(policy); - if (newTabModifier) { - if (shift) - *policy = WebNavigationPolicyNewForegroundTab; - else - *policy = WebNavigationPolicyNewBackgroundTab; - } else { - if (shift) - *policy = WebNavigationPolicyNewWindow; - else - *policy = WebNavigationPolicyDownload; - } - return true; -} - -void WebViewImpl::startDragging(Frame* frame, - const WebDragData& dragData, - WebDragOperationsMask mask, - const WebImage& dragImage, - const WebPoint& dragImageOffset) -{ - if (!m_client) - return; - ASSERT(!m_doingDragAndDrop); - m_doingDragAndDrop = true; - m_client->startDragging(WebFrameImpl::fromFrame(frame), dragData, mask, dragImage, dragImageOffset); -} - -void WebViewImpl::observeNewNavigation() -{ - m_observedNewNavigation = true; -#ifndef NDEBUG - m_newNavigationLoader = m_page->mainFrame()->loader()->documentLoader(); -#endif -} - -void WebViewImpl::setIgnoreInputEvents(bool newValue) -{ - ASSERT(m_ignoreInputEvents != newValue); - m_ignoreInputEvents = newValue; -} - -void WebViewImpl::addPageOverlay(WebPageOverlay* overlay, int zOrder) -{ - if (!m_pageOverlays) - m_pageOverlays = PageOverlayList::create(this); - - m_pageOverlays->add(overlay, zOrder); -} - -void WebViewImpl::removePageOverlay(WebPageOverlay* overlay) -{ - if (m_pageOverlays && m_pageOverlays->remove(overlay) && m_pageOverlays->empty()) - m_pageOverlays = nullptr; -} - -void WebViewImpl::setOverlayLayer(WebCore::GraphicsLayer* layer) -{ - if (m_rootGraphicsLayer) { - if (layer->parent() != m_rootGraphicsLayer) - m_rootGraphicsLayer->addChild(layer); - } -} - -#if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS) -NotificationPresenterImpl* WebViewImpl::notificationPresenterImpl() -{ - if (!m_notificationPresenter.isInitialized() && m_client) - m_notificationPresenter.initialize(m_client->notificationPresenter()); - return &m_notificationPresenter; -} -#endif - -void WebViewImpl::refreshAutofillPopup() -{ - ASSERT(m_autofillPopupShowing); - - // Hide the popup if it has become empty. - if (!m_autofillPopupClient->listSize()) { - hideAutofillPopup(); - return; - } - - WebRect newWidgetRect = m_autofillPopup->refresh(focusedWebCoreNode()->pixelSnappedBoundingBox()); - // Let's resize the backing window if necessary. - WebPopupMenuImpl* popupMenu = static_cast<WebPopupMenuImpl*>(m_autofillPopup->client()); - if (popupMenu && popupMenu->client()->windowRect() != newWidgetRect) - popupMenu->client()->setWindowRect(newWidgetRect); -} - -Node* WebViewImpl::focusedWebCoreNode() -{ - Frame* frame = m_page->focusController()->focusedFrame(); - if (!frame) - return 0; - - Document* document = frame->document(); - if (!document) - return 0; - - return document->focusedNode(); -} - -HitTestResult WebViewImpl::hitTestResultForWindowPos(const IntPoint& pos) -{ - IntPoint docPoint(m_page->mainFrame()->view()->windowToContents(pos)); - return m_page->mainFrame()->eventHandler()->hitTestResultAtPoint(docPoint, false); -} - -void WebViewImpl::setTabsToLinks(bool enable) -{ - m_tabsToLinks = enable; -} - -bool WebViewImpl::tabsToLinks() const -{ - return m_tabsToLinks; -} - -void WebViewImpl::suppressInvalidations(bool enable) -{ - m_suppressInvalidations = enable; -} - -#if USE(ACCELERATED_COMPOSITING) -bool WebViewImpl::allowsAcceleratedCompositing() -{ - return !m_compositorCreationFailed; -} - -void WebViewImpl::setRootGraphicsLayer(GraphicsLayer* layer) -{ - TemporaryChange<bool> change(m_suppressInvalidations, true); - - m_rootGraphicsLayer = layer; - m_rootLayer = layer ? layer->platformLayer() : 0; - - setIsAcceleratedCompositingActive(layer); - if (m_nonCompositedContentHost) { - GraphicsLayer* scrollLayer = 0; - if (layer) { - Document* document = page()->mainFrame()->document(); - RenderView* renderView = document->renderView(); - RenderLayerCompositor* compositor = renderView->compositor(); - scrollLayer = compositor->scrollLayer(); - } - m_nonCompositedContentHost->setScrollLayer(scrollLayer); - } - - if (m_layerTreeView) { - if (m_rootLayer) - m_layerTreeView->setRootLayer(*m_rootLayer); - else - m_layerTreeView->clearRootLayer(); - } - - IntRect damagedRect(0, 0, m_size.width, m_size.height); - if (!m_isAcceleratedCompositingActive && !m_suppressInvalidations) - m_client->didInvalidateRect(damagedRect); -} - -void WebViewImpl::scheduleCompositingLayerSync() -{ - m_layerTreeView->setNeedsRedraw(); -} - -void WebViewImpl::scrollRootLayerRect(const IntSize&, const IntRect&) -{ - updateLayerTreeViewport(); -} - -void WebViewImpl::invalidateRect(const IntRect& rect) -{ - if (m_layerTreeViewCommitsDeferred) { - // If we receive an invalidation from WebKit while in deferred commit mode, - // that means it's time to start producing frames again so un-defer. - m_layerTreeView->setDeferCommits(false); - m_layerTreeViewCommitsDeferred = false; - } - if (m_isAcceleratedCompositingActive) { - ASSERT(m_layerTreeView); - - if (!page()) - return; - - FrameView* view = page()->mainFrame()->view(); - IntRect dirtyRect = view->windowToContents(rect); - updateLayerTreeViewport(); - m_nonCompositedContentHost->invalidateRect(dirtyRect); - } else if (m_client) - m_client->didInvalidateRect(rect); -} - -NonCompositedContentHost* WebViewImpl::nonCompositedContentHost() -{ - return m_nonCompositedContentHost.get(); -} - -void WebViewImpl::setBackgroundColor(const WebCore::Color& color) -{ - WebCore::Color documentBackgroundColor = color.isValid() ? color : WebCore::Color::white; - WebColor webDocumentBackgroundColor = documentBackgroundColor.rgb(); - m_nonCompositedContentHost->setBackgroundColor(documentBackgroundColor); - m_layerTreeView->setBackgroundColor(webDocumentBackgroundColor); -} - -WebCore::GraphicsLayer* WebViewImpl::rootGraphicsLayer() -{ - return m_rootGraphicsLayer; -} - -#if ENABLE(REQUEST_ANIMATION_FRAME) -void WebViewImpl::scheduleAnimation() -{ - if (isAcceleratedCompositingActive()) { - if (Platform::current()->compositorSupport()->isThreadingEnabled()) { - ASSERT(m_layerTreeView); - m_layerTreeView->setNeedsAnimate(); - } else - m_client->scheduleAnimation(); - } else - m_client->scheduleAnimation(); -} -#endif - -void WebViewImpl::paintRootLayer(GraphicsContext& context, const IntRect& contentRect) -{ - double paintStart = currentTime(); - if (!page()) - return; - FrameView* view = page()->mainFrame()->view(); - if (context.platformContext()) - context.platformContext()->setDeviceScaleFactor(page()->deviceScaleFactor()); - view->paintContents(&context, contentRect); - double paintEnd = currentTime(); - double pixelsPerSec = (contentRect.width() * contentRect.height()) / (paintEnd - paintStart); - WebKit::Platform::current()->histogramCustomCounts("Renderer4.AccelRootPaintDurationMS", (paintEnd - paintStart) * 1000, 0, 120, 30); - WebKit::Platform::current()->histogramCustomCounts("Renderer4.AccelRootPaintMegapixPerSecond", pixelsPerSec / 1000000, 10, 210, 30); - - setBackgroundColor(view->documentBackgroundColor()); -} - -void WebViewImpl::setIsAcceleratedCompositingActive(bool active) -{ - WebKit::Platform::current()->histogramEnumeration("GPU.setIsAcceleratedCompositingActive", active * 2 + m_isAcceleratedCompositingActive, 4); - - if (m_isAcceleratedCompositingActive == active) - return; - - if (!active) { - m_isAcceleratedCompositingActive = false; - // We need to finish all GL rendering before sending didDeactivateCompositor() to prevent - // flickering when compositing turns off. This is only necessary if we're not in - // force-compositing-mode. - if (m_layerTreeView && !page()->settings()->forceCompositingMode()) - m_layerTreeView->finishAllRendering(); - m_client->didDeactivateCompositor(); - if (!m_layerTreeViewCommitsDeferred - && WebKit::Platform::current()->compositorSupport()->isThreadingEnabled()) { - ASSERT(m_layerTreeView); - // In threaded compositing mode, force compositing mode is always on so setIsAcceleratedCompositingActive(false) - // means that we're transitioning to a new page. Suppress commits until WebKit generates invalidations so - // we don't attempt to paint too early in the next page load. - m_layerTreeView->setDeferCommits(true); - m_layerTreeViewCommitsDeferred = true; - } - } else if (m_layerTreeView) { - m_isAcceleratedCompositingActive = true; - updateLayerTreeViewport(); - - m_client->didActivateCompositor(m_inputHandlerIdentifier); - } else { - TRACE_EVENT0("webkit", "WebViewImpl::setIsAcceleratedCompositingActive(true)"); - - WebLayerTreeView::Settings layerTreeViewSettings; - layerTreeViewSettings.acceleratePainting = page()->settings()->acceleratedDrawingEnabled(); - layerTreeViewSettings.showDebugBorders = page()->settings()->showDebugBorders(); - layerTreeViewSettings.showFPSCounter = settingsImpl()->showFPSCounter(); - layerTreeViewSettings.showPlatformLayerTree = settingsImpl()->showPlatformLayerTree(); - layerTreeViewSettings.showPaintRects = settingsImpl()->showPaintRects(); - layerTreeViewSettings.renderVSyncEnabled = settingsImpl()->renderVSyncEnabled(); - layerTreeViewSettings.perTilePaintingEnabled = settingsImpl()->perTilePaintingEnabled(); - layerTreeViewSettings.acceleratedAnimationEnabled = settingsImpl()->acceleratedAnimationEnabled(); - layerTreeViewSettings.pageScalePinchZoomEnabled = settingsImpl()->applyPageScaleFactorInCompositor(); - - layerTreeViewSettings.defaultTileSize = settingsImpl()->defaultTileSize(); - layerTreeViewSettings.maxUntiledLayerSize = settingsImpl()->maxUntiledLayerSize(); - - m_nonCompositedContentHost = NonCompositedContentHost::create(this); - m_nonCompositedContentHost->setShowDebugBorders(page()->settings()->showDebugBorders()); - m_nonCompositedContentHost->setOpaque(!isTransparent()); - - m_layerTreeView = adoptPtr(Platform::current()->compositorSupport()->createLayerTreeView(this, *m_rootLayer, layerTreeViewSettings)); - if (m_layerTreeView) { - if (m_webSettings->applyDeviceScaleFactorInCompositor() && page()->deviceScaleFactor() != 1) { - ASSERT(page()->deviceScaleFactor()); - - m_deviceScaleInCompositor = page()->deviceScaleFactor(); - setDeviceScaleFactor(m_deviceScaleInCompositor); - } - - bool visible = page()->visibilityState() == PageVisibilityStateVisible; - m_layerTreeView->setVisible(visible); - m_layerTreeView->setPageScaleFactorAndLimits(pageScaleFactor(), m_minimumPageScaleFactor, m_maximumPageScaleFactor); - if (m_compositorSurfaceReady) - m_layerTreeView->setSurfaceReady(); - m_layerTreeView->setHasTransparentBackground(isTransparent()); - updateLayerTreeViewport(); - m_client->didActivateCompositor(m_inputHandlerIdentifier); - m_isAcceleratedCompositingActive = true; - m_compositorCreationFailed = false; - m_isFontAtlasLoaded = false; - if (m_pageOverlays) - m_pageOverlays->update(); - - if (layerTreeViewSettings.showPlatformLayerTree) - loadFontAtlasIfNecessary(); - - if (settingsImpl()->showFPSCounter()) - setShowFPSCounter(true); - } else { - m_nonCompositedContentHost.clear(); - m_isAcceleratedCompositingActive = false; - m_client->didDeactivateCompositor(); - m_compositorCreationFailed = true; - } - } - if (page()) - page()->mainFrame()->view()->setClipsRepaints(!m_isAcceleratedCompositingActive); -} - -void WebViewImpl::loadFontAtlasIfNecessary() -{ - ASSERT(m_layerTreeView); - - if (m_isFontAtlasLoaded) - return; - - TRACE_EVENT0("webkit", "WebViewImpl::loadFontAtlas"); - WebRect asciiToRectTable[128]; - int fontHeight; - SkBitmap bitmap = WebCore::CompositorHUDFontAtlas::generateFontAtlas(asciiToRectTable, fontHeight); - m_layerTreeView->setFontAtlas(asciiToRectTable, bitmap, fontHeight); - m_isFontAtlasLoaded = true; -} - -#endif - -namespace { - -// Adapts a pure WebGraphicsContext3D into a WebCompositorOutputSurface until -// downstream code can be updated to produce output surfaces directly. -class WebGraphicsContextToOutputSurfaceAdapter : public WebCompositorOutputSurface { -public: - explicit WebGraphicsContextToOutputSurfaceAdapter(PassOwnPtr<WebGraphicsContext3D> context) - : m_context3D(context) - , m_client(0) - { - } - - virtual bool bindToClient(WebCompositorOutputSurfaceClient* client) OVERRIDE - { - ASSERT(client); - if (!m_context3D->makeContextCurrent()) - return false; - m_client = client; - return true; - } - - virtual const Capabilities& capabilities() const OVERRIDE - { - return m_capabilities; - } - - virtual WebGraphicsContext3D* context3D() const OVERRIDE - { - return m_context3D.get(); - } - - virtual void sendFrameToParentCompositor(const WebCompositorFrame&) OVERRIDE - { - } - -private: - OwnPtr<WebGraphicsContext3D> m_context3D; - Capabilities m_capabilities; - WebCompositorOutputSurfaceClient* m_client; -}; - -} // namespace - -WebCompositorOutputSurface* WebViewImpl::createOutputSurface() -{ - return m_client->createOutputSurface(); -} - -WebInputHandler* WebViewImpl::createInputHandler() -{ - WebCompositorInputHandlerImpl* handler = new WebCompositorInputHandlerImpl(); - m_inputHandlerIdentifier = handler->identifier(); - return handler; -} - -void WebViewImpl::applyScrollAndScale(const WebSize& scrollDelta, float pageScaleDelta) -{ - if (!mainFrameImpl() || !mainFrameImpl()->frameView()) - return; - - if (pageScaleDelta == 1) { - TRACE_EVENT_INSTANT2("webkit", "WebViewImpl::applyScrollAndScale::scrollBy", "x", scrollDelta.width, "y", scrollDelta.height); - mainFrameImpl()->frameView()->scrollBy(scrollDelta); - } else { - // The page scale changed, so apply a scale and scroll in a single - // operation. - WebSize scrollOffset = mainFrame()->scrollOffset(); - scrollOffset.width += scrollDelta.width; - scrollOffset.height += scrollDelta.height; - - WebPoint scrollPoint(scrollOffset.width, scrollOffset.height); - if (!m_page->settings()->applyPageScaleFactorInCompositor()) { - // The old scroll offset (and passed-in delta) are in the old - // coordinate space, so we first need to multiply them by the page - // scale delta. - scrollPoint.x = scrollPoint.x * pageScaleDelta; - scrollPoint.y = scrollPoint.y * pageScaleDelta; - } - - setPageScaleFactor(pageScaleFactor() * pageScaleDelta, scrollPoint); - m_doubleTapZoomInEffect = false; - } -} - -void WebViewImpl::willCommit() -{ - InspectorInstrumentation::willComposite(m_page.get()); -} - -void WebViewImpl::didCommit() -{ - if (m_client) - m_client->didBecomeReadyForAdditionalInput(); -} - -void WebViewImpl::didCommitAndDrawFrame() -{ - if (m_client) - m_client->didCommitAndDrawCompositorFrame(); -} - -void WebViewImpl::didCompleteSwapBuffers() -{ - if (m_client) - m_client->didCompleteSwapBuffers(); -} - -void WebViewImpl::didRecreateOutputSurface(bool success) -{ - // Switch back to software rendering mode, if necessary - if (!success) { - ASSERT(m_isAcceleratedCompositingActive); - setIsAcceleratedCompositingActive(false); - m_compositorCreationFailed = true; - m_client->didInvalidateRect(IntRect(0, 0, m_size.width, m_size.height)); - - // Force a style recalc to remove all the composited layers. - m_page->mainFrame()->document()->scheduleForcedStyleRecalc(); - return; - } - - if (m_pageOverlays) - m_pageOverlays->update(); -} - -void WebViewImpl::scheduleComposite() -{ - if (m_suppressInvalidations) { - TRACE_EVENT_INSTANT0("webkit", "WebViewImpl invalidations suppressed"); - return; - } - - ASSERT(!Platform::current()->compositorSupport()->isThreadingEnabled()); - m_client->scheduleComposite(); -} - -void WebViewImpl::createFontAtlas(SkBitmap& bitmap, WebRect asciiToRectTable[128], int& fontHeight) -{ - TRACE_EVENT0("webkit", "WebViewImpl::loadFontAtlas"); - bitmap = WebCore::CompositorHUDFontAtlas::generateFontAtlas(asciiToRectTable, fontHeight); -} - -void WebViewImpl::updateLayerTreeViewport() -{ - if (!page() || !m_nonCompositedContentHost || !m_layerTreeView) - return; - - FrameView* view = page()->mainFrame()->view(); - IntRect visibleRect = view->visibleContentRect(true /* include scrollbars */); - IntPoint scroll(view->scrollX(), view->scrollY()); - - m_nonCompositedContentHost->setViewport(visibleRect.size(), view->contentsSize(), scroll, view->scrollOrigin()); - - IntSize layoutViewportSize = size(); - IntSize deviceViewportSize = size(); - - // This part of the deviceScale will be used to scale the contents of - // the NCCH's GraphicsLayer. - deviceViewportSize.scale(m_deviceScaleInCompositor); - m_layerTreeView->setViewportSize(layoutViewportSize, deviceViewportSize); - m_layerTreeView->setPageScaleFactorAndLimits(pageScaleFactor(), m_minimumPageScaleFactor, m_maximumPageScaleFactor); -} - -WebGraphicsContext3D* WebViewImpl::sharedGraphicsContext3D() -{ - if (!m_page->settings()->acceleratedCompositingEnabled() || !allowsAcceleratedCompositing()) - return 0; - - return GraphicsContext3DPrivate::extractWebGraphicsContext3D(SharedGraphicsContext3D::get().get()); -} - -void WebViewImpl::selectAutofillSuggestionAtIndex(unsigned listIndex) -{ - if (m_autofillPopupClient && listIndex < m_autofillPopupClient->getSuggestionsCount()) - m_autofillPopupClient->valueChanged(listIndex); -} - -bool WebViewImpl::detectContentOnTouch(const WebPoint& position) -{ - HitTestResult touchHit = hitTestResultForWindowPos(position); - - if (touchHit.isContentEditable()) - return false; - - Node* node = touchHit.innerNode(); - if (!node || !node->isTextNode()) - return false; - - // Ignore when tapping on links or nodes listening to click events, unless the click event is on the - // body element, in which case it's unlikely that the original node itself was intended to be clickable. - for (; node && !node->hasTagName(HTMLNames::bodyTag); node = node->parentNode()) { - if (node->isLink() || node->willRespondToTouchEvents() || node->willRespondToMouseClickEvents()) - return false; - } - - WebContentDetectionResult content = m_client->detectContentAround(touchHit); - if (!content.isValid()) - return false; - - m_client->scheduleContentIntent(content.intent()); - return true; -} - -void WebViewImpl::setVisibilityState(WebPageVisibilityState visibilityState, - bool isInitialState) { - if (!page()) - return; - -#if ENABLE(PAGE_VISIBILITY_API) - ASSERT(visibilityState == WebPageVisibilityStateVisible - || visibilityState == WebPageVisibilityStateHidden - || visibilityState == WebPageVisibilityStatePrerender - || visibilityState == WebPageVisibilityStatePreview); - m_page->setVisibilityState(static_cast<PageVisibilityState>(static_cast<int>(visibilityState)), isInitialState); -#endif - -#if USE(ACCELERATED_COMPOSITING) - if (m_layerTreeView) { - bool visible = visibilityState == WebPageVisibilityStateVisible; - m_layerTreeView->setVisible(visible); - } -#endif -} - -#if ENABLE(POINTER_LOCK) -bool WebViewImpl::requestPointerLock() -{ - return m_client && m_client->requestPointerLock(); -} - -void WebViewImpl::requestPointerUnlock() -{ - if (m_client) - m_client->requestPointerUnlock(); -} - -bool WebViewImpl::isPointerLocked() -{ - return m_client && m_client->isPointerLocked(); -} - -void WebViewImpl::pointerLockMouseEvent(const WebInputEvent& event) -{ - AtomicString eventType; - switch (event.type) { - case WebInputEvent::MouseDown: - eventType = eventNames().mousedownEvent; - break; - case WebInputEvent::MouseUp: - eventType = eventNames().mouseupEvent; - break; - case WebInputEvent::MouseMove: - eventType = eventNames().mousemoveEvent; - break; - default: - ASSERT_NOT_REACHED(); - } - - const WebMouseEvent& mouseEvent = static_cast<const WebMouseEvent&>(event); - - if (page()) - page()->pointerLockController()->dispatchLockedMouseEvent( - PlatformMouseEventBuilder(mainFrameImpl()->frameView(), mouseEvent), - eventType); -} -#endif - -} // namespace WebKit |