diff options
Diffstat (limited to 'Source/WebKit/chromium/src/WebViewImpl.cpp')
-rw-r--r-- | Source/WebKit/chromium/src/WebViewImpl.cpp | 266 |
1 files changed, 217 insertions, 49 deletions
diff --git a/Source/WebKit/chromium/src/WebViewImpl.cpp b/Source/WebKit/chromium/src/WebViewImpl.cpp index a05e98920..55a2052a4 100644 --- a/Source/WebKit/chromium/src/WebViewImpl.cpp +++ b/Source/WebKit/chromium/src/WebViewImpl.cpp @@ -99,7 +99,6 @@ #include "RenderWidget.h" #include "ResourceHandle.h" #include "SchemeRegistry.h" -#include "ScrollAnimator.h" #include "SecurityOrigin.h" #include "SecurityPolicy.h" #include "Settings.h" @@ -171,7 +170,7 @@ using namespace std; namespace { -GraphicsContext3D::Attributes getCompositorContextAttributes() +WebKit::WebGraphicsContext3D::Attributes getCompositorContextAttributes(bool threaded) { // Explicitly disable antialiasing for the compositor. As of the time of // this writing, the only platform that supported antialiasing for the @@ -183,12 +182,21 @@ GraphicsContext3D::Attributes getCompositorContextAttributes() // be optimized to resolve directly into the IOSurface shared between the // GPU and browser processes. For these reasons and to avoid platform // disparities we explicitly disable antialiasing. - GraphicsContext3D::Attributes attributes; + WebKit::WebGraphicsContext3D::Attributes attributes; attributes.antialias = false; attributes.shareResources = true; + attributes.forUseOnAnotherThread = threaded; return attributes; } +// 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 float minScaleDifference = 0.01; +static const float doubleTapZoomContentDefaultMargin = 5; +static const float doubleTapZoomContentMinimumMargin = 2; + } // anonymous namespace namespace WebKit { @@ -390,21 +398,21 @@ WebViewImpl::WebViewImpl(WebViewClient* client) pageClients.editorClient = &m_editorClientImpl; pageClients.dragClient = &m_dragClientImpl; pageClients.inspectorClient = &m_inspectorClientImpl; -#if ENABLE(INPUT_SPEECH) - pageClients.speechInputClient = m_speechInputClient.get(); -#endif - pageClients.deviceOrientationClient = m_deviceOrientationClientProxy.get(); pageClients.geolocationClient = m_geolocationClientProxy.get(); -#if ENABLE(NOTIFICATIONS) - pageClients.notificationClient = notificationPresenterImpl(); -#endif pageClients.backForwardClient = BackForwardListChromium::create(this); -#if ENABLE(MEDIA_STREAM) - pageClients.userMediaClient = &m_userMediaClientImpl; -#endif 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(NOTIFICATIONS) + provideNotification(m_page.get(), notificationPresenterImpl()); +#endif + provideDeviceOrientationTo(m_page.get(), m_deviceOrientationClientProxy.get()); m_geolocationClientProxy->setController(m_page->geolocationController()); m_page->setGroupName(pageGroupName); @@ -614,14 +622,13 @@ bool WebViewImpl::mouseWheel(const WebMouseWheelEvent& event) bool WebViewImpl::gestureEvent(const WebGestureEvent& event) { PlatformGestureEventBuilder platformEvent(mainFrameImpl()->frameView(), event); - bool handled = mainFrameImpl()->frame()->eventHandler()->handleGestureEvent(platformEvent); - - Frame* frame = mainFrameImpl()->frame(); - WebPluginContainerImpl* pluginContainer = WebFrameImpl::pluginContainerFromFrame(frame); - if (pluginContainer) - handled |= pluginContainer->handleGestureEvent(platformEvent); + return mainFrameImpl()->frame()->eventHandler()->handleGestureEvent(platformEvent); +} - return handled; +void WebViewImpl::startPageScaleAnimation(const IntPoint& scroll, bool useAnchor, float newScale, double durationSec) +{ + if (m_layerTreeHost) + m_layerTreeHost->startPageScaleAnimation(IntSize(scroll.x(), scroll.y()), useAnchor, newScale, durationSec); } #endif @@ -797,15 +804,159 @@ bool WebViewImpl::touchEvent(const WebTouchEvent& event) } #endif +#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::getRect(); + 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::computeScaleAndScrollForHitRect(const WebRect& hitRect, AutoZoomType zoomType, float& scale, WebPoint& scroll) +{ + scale = pageScaleFactor(); + scroll.x = scroll.y = 0; + WebRect targetRect = hitRect; + if (targetRect.isEmpty()) + targetRect.width = targetRect.height = touchPointPadding; + + WebRect rect = computeBlockBounds(targetRect, zoomType); + + const float overviewScale = m_minimumPageScaleFactor; + 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 maxScale = deviceScaleFactor(); + + 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, maxScale); + scale = clampPageScaleFactorToLimits(scale); + + scaleUnchanged = fabs(pageScaleFactor() - scale) < minScaleDifference; + } + + if (zoomType == DoubleTap) { + if (rect.isEmpty() || scaleUnchanged) { + // Zoom out to overview mode. + if (overviewScale) + scale = overviewScale; + return; + } + } else if (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; + } + + // 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 + touchPointPadding - 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 + touchPointPadding - screenWidth); + + scroll.x = rect.x; + scroll.y = rect.y; +} +#endif + void WebViewImpl::numberOfWheelEventHandlersChanged(unsigned numberOfWheelHandlers) { - m_haveWheelEventHandlers = numberOfWheelHandlers > 0; if (m_client) m_client->numberOfWheelEventHandlersChanged(numberOfWheelHandlers); -#if USE(ACCELERATED_COMPOSITING) - if (m_layerTreeHost) - m_layerTreeHost->setHaveWheelEventHandlers(m_haveWheelEventHandlers); -#endif +} + +void WebViewImpl::numberOfTouchEventHandlersChanged(unsigned numberOfTouchHandlers) +{ + if (m_client) + m_client->numberOfTouchEventHandlersChanged(numberOfTouchHandlers); } #if !OS(DARWIN) @@ -1257,6 +1408,14 @@ void WebViewImpl::composite(bool) #endif } +void WebViewImpl::setNeedsRedraw() +{ +#if USE(ACCELERATED_COMPOSITING) + if (m_layerTreeHost && isAcceleratedCompositingActive()) + m_layerTreeHost->setNeedsRedraw(); +#endif +} + void WebViewImpl::loseCompositorContext(int numTimes) { #if USE(ACCELERATED_COMPOSITING) @@ -2140,12 +2299,12 @@ bool WebViewImpl::computePageScaleFactorLimits() m_maximumPageScaleFactor = max(m_minimumPageScaleFactor, m_maximumPageScaleFactor); } ASSERT(m_minimumPageScaleFactor <= m_maximumPageScaleFactor); + + float clampedScale = clampPageScaleFactorToLimits(pageScaleFactor()); #if USE(ACCELERATED_COMPOSITING) if (m_layerTreeHost) - m_layerTreeHost->setPageScaleFactorLimits(m_minimumPageScaleFactor, m_maximumPageScaleFactor); + m_layerTreeHost->setPageScaleFactorAndLimits(clampedScale, m_minimumPageScaleFactor, m_maximumPageScaleFactor); #endif - - float clampedScale = clampPageScaleFactorToLimits(pageScaleFactor()); if (clampedScale != pageScaleFactor()) { setPageScaleFactorPreservingScrollOffset(clampedScale); return true; @@ -3005,6 +3164,7 @@ void WebViewImpl::setIsAcceleratedCompositingActive(bool active) ccSettings.perTilePainting = page()->settings()->perTileDrawingEnabled(); ccSettings.partialSwapEnabled = page()->settings()->partialSwapEnabled(); + ccSettings.threadedAnimationEnabled = page()->settings()->threadedAnimationEnabled(); m_nonCompositedContentHost = NonCompositedContentHost::create(WebViewImplContentPainter::create(this)); m_nonCompositedContentHost->setShowDebugBorders(page()->settings()->showDebugBorders()); @@ -3014,8 +3174,7 @@ void WebViewImpl::setIsAcceleratedCompositingActive(bool active) m_layerTreeHost = CCLayerTreeHost::create(this, ccSettings); if (m_layerTreeHost) { - m_layerTreeHost->setHaveWheelEventHandlers(m_haveWheelEventHandlers); - m_layerTreeHost->setPageScaleFactorLimits(m_minimumPageScaleFactor, m_maximumPageScaleFactor); + m_layerTreeHost->setPageScaleFactorAndLimits(pageScaleFactor(), m_minimumPageScaleFactor, m_maximumPageScaleFactor); updateLayerTreeViewport(); m_client->didActivateCompositor(m_layerTreeHost->compositorIdentifier()); m_isAcceleratedCompositingActive = true; @@ -3036,15 +3195,25 @@ void WebViewImpl::setIsAcceleratedCompositingActive(bool active) #endif +PassRefPtr<GraphicsContext3D> WebViewImpl::createCompositorGraphicsContext3D() +{ + WebKit::WebGraphicsContext3D::Attributes attributes = getCompositorContextAttributes(CCProxy::hasImplThread()); + OwnPtr<WebGraphicsContext3D> webContext = adoptPtr(client()->createGraphicsContext3D(attributes, true /* renderDirectlyToHostWindow */)); + if (!webContext) + return 0; + + return GraphicsContext3DPrivate::createGraphicsContextFromWebContext(webContext.release(), GraphicsContext3D::RenderDirectlyToHostWindow); +} + PassRefPtr<GraphicsContext3D> WebViewImpl::createLayerTreeHostContext3D() { - RefPtr<GraphicsContext3D> context = m_temporaryOnscreenGraphicsContext3D.release(); - if (!context) { - if (CCProxy::hasImplThread()) - context = GraphicsContext3DPrivate::createGraphicsContextForAnotherThread(getCompositorContextAttributes(), m_page->chrome(), GraphicsContext3D::RenderDirectlyToHostWindow); - else - context = GraphicsContext3D::create(getCompositorContextAttributes(), m_page->chrome(), GraphicsContext3D::RenderDirectlyToHostWindow); - } + RefPtr<GraphicsContext3D> context; + + // If we've already created an onscreen context for this view, return that. + if (m_temporaryOnscreenGraphicsContext3D) + context = m_temporaryOnscreenGraphicsContext3D.release(); + else // Otherwise make a new one. + context = createCompositorGraphicsContext3D(); return context; } @@ -3125,7 +3294,7 @@ void WebViewImpl::updateLayerTreeViewport() } m_nonCompositedContentHost->setViewport(visibleRect.size(), view->contentsSize(), scroll, pageScaleFactor(), layerAdjustX); m_layerTreeHost->setViewportSize(visibleRect.size()); - m_layerTreeHost->setPageScale(pageScaleFactor()); + m_layerTreeHost->setPageScaleFactorAndLimits(pageScaleFactor(), m_minimumPageScaleFactor, m_maximumPageScaleFactor); } WebGraphicsContext3D* WebViewImpl::graphicsContext3D() @@ -3137,17 +3306,16 @@ WebGraphicsContext3D* WebViewImpl::graphicsContext3D() if (webContext && !webContext->isContextLost()) return webContext; } - if (m_temporaryOnscreenGraphicsContext3D) { - WebGraphicsContext3D* webContext = GraphicsContext3DPrivate::extractWebGraphicsContext3D(m_temporaryOnscreenGraphicsContext3D.get()); - if (webContext && !webContext->isContextLost()) - return webContext; - } - if (CCProxy::hasImplThread()) - m_temporaryOnscreenGraphicsContext3D = GraphicsContext3DPrivate::createGraphicsContextForAnotherThread(getCompositorContextAttributes(), m_page->chrome(), GraphicsContext3D::RenderDirectlyToHostWindow); - else - m_temporaryOnscreenGraphicsContext3D = GraphicsContext3D::create(getCompositorContextAttributes(), m_page->chrome(), GraphicsContext3D::RenderDirectlyToHostWindow); - - return GraphicsContext3DPrivate::extractWebGraphicsContext3D(m_temporaryOnscreenGraphicsContext3D.get()); + // If we get here it means that some system needs access to the context the compositor will use but the compositor itself + // hasn't requested a context or it was unable to successfully instantiate a context. + // We need to return the context that the compositor will later use so we allocate a new context (if needed) and stash it + // until the compositor requests and takes ownership of the context via createLayerTreeHost3D(). + if (!m_temporaryOnscreenGraphicsContext3D) + m_temporaryOnscreenGraphicsContext3D = createCompositorGraphicsContext3D(); + + WebGraphicsContext3D* webContext = GraphicsContext3DPrivate::extractWebGraphicsContext3D(m_temporaryOnscreenGraphicsContext3D.get()); + if (webContext && !webContext->isContextLost()) + return webContext; } #endif return 0; |