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/WebCore/rendering/RenderLayerBacking.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/WebCore/rendering/RenderLayerBacking.cpp')
| -rw-r--r-- | Source/WebCore/rendering/RenderLayerBacking.cpp | 1070 |
1 files changed, 725 insertions, 345 deletions
diff --git a/Source/WebCore/rendering/RenderLayerBacking.cpp b/Source/WebCore/rendering/RenderLayerBacking.cpp index 88be08dfe..955315eef 100644 --- a/Source/WebCore/rendering/RenderLayerBacking.cpp +++ b/Source/WebCore/rendering/RenderLayerBacking.cpp @@ -32,6 +32,7 @@ #include "AnimationController.h" #include "CanvasRenderingContext.h" #include "CSSPropertyNames.h" +#include "CachedImage.h" #include "Chrome.h" #include "FontCache.h" #include "FrameView.h" @@ -41,9 +42,11 @@ #include "HTMLIFrameElement.h" #include "HTMLMediaElement.h" #include "HTMLNames.h" +#include "HTMLPlugInElement.h" #include "InspectorInstrumentation.h" #include "KeyframeList.h" #include "PluginViewBase.h" +#include "ProgressTracker.h" #include "RenderApplet.h" #include "RenderIFrame.h" #include "RenderImage.h" @@ -55,7 +58,6 @@ #include "Settings.h" #include "StyleResolver.h" #include "TiledBacking.h" -#include <wtf/CurrentTime.h> #include <wtf/text/StringBuilder.h> #if ENABLE(CSS_FILTERS) @@ -75,8 +77,6 @@ namespace WebCore { using namespace HTMLNames; -static bool hasBoxDecorations(const RenderStyle*); -static bool hasBoxDecorationsOrBackground(const RenderObject*); static bool hasBoxDecorationsOrBackgroundImage(const RenderStyle*); static IntRect clipBox(RenderBox* renderer); @@ -94,18 +94,31 @@ static inline bool isAcceleratedCanvas(RenderObject* renderer) return false; } +// Get the scrolling coordinator in a way that works inside RenderLayerBacking's destructor. +static ScrollingCoordinator* scrollingCoordinatorFromLayer(RenderLayer* layer) +{ + Page* page = layer->renderer()->frame()->page(); + if (!page) + return 0; + + return page->scrollingCoordinator(); +} + bool RenderLayerBacking::m_creatingPrimaryGraphicsLayer = false; RenderLayerBacking::RenderLayerBacking(RenderLayer* layer) : m_owningLayer(layer) , m_scrollLayerID(0) , m_artificiallyInflatedBounds(false) + , m_boundsConstrainedByClipping(false) , m_isMainFrameRenderViewLayer(false) , m_usingTiledCacheLayer(false) , m_requiresOwnBackingStore(true) #if ENABLE(CSS_FILTERS) , m_canCompositeFilters(false) #endif + , m_backgroundLayerPaintsFixedRootBackground(false) + , m_didSwitchToFullTileCoverageDuringLoading(false) { if (layer->isRootLayer()) { Frame* frame = toRenderView(renderer())->frameView()->frame(); @@ -127,9 +140,13 @@ RenderLayerBacking::RenderLayerBacking(RenderLayer* layer) TiledBacking* tiledBacking = this->tiledBacking(); if (Page* page = renderer()->frame()->page()) { Frame* frame = renderer()->frame(); - tiledBacking->setIsInWindow(page->isOnscreen()); + tiledBacking->setIsInWindow(page->isInWindow()); + + if (m_isMainFrameRenderViewLayer) + tiledBacking->setUnparentsOffscreenTiles(true); + tiledBacking->setScrollingPerformanceLoggingEnabled(frame->settings() && frame->settings()->scrollingPerformanceLoggingEnabled()); - adjustTileCacheCoverage(); + adjustTiledBackingCoverage(); } } } @@ -139,17 +156,26 @@ RenderLayerBacking::~RenderLayerBacking() updateClippingLayers(false, false); updateOverflowControlsLayers(false, false, false); updateForegroundLayer(false); + updateBackgroundLayer(false); updateMaskLayer(false); updateScrollingLayers(false); detachFromScrollingCoordinator(); destroyGraphicsLayers(); } +void RenderLayerBacking::willDestroyLayer(const GraphicsLayer* layer) +{ + if (layer && layer->usingTiledBacking()) { + if (RenderLayerCompositor* compositor = this->compositor()) + compositor->layerTiledBackingUsageChanged(layer, false); + } +} + PassOwnPtr<GraphicsLayer> RenderLayerBacking::createGraphicsLayer(const String& name) { GraphicsLayerFactory* graphicsLayerFactory = 0; if (Page* page = renderer()->frame()->page()) - graphicsLayerFactory = page->chrome()->client()->graphicsLayerFactory(); + graphicsLayerFactory = page->chrome().client()->graphicsLayerFactory(); OwnPtr<GraphicsLayer> graphicsLayer = GraphicsLayer::create(graphicsLayerFactory, this); @@ -167,39 +193,61 @@ PassOwnPtr<GraphicsLayer> RenderLayerBacking::createGraphicsLayer(const String& return graphicsLayer.release(); } -bool RenderLayerBacking::shouldUseTileCache(const GraphicsLayer*) const +bool RenderLayerBacking::shouldUseTiledBacking(const GraphicsLayer*) const { return m_usingTiledCacheLayer && m_creatingPrimaryGraphicsLayer; } +void RenderLayerBacking::tiledBackingUsageChanged(const GraphicsLayer* layer, bool usingTiledBacking) +{ + compositor()->layerTiledBackingUsageChanged(layer, usingTiledBacking); +} + TiledBacking* RenderLayerBacking::tiledBacking() const { return m_graphicsLayer->tiledBacking(); } -void RenderLayerBacking::adjustTileCacheCoverage() +static TiledBacking::TileCoverage computeTileCoverage(RenderLayerBacking* backing) { - if (!m_usingTiledCacheLayer) - return; + // FIXME: When we use TiledBacking for overflow, this should look at RenderView scrollability. + Frame* frame = backing->owningLayer()->renderer()->frame(); + if (!frame) + return TiledBacking::CoverageForVisibleArea; TiledBacking::TileCoverage tileCoverage = TiledBacking::CoverageForVisibleArea; - - // FIXME: When we use TiledBacking for overflow, this should look at RenderView scrollability. - Frame* frame = renderer()->frame(); - if (frame) { - FrameView* frameView = frame->view(); - if (frameView->horizontalScrollbarMode() != ScrollbarAlwaysOff) + FrameView* frameView = frame->view(); + bool useMinimalTilesDuringLiveResize = frameView->inLiveResize(); + bool useMinimalTilesDuringLoading = false; + // Avoid churn. + if (!backing->didSwitchToFullTileCoverageDuringLoading()) { + useMinimalTilesDuringLoading = !frameView->isVisuallyNonEmpty() || (frame->page()->progress()->isMainLoadProgressing() && !frameView->wasScrolledByUser()); + if (!useMinimalTilesDuringLoading) + backing->setDidSwitchToFullTileCoverageDuringLoading(); + } + if (!(useMinimalTilesDuringLoading || useMinimalTilesDuringLiveResize)) { + bool clipsToExposedRect = backing->tiledBacking()->clipsToExposedRect(); + if (frameView->horizontalScrollbarMode() != ScrollbarAlwaysOff || clipsToExposedRect) tileCoverage |= TiledBacking::CoverageForHorizontalScrolling; - if (frameView->verticalScrollbarMode() != ScrollbarAlwaysOff) + if (frameView->verticalScrollbarMode() != ScrollbarAlwaysOff || clipsToExposedRect) tileCoverage |= TiledBacking::CoverageForVerticalScrolling; - - if (ScrollingCoordinator* scrollingCoordinator = frame->page()->scrollingCoordinator()) { - if (scrollingCoordinator->shouldUpdateScrollLayerPositionOnMainThread()) - tileCoverage |= TiledBacking::CoverageForSlowScrolling; - } } + if (ScrollingCoordinator* scrollingCoordinator = scrollingCoordinatorFromLayer(backing->owningLayer())) { + // Ask our TiledBacking for large tiles unless the only reason we're main-thread-scrolling + // is a page overlay (find-in-page, the Web Inspector highlight mechanism, etc.). + if (scrollingCoordinator->mainThreadScrollingReasons() & ~ScrollingCoordinator::ForcedOnMainThread) + tileCoverage |= TiledBacking::CoverageForSlowScrolling; + } + return tileCoverage; +} + +void RenderLayerBacking::adjustTiledBackingCoverage() +{ + if (!m_usingTiledCacheLayer) + return; + TiledBacking::TileCoverage tileCoverage = computeTileCoverage(this); tiledBacking()->setTileCoverage(tileCoverage); } @@ -215,6 +263,14 @@ void RenderLayerBacking::updateDebugIndicators(bool showBorder, bool showRepaint m_foregroundLayer->setShowDebugBorder(showBorder); m_foregroundLayer->setShowRepaintCounter(showRepaintCounter); } + + if (m_contentsContainmentLayer) + m_contentsContainmentLayer->setShowDebugBorder(showBorder); + + if (m_backgroundLayer) { + m_backgroundLayer->setShowDebugBorder(showBorder); + m_backgroundLayer->setShowRepaintCounter(showRepaintCounter); + } if (m_maskLayer) { m_maskLayer->setShowDebugBorder(showBorder); @@ -243,11 +299,11 @@ void RenderLayerBacking::createPrimaryGraphicsLayer() { String layerName; #ifndef NDEBUG - layerName = nameForLayer(); + layerName = m_owningLayer->name(); #endif // The call to createGraphicsLayer ends calling back into here as - // a GraphicsLayerClient to ask if it shouldUseTileCache(). We only want + // a GraphicsLayerClient to ask if it shouldUseTiledBacking(). We only want // the tile cache on our main layer. This is pretty ugly, but saves us from // exposing the API to all clients. @@ -256,14 +312,10 @@ void RenderLayerBacking::createPrimaryGraphicsLayer() m_creatingPrimaryGraphicsLayer = false; if (m_usingTiledCacheLayer) - m_containmentLayer = createGraphicsLayer("TileCache Flattening Layer"); + m_childContainmentLayer = createGraphicsLayer("TiledBacking Flattening Layer"); if (m_isMainFrameRenderViewLayer) { - bool isTransparent = false; - if (FrameView* frameView = toRenderView(renderer())->frameView()) - isTransparent = frameView->isTransparent(); - - m_graphicsLayer->setContentsOpaque(!isTransparent); + m_graphicsLayer->setContentsOpaque(true); m_graphicsLayer->setAppliesPageScale(); } @@ -287,12 +339,17 @@ void RenderLayerBacking::createPrimaryGraphicsLayer() void RenderLayerBacking::destroyGraphicsLayers() { - if (m_graphicsLayer) + if (m_graphicsLayer) { + willDestroyLayer(m_graphicsLayer.get()); m_graphicsLayer->removeFromParent(); + } + m_ancestorClippingLayer = nullptr; + m_contentsContainmentLayer = nullptr; m_graphicsLayer = nullptr; m_foregroundLayer = nullptr; - m_containmentLayer = nullptr; + m_backgroundLayer = nullptr; + m_childContainmentLayer = nullptr; m_maskLayer = nullptr; m_scrollingLayer = nullptr; @@ -314,7 +371,11 @@ void RenderLayerBacking::updateTransform(const RenderStyle* style) makeMatrixRenderable(t, compositor()->canRender3DTransforms()); } - m_graphicsLayer->setTransform(t); + if (m_contentsContainmentLayer) { + m_contentsContainmentLayer->setTransform(t); + m_graphicsLayer->setTransform(TransformationMatrix()); + } else + m_graphicsLayer->setTransform(t); } #if ENABLE(CSS_FILTERS) @@ -340,7 +401,7 @@ static bool hasNonZeroTransformOrigin(const RenderObject* renderer) static bool layerOrAncestorIsTransformedOrUsingCompositedScrolling(RenderLayer* layer) { for (RenderLayer* curr = layer; curr; curr = curr->parent()) { - if (curr->hasTransform() || curr->usesCompositedScrolling()) + if (curr->hasTransform() || curr->needsCompositedScrolling()) return true; } @@ -354,9 +415,6 @@ bool RenderLayerBacking::shouldClipCompositedBounds() const return false; if (m_usingTiledCacheLayer) - return true; - - if (!compositor()->compositingConsultsOverlap()) return false; if (layerOrAncestorIsTransformedOrUsingCompositedScrolling(m_owningLayer)) @@ -365,10 +423,9 @@ bool RenderLayerBacking::shouldClipCompositedBounds() const return true; } - void RenderLayerBacking::updateCompositedBounds() { - IntRect layerBounds = compositor()->calculateCompositedBounds(m_owningLayer, m_owningLayer); + LayoutRect layerBounds = compositor()->calculateCompositedBounds(m_owningLayer, m_owningLayer); // Clip to the size of the document or enclosing overflow-scroll layer. // If this or an ancestor is transformed, we can't currently compute the correct rect to intersect with. @@ -377,18 +434,23 @@ void RenderLayerBacking::updateCompositedBounds() RenderView* view = m_owningLayer->renderer()->view(); RenderLayer* rootLayer = view->layer(); - // Start by clipping to the view's bounds. - LayoutRect clippingBounds = view->unscaledDocumentRect(); + LayoutRect clippingBounds; + if (renderer()->style()->position() == FixedPosition && renderer()->container() == view) + clippingBounds = view->frameView()->viewportConstrainedVisibleContentRect(); + else + clippingBounds = view->unscaledDocumentRect(); if (m_owningLayer != rootLayer) clippingBounds.intersect(m_owningLayer->backgroundClipRect(RenderLayer::ClipRectsContext(rootLayer, 0, AbsoluteClipRects)).rect()); // FIXME: Incorrect for CSS regions. LayoutPoint delta; - m_owningLayer->convertToLayerCoords(rootLayer, delta); + m_owningLayer->convertToLayerCoords(rootLayer, delta, RenderLayer::AdjustForColumns); clippingBounds.move(-delta.x(), -delta.y()); - layerBounds.intersect(pixelSnappedIntRect(clippingBounds)); - } + layerBounds.intersect(clippingBounds); + m_boundsConstrainedByClipping = true; + } else + m_boundsConstrainedByClipping = false; // If the element has a transform-origin that has fixed lengths, and the renderer has zero size, // then we need to ensure that the compositing layer has non-zero size so that we can apply @@ -408,12 +470,12 @@ void RenderLayerBacking::updateAfterWidgetResize() if (renderer()->isRenderPart()) { if (RenderLayerCompositor* innerCompositor = RenderLayerCompositor::frameContentsCompositor(toRenderPart(renderer()))) { innerCompositor->frameViewDidChangeSize(); - innerCompositor->frameViewDidChangeLocation(contentsBox().location()); + innerCompositor->frameViewDidChangeLocation(flooredIntPoint(contentsBox().location())); } } } -void RenderLayerBacking::updateAfterLayout(UpdateDepth updateDepth, bool isUpdateRoot) +void RenderLayerBacking::updateAfterLayout(UpdateAfterLayoutFlags flags) { RenderLayerCompositor* layerCompositor = compositor(); if (!layerCompositor->compositingLayersNeedRebuild()) { @@ -425,13 +487,19 @@ void RenderLayerBacking::updateAfterLayout(UpdateDepth updateDepth, bool isUpdat // The solution is to update compositing children of this layer here, // via updateCompositingChildrenGeometry(). updateCompositedBounds(); - layerCompositor->updateCompositingDescendantGeometry(m_owningLayer, m_owningLayer, updateDepth); + layerCompositor->updateCompositingDescendantGeometry(m_owningLayer, m_owningLayer, flags & CompositingChildrenOnly); - if (isUpdateRoot) { + if (flags & IsUpdateRoot) { updateGraphicsLayerGeometry(); layerCompositor->updateRootLayerPosition(); + RenderLayer* stackingContainer = m_owningLayer->enclosingStackingContainer(); + if (!layerCompositor->compositingLayersNeedRebuild() && stackingContainer && (stackingContainer != m_owningLayer)) + layerCompositor->updateCompositingDescendantGeometry(stackingContainer, stackingContainer, flags & CompositingChildrenOnly); } } + + if (flags & NeedsFullRepaint && !paintsIntoWindow() && !paintsIntoCompositedAncestor()) + setContentsNeedDisplay(); } bool RenderLayerBacking::updateGraphicsLayerConfiguration() @@ -439,16 +507,23 @@ bool RenderLayerBacking::updateGraphicsLayerConfiguration() RenderLayerCompositor* compositor = this->compositor(); RenderObject* renderer = this->renderer(); + m_owningLayer->updateDescendantDependentFlags(); m_owningLayer->updateZOrderLists(); bool layerConfigChanged = false; + setBackgroundLayerPaintsFixedRootBackground(compositor->needsFixedRootBackgroundLayer(m_owningLayer)); + + // The background layer is currently only used for fixed root backgrounds. + if (updateBackgroundLayer(m_backgroundLayerPaintsFixedRootBackground)) + layerConfigChanged = true; + if (updateForegroundLayer(compositor->needsContentsCompositingLayer(m_owningLayer))) layerConfigChanged = true; bool needsDescendentsClippingLayer = compositor->clipsCompositingDescendants(m_owningLayer); // Our scrolling layer will clip. - if (m_owningLayer->usesCompositedScrolling()) + if (m_owningLayer->needsCompositedScrolling()) needsDescendentsClippingLayer = false; if (updateClippingLayers(compositor->clippedByAncestor(m_owningLayer), needsDescendentsClippingLayer)) @@ -457,7 +532,7 @@ bool RenderLayerBacking::updateGraphicsLayerConfiguration() if (updateOverflowControlsLayers(requiresHorizontalScrollbarLayer(), requiresVerticalScrollbarLayer(), requiresScrollCornerLayer())) layerConfigChanged = true; - if (updateScrollingLayers(m_owningLayer->usesCompositedScrolling())) + if (updateScrollingLayers(m_owningLayer->needsCompositedScrolling())) layerConfigChanged = true; if (layerConfigChanged) @@ -479,16 +554,23 @@ bool RenderLayerBacking::updateGraphicsLayerConfiguration() } else m_graphicsLayer->setReplicatedByLayer(0); + bool isSimpleContainer = isSimpleContainerCompositingLayer(); + bool didUpdateContentsRect = false; + updateDirectlyCompositedContents(isSimpleContainer, didUpdateContentsRect); + + updateRootLayerConfiguration(); + if (isDirectlyCompositedImage()) updateImageContents(); if (renderer->isEmbeddedObject() && toRenderEmbeddedObject(renderer)->allowsAcceleratedCompositing()) { - PluginViewBase* pluginViewBase = static_cast<PluginViewBase*>(toRenderWidget(renderer)->widget()); - m_graphicsLayer->setContentsToMedia(pluginViewBase->platformLayer()); + PluginViewBase* pluginViewBase = toPluginViewBase(toRenderWidget(renderer)->widget()); + if (!pluginViewBase->shouldNotAddLayer()) + m_graphicsLayer->setContentsToMedia(pluginViewBase->platformLayer()); } #if ENABLE(VIDEO) else if (renderer->isVideo()) { - HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(renderer->node()); + HTMLMediaElement* mediaElement = toHTMLMediaElement(renderer->node()); m_graphicsLayer->setContentsToMedia(mediaElement->platformLayer()); } #endif @@ -500,19 +582,6 @@ bool RenderLayerBacking::updateGraphicsLayerConfiguration() layerConfigChanged = true; } #endif -#if ENABLE(FULLSCREEN_API) - else if (renderer->isRenderFullScreen()) { - // RenderFullScreen renderers have no content, and only a solid - // background color. They also can be large enough to trigger the - // creation of a tiled-layer, which can cause flashing problems - // during repainting. Special case the RenderFullScreen case because - // we know its style does not come from CSS and it is therefore will - // not contain paintable content (e.g. background images, gradients, - // etc), so safe to set the layer's background color to the renderer's - // style's background color. - updateBackgroundColor(); - } -#endif if (renderer->isRenderPart()) layerConfigChanged = RenderLayerCompositor::parentFrameContentLayers(toRenderPart(renderer)); @@ -534,7 +603,7 @@ static IntRect clipBox(RenderBox* renderer) void RenderLayerBacking::updateGraphicsLayerGeometry() { // If we haven't built z-order lists yet, wait until later. - if (m_owningLayer->isStackingContext() && m_owningLayer->m_zOrderListsDirty) + if (m_owningLayer->isStackingContainer() && m_owningLayer->m_zOrderListsDirty) return; // Set transform property, if it is not animating. We have to do this here because the transform @@ -553,6 +622,8 @@ void RenderLayerBacking::updateGraphicsLayerGeometry() #if ENABLE(CSS_COMPOSITING) updateLayerBlendMode(renderer()->style()); #endif + + bool isSimpleContainer = isSimpleContainerCompositingLayer(); m_owningLayer->updateDescendantDependentFlags(); @@ -562,26 +633,11 @@ void RenderLayerBacking::updateGraphicsLayerGeometry() m_graphicsLayer->setContentsVisible(m_owningLayer->hasVisibleContent() || hasVisibleNonCompositingDescendantLayers()); RenderStyle* style = renderer()->style(); - m_graphicsLayer->setPreserves3D(style->transformStyle3D() == TransformStyle3DPreserve3D && !renderer()->hasReflection()); + // FIXME: reflections should force transform-style to be flat in the style: https://bugs.webkit.org/show_bug.cgi?id=106959 + bool preserves3D = style->transformStyle3D() == TransformStyle3DPreserve3D && !renderer()->hasReflection(); + m_graphicsLayer->setPreserves3D(preserves3D); m_graphicsLayer->setBackfaceVisibility(style->backfaceVisibility() == BackfaceVisibilityVisible); - // Register fixed position layers and their containers with the scrolling coordinator. - if (Page* page = renderer()->frame()->page()) { - if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator()) { - if (style->position() == FixedPosition || compositor()->fixedPositionedByAncestor(m_owningLayer)) - scrollingCoordinator->setLayerIsFixedToContainerLayer(childForSuperlayers(), true); - else { - if (m_ancestorClippingLayer) - scrollingCoordinator->setLayerIsFixedToContainerLayer(m_ancestorClippingLayer.get(), false); - scrollingCoordinator->setLayerIsFixedToContainerLayer(m_graphicsLayer.get(), false); - } - // Page scale is applied as a transform on the root render view layer. Because the scroll - // layer is further up in the hierarchy, we need to avoid marking the root render view - // layer as a container. - bool isContainer = m_owningLayer->hasTransform() && !m_owningLayer->isRootLayer(); - scrollingCoordinator->setLayerIsContainerForFixedPositionLayers(childForSuperlayers(), isContainer); - } - } RenderLayer* compAncestor = m_owningLayer->ancestorCompositingLayer(); // We compute everything relative to the enclosing compositing layer. @@ -591,11 +647,16 @@ void RenderLayerBacking::updateGraphicsLayerGeometry() ancestorCompositingBounds = pixelSnappedIntRect(compAncestor->backing()->compositedBounds()); } - IntRect localCompositingBounds = pixelSnappedIntRect(compositedBounds()); + LayoutRect localRawCompositingBounds = compositedBounds(); + LayoutPoint rawDelta; + m_owningLayer->convertToLayerCoords(compAncestor, rawDelta, RenderLayer::AdjustForColumns); + IntPoint delta = flooredIntPoint(rawDelta); + m_subpixelAccumulation = toLayoutSize(rawDelta.fraction()); + // Move the bounds by the subpixel accumulation so that it pixel-snaps relative to absolute pixels instead of local coordinates. + localRawCompositingBounds.move(m_subpixelAccumulation); + IntRect localCompositingBounds = pixelSnappedIntRect(localRawCompositingBounds); IntRect relativeCompositingBounds(localCompositingBounds); - IntPoint delta; - m_owningLayer->convertToPixelSnappedLayerCoords(compAncestor, delta); relativeCompositingBounds.moveBy(delta); IntPoint graphicsLayerParentLocation; @@ -609,7 +670,7 @@ void RenderLayerBacking::updateGraphicsLayerGeometry() else graphicsLayerParentLocation = renderer()->view()->documentRect().location(); - if (compAncestor && compAncestor->usesCompositedScrolling()) { + if (compAncestor && compAncestor->needsCompositedScrolling()) { RenderBox* renderBox = toRenderBox(compAncestor->renderer()); IntSize scrollOffset = compAncestor->scrolledContentOffset(); IntPoint scrollOrigin(renderBox->borderLeft(), renderBox->borderTop()); @@ -620,10 +681,10 @@ void RenderLayerBacking::updateGraphicsLayerGeometry() // Call calculateRects to get the backgroundRect which is what is used to clip the contents of this // layer. Note that we call it with temporaryClipRects = true because normally when computing clip rects // for a compositing layer, rootLayer is the layer itself. - RenderLayer::ClipRectsContext clipRectsContext(compAncestor, 0, TemporaryClipRects, IgnoreOverlayScrollbarSize, RenderLayer::IgnoreOverflowClip); + RenderLayer::ClipRectsContext clipRectsContext(compAncestor, 0, TemporaryClipRects, IgnoreOverlayScrollbarSize, IgnoreOverflowClip); IntRect parentClipRect = pixelSnappedIntRect(m_owningLayer->backgroundClipRect(clipRectsContext).rect()); // FIXME: Incorrect for CSS regions. ASSERT(parentClipRect != PaintInfo::infiniteRect()); - m_ancestorClippingLayer->setPosition(FloatPoint() + (parentClipRect.location() - graphicsLayerParentLocation)); + m_ancestorClippingLayer->setPosition(FloatPoint(parentClipRect.location() - graphicsLayerParentLocation)); m_ancestorClippingLayer->setSize(parentClipRect.size()); // backgroundRect is relative to compAncestor, so subtract deltaX/deltaY to get back to local coords. @@ -633,26 +694,41 @@ void RenderLayerBacking::updateGraphicsLayerGeometry() graphicsLayerParentLocation = parentClipRect.location(); } - m_graphicsLayer->setPosition(FloatPoint() + (relativeCompositingBounds.location() - graphicsLayerParentLocation)); - m_graphicsLayer->setOffsetFromRenderer(localCompositingBounds.location() - IntPoint()); + FloatSize contentsSize = relativeCompositingBounds.size(); + if (m_contentsContainmentLayer) { + m_contentsContainmentLayer->setPreserves3D(preserves3D); + m_contentsContainmentLayer->setPosition(FloatPoint(relativeCompositingBounds.location() - graphicsLayerParentLocation)); + // Use the same size as m_graphicsLayer so transforms behave correctly. + m_contentsContainmentLayer->setSize(contentsSize); + graphicsLayerParentLocation = relativeCompositingBounds.location(); + } + + m_graphicsLayer->setPosition(FloatPoint(relativeCompositingBounds.location() - graphicsLayerParentLocation)); + m_graphicsLayer->setOffsetFromRenderer(toIntSize(localCompositingBounds.location())); + FloatSize oldSize = m_graphicsLayer->size(); - FloatSize newSize = relativeCompositingBounds.size(); - if (oldSize != newSize) { - m_graphicsLayer->setSize(newSize); - // A bounds change will almost always require redisplay. Usually that redisplay - // will happen because of a repaint elsewhere, but not always: - // e.g. see RenderView::setMaximalOutlineSize() - m_graphicsLayer->setNeedsDisplay(); + if (oldSize != contentsSize) { + m_graphicsLayer->setSize(contentsSize); + // Usually invalidation will happen via layout etc, but if we've affected the layer + // size by constraining relative to a clipping ancestor or the viewport, we + // have to invalidate to avoid showing stretched content. + if (m_boundsConstrainedByClipping) + m_graphicsLayer->setNeedsDisplay(); + } + if (!m_isMainFrameRenderViewLayer) { + // For non-root layers, background is always painted by the primary graphics layer. + ASSERT(!m_backgroundLayer); + m_graphicsLayer->setContentsOpaque(m_owningLayer->backgroundIsKnownToBeOpaqueInRect(localCompositingBounds)); } // If we have a layer that clips children, position it. IntRect clippingBox; if (GraphicsLayer* clipLayer = clippingLayer()) { clippingBox = clipBox(toRenderBox(renderer())); - clipLayer->setPosition(FloatPoint() + (clippingBox.location() - localCompositingBounds.location())); + clipLayer->setPosition(FloatPoint(clippingBox.location() - localCompositingBounds.location())); clipLayer->setSize(clippingBox.size()); - clipLayer->setOffsetFromRenderer(clippingBox.location() - IntPoint()); + clipLayer->setOffsetFromRenderer(toIntSize(clippingBox.location())); } if (m_maskLayer) { @@ -668,7 +744,7 @@ void RenderLayerBacking::updateGraphicsLayerGeometry() const IntRect borderBox = toRenderBox(renderer())->pixelSnappedBorderBoxRect(); // Get layout bounds in the coords of compAncestor to match relativeCompositingBounds. - IntRect layerBounds = IntRect(delta, borderBox.size()); + IntRect layerBounds(delta, borderBox.size()); // Update properties that depend on layer dimensions FloatPoint3D transformOrigin = computeTransformOrigin(borderBox); @@ -676,7 +752,10 @@ void RenderLayerBacking::updateGraphicsLayerGeometry() FloatPoint3D anchor(relativeCompositingBounds.width() != 0.0f ? ((layerBounds.x() - relativeCompositingBounds.x()) + transformOrigin.x()) / relativeCompositingBounds.width() : 0.5f, relativeCompositingBounds.height() != 0.0f ? ((layerBounds.y() - relativeCompositingBounds.y()) + transformOrigin.y()) / relativeCompositingBounds.height() : 0.5f, transformOrigin.z()); - m_graphicsLayer->setAnchorPoint(anchor); + if (m_contentsContainmentLayer) + m_contentsContainmentLayer->setAnchorPoint(anchor); + else + m_graphicsLayer->setAnchorPoint(anchor); RenderStyle* style = renderer()->style(); GraphicsLayer* clipLayer = clippingLayer(); @@ -697,17 +776,19 @@ void RenderLayerBacking::updateGraphicsLayerGeometry() } } else { m_graphicsLayer->setAnchorPoint(FloatPoint3D(0.5f, 0.5f, 0)); + if (m_contentsContainmentLayer) + m_contentsContainmentLayer->setAnchorPoint(FloatPoint3D(0.5f, 0.5f, 0)); } if (m_foregroundLayer) { FloatPoint foregroundPosition; - FloatSize foregroundSize = newSize; + FloatSize foregroundSize = contentsSize; IntSize foregroundOffset = m_graphicsLayer->offsetFromRenderer(); if (hasClippingLayer()) { // If we have a clipping layer (which clips descendants), then the foreground layer is a child of it, // so that it gets correctly sorted with children. In that case, position relative to the clipping layer. foregroundSize = FloatSize(clippingBox.size()); - foregroundOffset = clippingBox.location() - IntPoint(); + foregroundOffset = toIntSize(clippingBox.location()); } m_foregroundLayer->setPosition(foregroundPosition); @@ -718,6 +799,22 @@ void RenderLayerBacking::updateGraphicsLayerGeometry() m_foregroundLayer->setOffsetFromRenderer(foregroundOffset); } + if (m_backgroundLayer) { + FloatPoint backgroundPosition; + FloatSize backgroundSize = contentsSize; + if (backgroundLayerPaintsFixedRootBackground()) { + FrameView* frameView = toRenderView(renderer())->frameView(); + backgroundPosition = IntPoint(frameView->scrollOffsetForFixedPosition()); + backgroundSize = frameView->visibleContentRect().size(); + } + m_backgroundLayer->setPosition(backgroundPosition); + if (backgroundSize != m_backgroundLayer->size()) { + m_backgroundLayer->setSize(backgroundSize); + m_backgroundLayer->setNeedsDisplay(); + } + m_backgroundLayer->setOffsetFromRenderer(m_graphicsLayer->offsetFromRenderer()); + } + if (m_owningLayer->reflectionLayer() && m_owningLayer->reflectionLayer()->isComposited()) { RenderLayerBacking* reflectionBacking = m_owningLayer->reflectionLayer()->backing(); reflectionBacking->updateGraphicsLayerGeometry(); @@ -726,22 +823,22 @@ void RenderLayerBacking::updateGraphicsLayerGeometry() // but the reflected layer is the bounds of this layer, so we need to position it appropriately. FloatRect layerBounds = compositedBounds(); FloatRect reflectionLayerBounds = reflectionBacking->compositedBounds(); - reflectionBacking->graphicsLayer()->setReplicatedLayerPosition(FloatPoint() + (layerBounds.location() - reflectionLayerBounds.location())); + reflectionBacking->graphicsLayer()->setReplicatedLayerPosition(FloatPoint(layerBounds.location() - reflectionLayerBounds.location())); } if (m_scrollingLayer) { ASSERT(m_scrollingContentsLayer); RenderBox* renderBox = toRenderBox(renderer()); IntRect paddingBox(renderBox->borderLeft(), renderBox->borderTop(), renderBox->width() - renderBox->borderLeft() - renderBox->borderRight(), renderBox->height() - renderBox->borderTop() - renderBox->borderBottom()); - IntSize scrollOffset = m_owningLayer->scrolledContentOffset(); + IntSize scrollOffset = m_owningLayer->scrollOffset(); - m_scrollingLayer->setPosition(FloatPoint() + (paddingBox.location() - localCompositingBounds.location())); + m_scrollingLayer->setPosition(FloatPoint(paddingBox.location() - localCompositingBounds.location())); m_scrollingLayer->setSize(paddingBox.size()); m_scrollingContentsLayer->setPosition(FloatPoint(-scrollOffset.width(), -scrollOffset.height())); IntSize oldScrollingLayerOffset = m_scrollingLayer->offsetFromRenderer(); - m_scrollingLayer->setOffsetFromRenderer(IntPoint() - paddingBox.location()); + m_scrollingLayer->setOffsetFromRenderer(-toIntSize(paddingBox.location())); bool paddingBoxOffsetChanged = oldScrollingLayerOffset != m_scrollingLayer->offsetFromRenderer(); @@ -749,41 +846,96 @@ void RenderLayerBacking::updateGraphicsLayerGeometry() if (scrollSize != m_scrollingContentsLayer->size() || paddingBoxOffsetChanged) m_scrollingContentsLayer->setNeedsDisplay(); - IntSize scrollingContentsOffset = paddingBox.location() - IntPoint() - scrollOffset; + IntSize scrollingContentsOffset = toIntSize(paddingBox.location() - scrollOffset); if (scrollingContentsOffset != m_scrollingContentsLayer->offsetFromRenderer() || scrollSize != m_scrollingContentsLayer->size()) compositor()->scrollingLayerDidChange(m_owningLayer); m_scrollingContentsLayer->setSize(scrollSize); // FIXME: The paint offset and the scroll offset should really be separate concepts. m_scrollingContentsLayer->setOffsetFromRenderer(scrollingContentsOffset, GraphicsLayer::DontSetNeedsDisplay); - } - m_graphicsLayer->setContentsRect(contentsBox()); + if (m_foregroundLayer) { + if (m_foregroundLayer->size() != m_scrollingContentsLayer->size()) + m_foregroundLayer->setSize(m_scrollingContentsLayer->size()); + m_foregroundLayer->setNeedsDisplay(); + m_foregroundLayer->setOffsetFromRenderer(m_scrollingContentsLayer->offsetFromRenderer()); + } + } // If this layer was created just for clipping or to apply perspective, it doesn't need its own backing store. - setRequiresOwnBackingStore(compositor()->requiresOwnBackingStore(m_owningLayer, compAncestor)); + setRequiresOwnBackingStore(compositor()->requiresOwnBackingStore(m_owningLayer, compAncestor, relativeCompositingBounds, ancestorCompositingBounds)); + + bool didUpdateContentsRect = false; + updateDirectlyCompositedContents(isSimpleContainer, didUpdateContentsRect); + if (!didUpdateContentsRect && m_graphicsLayer->hasContentsLayer()) + resetContentsRect(); - updateDrawsContent(); + updateDrawsContent(isSimpleContainer); updateAfterWidgetResize(); + registerScrollingLayers(); +} + +void RenderLayerBacking::updateDirectlyCompositedContents(bool isSimpleContainer, bool& didUpdateContentsRect) +{ + if (!m_owningLayer->hasVisibleContent()) + return; + + // The order of operations here matters, since the last valid type of contents needs + // to also update the contentsRect. + updateDirectlyCompositedBackgroundColor(isSimpleContainer, didUpdateContentsRect); + updateDirectlyCompositedBackgroundImage(isSimpleContainer, didUpdateContentsRect); +} + +void RenderLayerBacking::registerScrollingLayers() +{ + // Register fixed position layers and their containers with the scrolling coordinator. + ScrollingCoordinator* scrollingCoordinator = scrollingCoordinatorFromLayer(m_owningLayer); + if (!scrollingCoordinator) + return; + + compositor()->updateViewportConstraintStatus(m_owningLayer); + + if (!scrollingCoordinator->supportsFixedPositionLayers()) + return; + + scrollingCoordinator->updateLayerPositionConstraint(m_owningLayer); + + // Page scale is applied as a transform on the root render view layer. Because the scroll + // layer is further up in the hierarchy, we need to avoid marking the root render view + // layer as a container. + bool isContainer = m_owningLayer->hasTransform() && !m_owningLayer->isRootLayer(); + scrollingCoordinator->setLayerIsContainerForFixedPositionLayers(childForSuperlayers(), isContainer); } void RenderLayerBacking::updateInternalHierarchy() { // m_foregroundLayer has to be inserted in the correct order with child layers, // so it's not inserted here. - if (m_ancestorClippingLayer) { + if (m_ancestorClippingLayer) m_ancestorClippingLayer->removeAllChildren(); - m_graphicsLayer->removeFromParent(); - m_ancestorClippingLayer->addChild(m_graphicsLayer.get()); + + if (m_contentsContainmentLayer) { + m_contentsContainmentLayer->removeAllChildren(); + if (m_ancestorClippingLayer) + m_ancestorClippingLayer->addChild(m_contentsContainmentLayer.get()); } + + if (m_backgroundLayer) + m_contentsContainmentLayer->addChild(m_backgroundLayer.get()); - if (m_containmentLayer) { - m_containmentLayer->removeFromParent(); - m_graphicsLayer->addChild(m_containmentLayer.get()); + m_graphicsLayer->removeFromParent(); + if (m_contentsContainmentLayer) + m_contentsContainmentLayer->addChild(m_graphicsLayer.get()); + else if (m_ancestorClippingLayer) + m_ancestorClippingLayer->addChild(m_graphicsLayer.get()); + + if (m_childContainmentLayer) { + m_childContainmentLayer->removeFromParent(); + m_graphicsLayer->addChild(m_childContainmentLayer.get()); } if (m_scrollingLayer) { - GraphicsLayer* superlayer = m_containmentLayer ? m_containmentLayer.get() : m_graphicsLayer.get(); + GraphicsLayer* superlayer = m_childContainmentLayer ? m_childContainmentLayer.get() : m_graphicsLayer.get(); m_scrollingLayer->removeFromParent(); superlayer->addChild(m_scrollingLayer.get()); } @@ -805,14 +957,27 @@ void RenderLayerBacking::updateInternalHierarchy() } } +void RenderLayerBacking::resetContentsRect() +{ + IntRect rect = pixelSnappedIntRect(contentsBox()); + m_graphicsLayer->setContentsRect(rect); + m_graphicsLayer->setContentsTileSize(IntSize()); + m_graphicsLayer->setContentsTilePhase(IntPoint()); +} + void RenderLayerBacking::updateDrawsContent() { + updateDrawsContent(isSimpleContainerCompositingLayer()); +} + +void RenderLayerBacking::updateDrawsContent(bool isSimpleContainer) +{ if (m_scrollingLayer) { // We don't have to consider overflow controls, because we know that the scrollbars are drawn elsewhere. // m_graphicsLayer only needs backing store if the non-scrolling parts (background, outlines, borders, shadows etc) need to paint. // m_scrollingLayer never has backing store. // m_scrollingContentsLayer only needs backing store if the scrolled contents need to paint. - bool hasNonScrollingPaintedContent = m_owningLayer->hasVisibleContent() && hasBoxDecorationsOrBackground(renderer()); + bool hasNonScrollingPaintedContent = m_owningLayer->hasVisibleContent() && m_owningLayer->hasBoxDecorationsOrBackground(); m_graphicsLayer->setDrawsContent(hasNonScrollingPaintedContent); bool hasScrollingPaintedContent = m_owningLayer->hasVisibleContent() && (renderer()->hasBackground() || paintsChildren()); @@ -820,12 +985,15 @@ void RenderLayerBacking::updateDrawsContent() return; } - bool hasPaintedContent = containsPaintedContent(); + bool hasPaintedContent = containsPaintedContent(isSimpleContainer); // FIXME: we could refine this to only allocate backing for one of these layers if possible. m_graphicsLayer->setDrawsContent(hasPaintedContent); if (m_foregroundLayer) m_foregroundLayer->setDrawsContent(hasPaintedContent); + + if (m_backgroundLayer) + m_backgroundLayer->setDrawsContent(hasPaintedContent); } // Return true if the layers changed. @@ -840,87 +1008,100 @@ bool RenderLayerBacking::updateClippingLayers(bool needsAncestorClip, bool needs layersChanged = true; } } else if (m_ancestorClippingLayer) { + willDestroyLayer(m_ancestorClippingLayer.get()); m_ancestorClippingLayer->removeFromParent(); m_ancestorClippingLayer = nullptr; layersChanged = true; } if (needsDescendantClip) { - if (!m_containmentLayer && !m_usingTiledCacheLayer) { - m_containmentLayer = createGraphicsLayer("Child clipping Layer"); - m_containmentLayer->setMasksToBounds(true); + if (!m_childContainmentLayer && !m_usingTiledCacheLayer) { + m_childContainmentLayer = createGraphicsLayer("Child clipping Layer"); + m_childContainmentLayer->setMasksToBounds(true); layersChanged = true; } } else if (hasClippingLayer()) { - m_containmentLayer->removeFromParent(); - m_containmentLayer = nullptr; + willDestroyLayer(m_childContainmentLayer.get()); + m_childContainmentLayer->removeFromParent(); + m_childContainmentLayer = nullptr; layersChanged = true; } return layersChanged; } +void RenderLayerBacking::setBackgroundLayerPaintsFixedRootBackground(bool backgroundLayerPaintsFixedRootBackground) +{ + m_backgroundLayerPaintsFixedRootBackground = backgroundLayerPaintsFixedRootBackground; +} + bool RenderLayerBacking::requiresHorizontalScrollbarLayer() const { -#if !PLATFORM(CHROMIUM) - if (!m_owningLayer->hasOverlayScrollbars()) + if (!m_owningLayer->hasOverlayScrollbars() && !m_owningLayer->needsCompositedScrolling()) return false; -#endif return m_owningLayer->horizontalScrollbar(); } bool RenderLayerBacking::requiresVerticalScrollbarLayer() const { -#if !PLATFORM(CHROMIUM) - if (!m_owningLayer->hasOverlayScrollbars()) + if (!m_owningLayer->hasOverlayScrollbars() && !m_owningLayer->needsCompositedScrolling()) return false; -#endif return m_owningLayer->verticalScrollbar(); } bool RenderLayerBacking::requiresScrollCornerLayer() const { -#if !PLATFORM(CHROMIUM) - if (!m_owningLayer->hasOverlayScrollbars()) + if (!m_owningLayer->hasOverlayScrollbars() && !m_owningLayer->needsCompositedScrolling()) return false; -#endif return !m_owningLayer->scrollCornerAndResizerRect().isEmpty(); } bool RenderLayerBacking::updateOverflowControlsLayers(bool needsHorizontalScrollbarLayer, bool needsVerticalScrollbarLayer, bool needsScrollCornerLayer) { - bool layersChanged = false; + bool horizontalScrollbarLayerChanged = false; if (needsHorizontalScrollbarLayer) { if (!m_layerForHorizontalScrollbar) { m_layerForHorizontalScrollbar = createGraphicsLayer("horizontal scrollbar"); - layersChanged = true; + horizontalScrollbarLayerChanged = true; } } else if (m_layerForHorizontalScrollbar) { - m_layerForHorizontalScrollbar.clear(); - layersChanged = true; + willDestroyLayer(m_layerForHorizontalScrollbar.get()); + m_layerForHorizontalScrollbar = nullptr; + horizontalScrollbarLayerChanged = true; } + bool verticalScrollbarLayerChanged = false; if (needsVerticalScrollbarLayer) { if (!m_layerForVerticalScrollbar) { m_layerForVerticalScrollbar = createGraphicsLayer("vertical scrollbar"); - layersChanged = true; + verticalScrollbarLayerChanged = true; } } else if (m_layerForVerticalScrollbar) { - m_layerForVerticalScrollbar.clear(); - layersChanged = true; + willDestroyLayer(m_layerForVerticalScrollbar.get()); + m_layerForVerticalScrollbar = nullptr; + verticalScrollbarLayerChanged = true; } + bool scrollCornerLayerChanged = false; if (needsScrollCornerLayer) { if (!m_layerForScrollCorner) { m_layerForScrollCorner = createGraphicsLayer("scroll corner"); - layersChanged = true; + scrollCornerLayerChanged = true; } } else if (m_layerForScrollCorner) { - m_layerForScrollCorner.clear(); - layersChanged = true; + willDestroyLayer(m_layerForScrollCorner.get()); + m_layerForScrollCorner = nullptr; + scrollCornerLayerChanged = true; } - return layersChanged; + if (ScrollingCoordinator* scrollingCoordinator = scrollingCoordinatorFromLayer(m_owningLayer)) { + if (horizontalScrollbarLayerChanged) + scrollingCoordinator->scrollableAreaScrollbarLayerDidChange(m_owningLayer, HorizontalScrollbar); + if (verticalScrollbarLayerChanged) + scrollingCoordinator->scrollableAreaScrollbarLayerDidChange(m_owningLayer, VerticalScrollbar); + } + + return horizontalScrollbarLayerChanged || verticalScrollbarLayerChanged || scrollCornerLayerChanged; } void RenderLayerBacking::positionOverflowControlsLayers(const IntSize& offsetFromRoot) @@ -931,8 +1112,10 @@ void RenderLayerBacking::positionOverflowControlsLayers(const IntSize& offsetFro if (hBar) { layer->setPosition(hBar->frameRect().location() - offsetFromRoot - offsetFromRenderer); layer->setSize(hBar->frameRect().size()); + if (layer->hasContentsLayer()) + layer->setContentsRect(IntRect(IntPoint(), hBar->frameRect().size())); } - layer->setDrawsContent(hBar); + layer->setDrawsContent(hBar && !layer->hasContentsLayer()); } if (GraphicsLayer* layer = layerForVerticalScrollbar()) { @@ -940,8 +1123,10 @@ void RenderLayerBacking::positionOverflowControlsLayers(const IntSize& offsetFro if (vBar) { layer->setPosition(vBar->frameRect().location() - offsetFromRoot - offsetFromRenderer); layer->setSize(vBar->frameRect().size()); + if (layer->hasContentsLayer()) + layer->setContentsRect(IntRect(IntPoint(), vBar->frameRect().size())); } - layer->setDrawsContent(vBar); + layer->setDrawsContent(vBar && !layer->hasContentsLayer()); } if (GraphicsLayer* layer = layerForScrollCorner()) { @@ -952,6 +1137,23 @@ void RenderLayerBacking::positionOverflowControlsLayers(const IntSize& offsetFro } } +bool RenderLayerBacking::hasUnpositionedOverflowControlsLayers() const +{ + if (GraphicsLayer* layer = layerForHorizontalScrollbar()) + if (!layer->drawsContent()) + return true; + + if (GraphicsLayer* layer = layerForVerticalScrollbar()) + if (!layer->drawsContent()) + return true; + + if (GraphicsLayer* layer = layerForScrollCorner()) + if (!layer->drawsContent()) + return true; + + return false; +} + bool RenderLayerBacking::updateForegroundLayer(bool needsForegroundLayer) { bool layerChanged = false; @@ -959,7 +1161,7 @@ bool RenderLayerBacking::updateForegroundLayer(bool needsForegroundLayer) if (!m_foregroundLayer) { String layerName; #ifndef NDEBUG - layerName = nameForLayer() + " (foreground)"; + layerName = m_owningLayer->name() + " (foreground)"; #endif m_foregroundLayer = createGraphicsLayer(layerName); m_foregroundLayer->setDrawsContent(true); @@ -967,17 +1169,72 @@ bool RenderLayerBacking::updateForegroundLayer(bool needsForegroundLayer) layerChanged = true; } } else if (m_foregroundLayer) { + willDestroyLayer(m_foregroundLayer.get()); m_foregroundLayer->removeFromParent(); m_foregroundLayer = nullptr; layerChanged = true; } - if (layerChanged) + if (layerChanged) { + m_graphicsLayer->setNeedsDisplay(); m_graphicsLayer->setPaintingPhase(paintingPhaseForPrimaryLayer()); + } return layerChanged; } +bool RenderLayerBacking::updateBackgroundLayer(bool needsBackgroundLayer) +{ + bool layerChanged = false; + if (needsBackgroundLayer) { + if (!m_backgroundLayer) { + String layerName; +#ifndef NDEBUG + layerName = m_owningLayer->name() + " (background)"; +#endif + m_backgroundLayer = createGraphicsLayer(layerName); + m_backgroundLayer->setDrawsContent(true); + m_backgroundLayer->setAnchorPoint(FloatPoint3D()); + m_backgroundLayer->setPaintingPhase(GraphicsLayerPaintBackground); + layerChanged = true; + } + + if (!m_contentsContainmentLayer) { + String layerName; +#ifndef NDEBUG + layerName = m_owningLayer->name() + " (contents containment)"; +#endif + m_contentsContainmentLayer = createGraphicsLayer(layerName); + m_contentsContainmentLayer->setAppliesPageScale(true); + m_graphicsLayer->setAppliesPageScale(false); + layerChanged = true; + } + } else { + if (m_backgroundLayer) { + willDestroyLayer(m_backgroundLayer.get()); + m_backgroundLayer->removeFromParent(); + m_backgroundLayer = nullptr; + layerChanged = true; + } + if (m_contentsContainmentLayer) { + willDestroyLayer(m_contentsContainmentLayer.get()); + m_contentsContainmentLayer->removeFromParent(); + m_contentsContainmentLayer = nullptr; + layerChanged = true; + m_graphicsLayer->setAppliesPageScale(true); + } + } + + if (layerChanged) { + m_graphicsLayer->setNeedsDisplay(); + // This assumes that the background layer is only used for fixed backgrounds, which is currently a correct assumption. + if (renderer()->view()) + compositor()->fixedRootBackgroundLayerChanged(); + } + + return layerChanged; +} + bool RenderLayerBacking::updateMaskLayer(bool needsMaskLayer) { bool layerChanged = false; @@ -989,6 +1246,7 @@ bool RenderLayerBacking::updateMaskLayer(bool needsMaskLayer) layerChanged = true; } } else if (m_maskLayer) { + willDestroyLayer(m_maskLayer.get()); m_maskLayer = nullptr; layerChanged = true; } @@ -1001,6 +1259,8 @@ bool RenderLayerBacking::updateMaskLayer(bool needsMaskLayer) bool RenderLayerBacking::updateScrollingLayers(bool needsScrollingLayers) { + ScrollingCoordinator* scrollingCoordinator = scrollingCoordinatorFromLayer(m_owningLayer); + bool layerChanged = false; if (needsScrollingLayers) { if (!m_scrollingLayer) { @@ -1012,15 +1272,24 @@ bool RenderLayerBacking::updateScrollingLayers(bool needsScrollingLayers) // Inner layer which renders the content that scrolls. m_scrollingContentsLayer = createGraphicsLayer("Scrolled Contents"); m_scrollingContentsLayer->setDrawsContent(true); - m_scrollingContentsLayer->setPaintingPhase(GraphicsLayerPaintForeground | GraphicsLayerPaintOverflowContents); + GraphicsLayerPaintingPhase paintPhase = GraphicsLayerPaintOverflowContents | GraphicsLayerPaintCompositedScroll; + if (!m_foregroundLayer) + paintPhase |= GraphicsLayerPaintForeground; + m_scrollingContentsLayer->setPaintingPhase(paintPhase); m_scrollingLayer->addChild(m_scrollingContentsLayer.get()); layerChanged = true; + if (scrollingCoordinator) + scrollingCoordinator->scrollableAreaScrollLayerDidChange(m_owningLayer); } } else if (m_scrollingLayer) { + willDestroyLayer(m_scrollingLayer.get()); + willDestroyLayer(m_scrollingContentsLayer.get()); m_scrollingLayer = nullptr; m_scrollingContentsLayer = nullptr; layerChanged = true; + if (scrollingCoordinator) + scrollingCoordinator->scrollableAreaScrollLayerDidChange(m_owningLayer); } if (layerChanged) { @@ -1034,17 +1303,9 @@ bool RenderLayerBacking::updateScrollingLayers(bool needsScrollingLayers) return layerChanged; } -void RenderLayerBacking::attachToScrollingCoordinator(RenderLayerBacking* parent) +void RenderLayerBacking::attachToScrollingCoordinatorWithParent(RenderLayerBacking* parent) { - // If m_scrollLayerID non-zero, then this backing is already attached to the ScrollingCoordinator. - if (m_scrollLayerID) - return; - - Page* page = renderer()->frame()->page(); - if (!page) - return; - - ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator(); + ScrollingCoordinator* scrollingCoordinator = scrollingCoordinatorFromLayer(m_owningLayer); if (!scrollingCoordinator) return; @@ -1053,11 +1314,13 @@ void RenderLayerBacking::attachToScrollingCoordinator(RenderLayerBacking* parent ScrollingNodeType nodeType; if (renderer()->style()->position() == FixedPosition) nodeType = FixedNode; + else if (renderer()->style()->position() == StickyPosition) + nodeType = StickyNode; else nodeType = ScrollingNode; ScrollingNodeID parentID = parent ? parent->scrollLayerID() : 0; - m_scrollLayerID = scrollingCoordinator->attachToStateTree(nodeType, scrollingCoordinator->uniqueScrollLayerID(), parentID); + m_scrollLayerID = scrollingCoordinator->attachToStateTree(nodeType, m_scrollLayerID ? m_scrollLayerID : scrollingCoordinator->uniqueScrollLayerID(), parentID); } void RenderLayerBacking::detachFromScrollingCoordinator() @@ -1066,11 +1329,7 @@ void RenderLayerBacking::detachFromScrollingCoordinator() if (!m_scrollLayerID) return; - Page* page = renderer()->frame()->page(); - if (!page) - return; - - ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator(); + ScrollingCoordinator* scrollingCoordinator = scrollingCoordinatorFromLayer(m_owningLayer); if (!scrollingCoordinator) return; @@ -1080,14 +1339,18 @@ void RenderLayerBacking::detachFromScrollingCoordinator() GraphicsLayerPaintingPhase RenderLayerBacking::paintingPhaseForPrimaryLayer() const { - unsigned phase = GraphicsLayerPaintBackground; + unsigned phase = 0; + if (!m_backgroundLayer) + phase |= GraphicsLayerPaintBackground; if (!m_foregroundLayer) phase |= GraphicsLayerPaintForeground; if (!m_maskLayer) phase |= GraphicsLayerPaintMask; - if (m_scrollingContentsLayer) + if (m_scrollingContentsLayer) { phase &= ~GraphicsLayerPaintForeground; + phase |= GraphicsLayerPaintCompositedScroll; + } return static_cast<GraphicsLayerPaintingPhase>(phase); } @@ -1099,7 +1362,7 @@ float RenderLayerBacking::compositingOpacity(float rendererOpacity) const for (RenderLayer* curr = m_owningLayer->parent(); curr; curr = curr->parent()) { // We only care about parents that are stacking contexts. // Recall that opacity creates stacking context. - if (!curr->isStackingContext()) + if (!curr->isStackingContainer()) continue; // If we found a compositing layer, we want to compute opacity @@ -1118,14 +1381,17 @@ static bool hasBoxDecorations(const RenderStyle* style) return style->hasBorder() || style->hasBorderRadius() || style->hasOutline() || style->hasAppearance() || style->boxShadow() || style->hasFilter(); } -static bool hasBoxDecorationsOrBackground(const RenderObject* renderer) -{ - return hasBoxDecorations(renderer->style()) || renderer->hasBackground(); -} +static bool canCreateTiledImage(const RenderStyle*); static bool hasBoxDecorationsOrBackgroundImage(const RenderStyle* style) { - return hasBoxDecorations(style) || style->hasBackgroundImage(); + if (hasBoxDecorations(style)) + return true; + + if (!style->hasBackgroundImage()) + return false; + + return !GraphicsLayer::supportsContentsTiling() || !canCreateTiledImage(style); } Color RenderLayerBacking::rendererBackgroundColor() const @@ -1137,20 +1403,128 @@ Color RenderLayerBacking::rendererBackgroundColor() const return backgroundRenderer->style()->visitedDependentColor(CSSPropertyBackgroundColor); } -void RenderLayerBacking::updateBackgroundColor() +void RenderLayerBacking::updateDirectlyCompositedBackgroundColor(bool isSimpleContainer, bool& didUpdateContentsRect) { - m_graphicsLayer->setContentsToBackgroundColor(rendererBackgroundColor()); + if (!isSimpleContainer) { + m_graphicsLayer->setContentsToSolidColor(Color()); + return; + } + + Color backgroundColor = rendererBackgroundColor(); + + // An unset (invalid) color will remove the solid color. + m_graphicsLayer->setContentsToSolidColor(backgroundColor); + m_graphicsLayer->setContentsRect(backgroundBox()); + didUpdateContentsRect = true; } -bool RenderLayerBacking::paintsBoxDecorations() const +bool canCreateTiledImage(const RenderStyle* style) { - if (!m_owningLayer->hasVisibleContent()) + const FillLayer* fillLayer = style->backgroundLayers(); + if (fillLayer->next()) return false; - if (hasBoxDecorationsOrBackground(renderer())) - return true; + if (!fillLayer->imagesAreLoaded()) + return false; + + if (fillLayer->attachment() != ScrollBackgroundAttachment) + return false; + + Color color = style->visitedDependentColor(CSSPropertyBackgroundColor); + + // FIXME: Allow color+image compositing when it makes sense. + // For now bailing out. + if (color.isValid() && color.alpha()) + return false; + + StyleImage* styleImage = fillLayer->image(); + + // FIXME: support gradients with isGeneratedImage. + if (!styleImage->isCachedImage()) + return false; + + Image* image = styleImage->cachedImage()->image(); + if (!image->isBitmapImage()) + return false; + + return true; +} + +void RenderLayerBacking::updateDirectlyCompositedBackgroundImage(bool isSimpleContainer, bool& didUpdateContentsRect) +{ + if (!GraphicsLayer::supportsContentsTiling()) + return; + + if (isDirectlyCompositedImage()) + return; + + const RenderStyle* style = renderer()->style(); + + if (!isSimpleContainer || !style->hasBackgroundImage()) { + m_graphicsLayer->setContentsToImage(0); + return; + } + + IntRect destRect = backgroundBox(); + IntPoint phase; + IntSize tileSize; + + RefPtr<Image> image = style->backgroundLayers()->image()->cachedImage()->image(); + toRenderBox(renderer())->getGeometryForBackgroundImage(m_owningLayer->renderer(), destRect, phase, tileSize); + m_graphicsLayer->setContentsTileSize(tileSize); + m_graphicsLayer->setContentsTilePhase(phase); + m_graphicsLayer->setContentsRect(destRect); + m_graphicsLayer->setContentsToImage(image.get()); + didUpdateContentsRect = true; +} + +void RenderLayerBacking::updateRootLayerConfiguration() +{ + if (!m_usingTiledCacheLayer) + return; + + Color backgroundColor; + bool viewIsTransparent = compositor()->viewHasTransparentBackground(&backgroundColor); + + if (m_backgroundLayerPaintsFixedRootBackground && m_backgroundLayer) { + m_backgroundLayer->setBackgroundColor(backgroundColor); + m_backgroundLayer->setContentsOpaque(!viewIsTransparent); + + m_graphicsLayer->setBackgroundColor(Color()); + m_graphicsLayer->setContentsOpaque(false); + } else { + m_graphicsLayer->setBackgroundColor(backgroundColor); + m_graphicsLayer->setContentsOpaque(!viewIsTransparent); + } +} + +static bool supportsDirectBoxDecorationsComposition(const RenderObject* renderer) +{ + if (!GraphicsLayer::supportsBackgroundColorContent()) + return false; + + if (renderer->hasClip()) + return false; + + if (hasBoxDecorationsOrBackgroundImage(renderer->style())) + return false; + + // FIXME: we should be able to allow backgroundComposite; However since this is not a common use case it has been deferred for now. + if (renderer->style()->backgroundComposite() != CompositeSourceOver) + return false; - if (m_owningLayer->hasOverflowControls()) + if (renderer->style()->backgroundClip() == TextFillBox) + return false; + + return true; +} + +bool RenderLayerBacking::paintsBoxDecorations() const +{ + if (!m_owningLayer->hasVisibleBoxDecorations()) + return false; + + if (!supportsDirectBoxDecorationsComposition(renderer())) return true; return false; @@ -1158,15 +1532,27 @@ bool RenderLayerBacking::paintsBoxDecorations() const bool RenderLayerBacking::paintsChildren() const { - if (m_owningLayer->hasVisibleContent() && containsNonEmptyRenderers()) + if (m_owningLayer->hasVisibleContent() && m_owningLayer->hasNonEmptyChildRenderers()) return true; - + if (hasVisibleNonCompositingDescendantLayers()) return true; return false; } +static bool isRestartedPlugin(RenderObject* renderer) +{ + if (!renderer->isEmbeddedObject()) + return false; + + Element* element = toElement(renderer->node()); + if (!element || !element->isPluginElement()) + return false; + + return toHTMLPlugInElement(element)->isRestartedPlugin(); +} + static bool isCompositedPlugin(RenderObject* renderer) { return renderer->isEmbeddedObject() && toRenderEmbeddedObject(renderer)->allowsAcceleratedCompositing(); @@ -1181,12 +1567,15 @@ bool RenderLayerBacking::isSimpleContainerCompositingLayer() const if (renderObject->hasMask()) // masks require special treatment return false; - if (renderObject->isReplaced() && !isCompositedPlugin(renderObject)) - return false; - + if (renderObject->isReplaced() && (!isCompositedPlugin(renderObject) || isRestartedPlugin(renderObject))) + return false; + if (paintsBoxDecorations() || paintsChildren()) return false; - + + if (renderObject->isRenderRegion()) + return false; + if (renderObject->node() && renderObject->node()->isDocumentNode()) { // Look to see if the root object has a non-simple background RenderObject* rootObject = renderObject->document()->documentElement() ? renderObject->document()->documentElement()->renderer() : 0; @@ -1215,63 +1604,46 @@ bool RenderLayerBacking::isSimpleContainerCompositingLayer() const return true; } -bool RenderLayerBacking::containsNonEmptyRenderers() const -{ - // Some HTML can cause whitespace text nodes to have renderers, like: - // <div> - // <img src=...> - // </div> - // so test for 0x0 RenderTexts here - for (RenderObject* child = renderer()->firstChild(); child; child = child->nextSibling()) { - if (!child->hasLayer()) { - if (child->isRenderInline() || !child->isBox()) - return true; - - if (toRenderBox(child)->width() > 0 || toRenderBox(child)->height() > 0) - return true; - } - } - return false; -} - -// Conservative test for having no rendered children. -bool RenderLayerBacking::hasVisibleNonCompositingDescendantLayers() const +static bool hasVisibleNonCompositingDescendant(RenderLayer* parent) { // FIXME: We shouldn't be called with a stale z-order lists. See bug 85512. - m_owningLayer->updateLayerListsIfNeeded(); + parent->updateLayerListsIfNeeded(); #if !ASSERT_DISABLED - LayerListMutationDetector mutationChecker(m_owningLayer); + LayerListMutationDetector mutationChecker(parent); #endif - if (Vector<RenderLayer*>* normalFlowList = m_owningLayer->normalFlowList()) { + if (Vector<RenderLayer*>* normalFlowList = parent->normalFlowList()) { size_t listSize = normalFlowList->size(); for (size_t i = 0; i < listSize; ++i) { RenderLayer* curLayer = normalFlowList->at(i); - if (!curLayer->isComposited() && curLayer->hasVisibleContent()) + if (!curLayer->isComposited() + && (curLayer->hasVisibleContent() || hasVisibleNonCompositingDescendant(curLayer))) return true; } } - if (m_owningLayer->isStackingContext()) { - if (!m_owningLayer->hasVisibleDescendant()) + if (parent->isStackingContainer()) { + if (!parent->hasVisibleDescendant()) return false; // Use the m_hasCompositingDescendant bit to optimize? - if (Vector<RenderLayer*>* negZOrderList = m_owningLayer->negZOrderList()) { + if (Vector<RenderLayer*>* negZOrderList = parent->negZOrderList()) { size_t listSize = negZOrderList->size(); for (size_t i = 0; i < listSize; ++i) { RenderLayer* curLayer = negZOrderList->at(i); - if (!curLayer->isComposited() && curLayer->hasVisibleContent()) + if (!curLayer->isComposited() + && (curLayer->hasVisibleContent() || hasVisibleNonCompositingDescendant(curLayer))) return true; } } - if (Vector<RenderLayer*>* posZOrderList = m_owningLayer->posZOrderList()) { + if (Vector<RenderLayer*>* posZOrderList = parent->posZOrderList()) { size_t listSize = posZOrderList->size(); for (size_t i = 0; i < listSize; ++i) { RenderLayer* curLayer = posZOrderList->at(i); - if (!curLayer->isComposited() && curLayer->hasVisibleContent()) + if (!curLayer->isComposited() + && (curLayer->hasVisibleContent() || hasVisibleNonCompositingDescendant(curLayer))) return true; } } @@ -1280,9 +1652,15 @@ bool RenderLayerBacking::hasVisibleNonCompositingDescendantLayers() const return false; } -bool RenderLayerBacking::containsPaintedContent() const +// Conservative test for having no rendered children. +bool RenderLayerBacking::hasVisibleNonCompositingDescendantLayers() const { - if (isSimpleContainerCompositingLayer() || paintsIntoWindow() || paintsIntoCompositedAncestor() || m_artificiallyInflatedBounds || m_owningLayer->isReflection()) + return hasVisibleNonCompositingDescendant(m_owningLayer); +} + +bool RenderLayerBacking::containsPaintedContent(bool isSimpleContainer) const +{ + if (isSimpleContainer || paintsIntoWindow() || paintsIntoCompositedAncestor() || m_artificiallyInflatedBounds || m_owningLayer->isReflection()) return false; if (isDirectlyCompositedImage()) @@ -1292,12 +1670,12 @@ bool RenderLayerBacking::containsPaintedContent() const // and set background color on the layer in that case, instead of allocating backing store and painting. #if ENABLE(VIDEO) if (renderer()->isVideo() && toRenderVideo(renderer())->shouldDisplayVideo()) - return hasBoxDecorationsOrBackground(renderer()); + return m_owningLayer->hasBoxDecorationsOrBackground(); #endif #if PLATFORM(MAC) && USE(CA) && (PLATFORM(IOS) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070) #elif ENABLE(WEBGL) || ENABLE(ACCELERATED_2D_CANVAS) if (isAcceleratedCanvas(renderer())) - return hasBoxDecorationsOrBackground(renderer()); + return m_owningLayer->hasBoxDecorationsOrBackground(); #endif return true; @@ -1308,8 +1686,8 @@ bool RenderLayerBacking::containsPaintedContent() const bool RenderLayerBacking::isDirectlyCompositedImage() const { RenderObject* renderObject = renderer(); - - if (!renderObject->isImage() || hasBoxDecorationsOrBackground(renderObject) || renderObject->hasClip()) + + if (!renderObject->isImage() || m_owningLayer->hasBoxDecorationsOrBackground() || renderObject->hasClip()) return false; RenderImage* imageRenderer = toRenderImage(renderObject); @@ -1333,12 +1711,14 @@ void RenderLayerBacking::contentChanged(ContentChangeType changeType) updateImageContents(); return; } - + + if ((changeType == BackgroundImageChanged) && canCreateTiledImage(renderer()->style())) + updateGraphicsLayerGeometry(); + if ((changeType == MaskImageChanged) && m_maskLayer) { // The composited layer bounds relies on box->maskClipRect(), which changes // when the mask image becomes available. - bool isUpdateRoot = true; - updateAfterLayout(CompositingChildren, isUpdateRoot); + updateAfterLayout(CompositingChildrenOnly | IsUpdateRoot); } #if ENABLE(WEBGL) || ENABLE(ACCELERATED_2D_CANVAS) @@ -1367,8 +1747,10 @@ void RenderLayerBacking::updateImageContents() return; // This is a no-op if the layer doesn't have an inner layer for the image. + m_graphicsLayer->setContentsRect(pixelSnappedIntRect(contentsBox())); m_graphicsLayer->setContentsToImage(image); - updateDrawsContent(); + bool isSimpleContainer = false; + updateDrawsContent(isSimpleContainer); // Image animation is "lazy", in that it automatically stops unless someone is drawing // the image. So we have to kick the animation each time; this has the downside that the @@ -1403,36 +1785,73 @@ FloatPoint RenderLayerBacking::computePerspectiveOrigin(const IntRect& borderBox } // Return the offset from the top-left of this compositing layer at which the renderer's contents are painted. -IntSize RenderLayerBacking::contentOffsetInCompostingLayer() const +LayoutSize RenderLayerBacking::contentOffsetInCompostingLayer() const { - return IntSize(-m_compositedBounds.x(), -m_compositedBounds.y()); + return LayoutSize(-m_compositedBounds.x(), -m_compositedBounds.y()); } -IntRect RenderLayerBacking::contentsBox() const +LayoutRect RenderLayerBacking::contentsBox() const { if (!renderer()->isBox()) - return IntRect(); + return LayoutRect(); - IntRect contentsRect; + LayoutRect contentsRect; #if ENABLE(VIDEO) if (renderer()->isVideo()) { RenderVideo* videoRenderer = toRenderVideo(renderer()); contentsRect = videoRenderer->videoBox(); } else #endif - contentsRect = pixelSnappedIntRect(toRenderBox(renderer())->contentBoxRect()); + contentsRect = toRenderBox(renderer())->contentBoxRect(); - IntSize contentOffset = contentOffsetInCompostingLayer(); - contentsRect.move(contentOffset); + contentsRect.move(contentOffsetInCompostingLayer()); return contentsRect; } +static LayoutRect backgroundRectForBox(const RenderBox* box) +{ + switch (box->style()->backgroundClip()) { + case BorderFillBox: + return box->borderBoxRect(); + case PaddingFillBox: + return box->paddingBoxRect(); + case ContentFillBox: + return box->contentBoxRect(); + case TextFillBox: + break; + } + + ASSERT_NOT_REACHED(); + return LayoutRect(); +} + +IntRect RenderLayerBacking::backgroundBox() const +{ + if (!renderer()->isBox()) + return IntRect(); + + LayoutRect backgroundBox = backgroundRectForBox(toRenderBox(renderer())); + backgroundBox.move(contentOffsetInCompostingLayer()); + return pixelSnappedIntRect(backgroundBox); +} + GraphicsLayer* RenderLayerBacking::parentForSublayers() const { if (m_scrollingContentsLayer) return m_scrollingContentsLayer.get(); - return m_containmentLayer ? m_containmentLayer.get() : m_graphicsLayer.get(); + return m_childContainmentLayer ? m_childContainmentLayer.get() : m_graphicsLayer.get(); +} + +GraphicsLayer* RenderLayerBacking::childForSuperlayers() const +{ + if (m_ancestorClippingLayer) + return m_ancestorClippingLayer.get(); + + if (m_contentsContainmentLayer) + return m_contentsContainmentLayer.get(); + + return m_graphicsLayer.get(); } bool RenderLayerBacking::paintsIntoWindow() const @@ -1441,7 +1860,7 @@ bool RenderLayerBacking::paintsIntoWindow() const return false; if (m_owningLayer->isRootLayer()) { -#if PLATFORM(BLACKBERRY) +#if PLATFORM(BLACKBERRY) || USE(COORDINATED_GRAPHICS) if (compositor()->inForcedCompositingMode()) return false; #endif @@ -1483,6 +1902,9 @@ void RenderLayerBacking::setContentsNeedDisplay() if (m_foregroundLayer && m_foregroundLayer->drawsContent()) m_foregroundLayer->setNeedsDisplay(); + if (m_backgroundLayer && m_backgroundLayer->drawsContent()) + m_backgroundLayer->setNeedsDisplay(); + if (m_maskLayer && m_maskLayer->drawsContent()) m_maskLayer->setNeedsDisplay(); @@ -1507,6 +1929,13 @@ void RenderLayerBacking::setContentsNeedDisplayInRect(const IntRect& r) m_foregroundLayer->setNeedsDisplayInRect(layerDirtyRect); } + // FIXME: need to split out repaints for the background. + if (m_backgroundLayer && m_backgroundLayer->drawsContent()) { + IntRect layerDirtyRect = r; + layerDirtyRect.move(-m_backgroundLayer->offsetFromRenderer()); + m_backgroundLayer->setNeedsDisplayInRect(layerDirtyRect); + } + if (m_maskLayer && m_maskLayer->drawsContent()) { IntRect layerDirtyRect = r; layerDirtyRect.move(-m_maskLayer->offsetFromRenderer()); @@ -1520,7 +1949,7 @@ void RenderLayerBacking::setContentsNeedDisplayInRect(const IntRect& r) } } -void RenderLayerBacking::paintIntoLayer(RenderLayer* rootLayer, GraphicsContext* context, +void RenderLayerBacking::paintIntoLayer(const GraphicsLayer* graphicsLayer, GraphicsContext* context, const IntRect& paintDirtyRect, // In the coords of rootLayer. PaintBehavior paintBehavior, GraphicsLayerPaintingPhase paintingPhase) { @@ -1540,14 +1969,23 @@ void RenderLayerBacking::paintIntoLayer(RenderLayer* rootLayer, GraphicsContext* paintFlags |= RenderLayer::PaintLayerPaintingCompositingMaskPhase; if (paintingPhase & GraphicsLayerPaintOverflowContents) paintFlags |= RenderLayer::PaintLayerPaintingOverflowContents; + if (paintingPhase & GraphicsLayerPaintCompositedScroll) + paintFlags |= RenderLayer::PaintLayerPaintingCompositingScrollingPhase; + + if (graphicsLayer == m_backgroundLayer) + paintFlags |= (RenderLayer::PaintLayerPaintingRootBackgroundOnly | RenderLayer::PaintLayerPaintingCompositingForegroundPhase); // Need PaintLayerPaintingCompositingForegroundPhase to walk child layers. + else if (compositor()->fixedRootBackgroundLayer()) + paintFlags |= RenderLayer::PaintLayerPaintingSkipRootBackground; // FIXME: GraphicsLayers need a way to split for RenderRegions. - RenderLayer::LayerPaintingInfo paintingInfo(rootLayer, paintDirtyRect, paintBehavior, LayoutSize()); + RenderLayer::LayerPaintingInfo paintingInfo(m_owningLayer, paintDirtyRect, paintBehavior, m_subpixelAccumulation); m_owningLayer->paintLayerContents(context, paintingInfo, paintFlags); if (m_owningLayer->containsDirtyOverlayScrollbars()) m_owningLayer->paintLayerContents(context, paintingInfo, paintFlags | RenderLayer::PaintLayerPaintingOverlayScrollbars); + compositor()->didPaintBacking(this); + ASSERT(!m_owningLayer->m_usedTransparency); } @@ -1573,21 +2011,22 @@ void RenderLayerBacking::paintContents(const GraphicsLayer* graphicsLayer, Graph page->setIsPainting(true); #endif - if (graphicsLayer == m_graphicsLayer.get() || graphicsLayer == m_foregroundLayer.get() || graphicsLayer == m_maskLayer.get() || graphicsLayer == m_scrollingContentsLayer.get()) { - InspectorInstrumentationCookie cookie = InspectorInstrumentation::willPaint(m_owningLayer->renderer()->frame()); + if (graphicsLayer == m_graphicsLayer.get() + || graphicsLayer == m_foregroundLayer.get() + || graphicsLayer == m_backgroundLayer.get() + || graphicsLayer == m_maskLayer.get() + || graphicsLayer == m_scrollingContentsLayer.get()) { + InspectorInstrumentation::willPaint(renderer()); // The dirtyRect is in the coords of the painting root. IntRect dirtyRect = clip; if (!(paintingPhase & GraphicsLayerPaintOverflowContents)) - dirtyRect.intersect(compositedBounds()); + dirtyRect.intersect(enclosingIntRect(compositedBounds())); // We have to use the same root as for hit testing, because both methods can compute and cache clipRects. - paintIntoLayer(m_owningLayer, &context, dirtyRect, PaintBehaviorNormal, paintingPhase); - - if (m_usingTiledCacheLayer) - m_owningLayer->renderer()->frame()->view()->setLastPaintTime(currentTime()); + paintIntoLayer(graphicsLayer, &context, dirtyRect, PaintBehaviorNormal, paintingPhase); - InspectorInstrumentation::didPaint(cookie, &context, clip); + InspectorInstrumentation::didPaint(renderer(), &context, clip); } else if (graphicsLayer == layerForHorizontalScrollbar()) { paintScrollbar(m_owningLayer->horizontalScrollbar(), context, clip); } else if (graphicsLayer == layerForVerticalScrollbar()) { @@ -1618,14 +2057,15 @@ float RenderLayerBacking::deviceScaleFactor() const return compositor()->deviceScaleFactor(); } -void RenderLayerBacking::didCommitChangesForLayer(const GraphicsLayer*) const +void RenderLayerBacking::didCommitChangesForLayer(const GraphicsLayer* layer) const { - compositor()->didFlushChangesForLayer(m_owningLayer); + compositor()->didFlushChangesForLayer(m_owningLayer, layer); } bool RenderLayerBacking::getCurrentTransform(const GraphicsLayer* graphicsLayer, TransformationMatrix& transform) const { - if (graphicsLayer != m_graphicsLayer) + GraphicsLayer* transformedLayer = m_contentsContainmentLayer.get() ? m_contentsContainmentLayer.get() : m_graphicsLayer.get(); + if (graphicsLayer != transformedLayer) return false; if (m_owningLayer->hasTransform()) { @@ -1681,39 +2121,31 @@ bool RenderLayerBacking::startAnimation(double timeOffset, const Animation* anim bool isFirstOrLastKeyframe = key == 0 || key == 1; if ((hasTransform && isFirstOrLastKeyframe) || currentKeyframe.containsProperty(CSSPropertyWebkitTransform)) - transformVector.insert(new TransformAnimationValue(key, &(keyframeStyle->transform()), tf)); - + transformVector.insert(TransformAnimationValue::create(key, keyframeStyle->transform(), tf)); + if ((hasOpacity && isFirstOrLastKeyframe) || currentKeyframe.containsProperty(CSSPropertyOpacity)) - opacityVector.insert(new FloatAnimationValue(key, keyframeStyle->opacity(), tf)); + opacityVector.insert(FloatAnimationValue::create(key, keyframeStyle->opacity(), tf)); #if ENABLE(CSS_FILTERS) if ((hasFilter && isFirstOrLastKeyframe) || currentKeyframe.containsProperty(CSSPropertyWebkitFilter)) - filterVector.insert(new FilterAnimationValue(key, &(keyframeStyle->filter()), tf)); + filterVector.insert(FilterAnimationValue::create(key, keyframeStyle->filter(), tf)); #endif } - bool didAnimateTransform = false; - bool didAnimateOpacity = false; -#if ENABLE(CSS_FILTERS) - bool didAnimateFilter = false; -#endif + bool didAnimate = false; if (hasTransform && m_graphicsLayer->addAnimation(transformVector, toRenderBox(renderer())->pixelSnappedBorderBoxRect().size(), anim, keyframes.animationName(), timeOffset)) - didAnimateTransform = true; + didAnimate = true; if (hasOpacity && m_graphicsLayer->addAnimation(opacityVector, IntSize(), anim, keyframes.animationName(), timeOffset)) - didAnimateOpacity = true; + didAnimate = true; #if ENABLE(CSS_FILTERS) if (hasFilter && m_graphicsLayer->addAnimation(filterVector, IntSize(), anim, keyframes.animationName(), timeOffset)) - didAnimateFilter = true; + didAnimate = true; #endif -#if ENABLE(CSS_FILTERS) - return didAnimateTransform || didAnimateOpacity || didAnimateFilter; -#else - return didAnimateTransform || didAnimateOpacity; -#endif + return didAnimate; } void RenderLayerBacking::animationPaused(double timeOffset, const String& animationName) @@ -1728,11 +2160,7 @@ void RenderLayerBacking::animationFinished(const String& animationName) bool RenderLayerBacking::startTransition(double timeOffset, CSSPropertyID property, const RenderStyle* fromStyle, const RenderStyle* toStyle) { - bool didAnimateOpacity = false; - bool didAnimateTransform = false; -#if ENABLE(CSS_FILTERS) - bool didAnimateFilter = false; -#endif + bool didAnimate = false; ASSERT(property != CSSPropertyInvalid); @@ -1740,13 +2168,13 @@ bool RenderLayerBacking::startTransition(double timeOffset, CSSPropertyID proper const Animation* opacityAnim = toStyle->transitionForProperty(CSSPropertyOpacity); if (opacityAnim && !opacityAnim->isEmptyOrZeroDuration()) { KeyframeValueList opacityVector(AnimatedPropertyOpacity); - opacityVector.insert(new FloatAnimationValue(0, compositingOpacity(fromStyle->opacity()))); - opacityVector.insert(new FloatAnimationValue(1, compositingOpacity(toStyle->opacity()))); + opacityVector.insert(FloatAnimationValue::create(0, compositingOpacity(fromStyle->opacity()))); + opacityVector.insert(FloatAnimationValue::create(1, compositingOpacity(toStyle->opacity()))); // The boxSize param is only used for transform animations (which can only run on RenderBoxes), so we pass an empty size here. if (m_graphicsLayer->addAnimation(opacityVector, IntSize(), opacityAnim, GraphicsLayer::animationNameForTransition(AnimatedPropertyOpacity), timeOffset)) { // To ensure that the correct opacity is visible when the animation ends, also set the final opacity. updateOpacity(toStyle); - didAnimateOpacity = true; + didAnimate = true; } } } @@ -1755,12 +2183,12 @@ bool RenderLayerBacking::startTransition(double timeOffset, CSSPropertyID proper const Animation* transformAnim = toStyle->transitionForProperty(CSSPropertyWebkitTransform); if (transformAnim && !transformAnim->isEmptyOrZeroDuration()) { KeyframeValueList transformVector(AnimatedPropertyWebkitTransform); - transformVector.insert(new TransformAnimationValue(0, &fromStyle->transform())); - transformVector.insert(new TransformAnimationValue(1, &toStyle->transform())); + transformVector.insert(TransformAnimationValue::create(0, fromStyle->transform())); + transformVector.insert(TransformAnimationValue::create(1, toStyle->transform())); if (m_graphicsLayer->addAnimation(transformVector, toRenderBox(renderer())->pixelSnappedBorderBoxRect().size(), transformAnim, GraphicsLayer::animationNameForTransition(AnimatedPropertyWebkitTransform), timeOffset)) { // To ensure that the correct transform is visible when the animation ends, also set the final transform. updateTransform(toStyle); - didAnimateTransform = true; + didAnimate = true; } } } @@ -1770,22 +2198,18 @@ bool RenderLayerBacking::startTransition(double timeOffset, CSSPropertyID proper const Animation* filterAnim = toStyle->transitionForProperty(CSSPropertyWebkitFilter); if (filterAnim && !filterAnim->isEmptyOrZeroDuration()) { KeyframeValueList filterVector(AnimatedPropertyWebkitFilter); - filterVector.insert(new FilterAnimationValue(0, &fromStyle->filter())); - filterVector.insert(new FilterAnimationValue(1, &toStyle->filter())); + filterVector.insert(FilterAnimationValue::create(0, fromStyle->filter())); + filterVector.insert(FilterAnimationValue::create(1, toStyle->filter())); if (m_graphicsLayer->addAnimation(filterVector, IntSize(), filterAnim, GraphicsLayer::animationNameForTransition(AnimatedPropertyWebkitFilter), timeOffset)) { // To ensure that the correct filter is visible when the animation ends, also set the final filter. updateFilters(toStyle); - didAnimateFilter = true; + didAnimate = true; } } } #endif -#if ENABLE(CSS_FILTERS) - return didAnimateOpacity || didAnimateTransform || didAnimateFilter; -#else - return didAnimateOpacity || didAnimateTransform; -#endif + return didAnimate; } void RenderLayerBacking::transitionPaused(double timeOffset, CSSPropertyID property) @@ -1807,10 +2231,11 @@ void RenderLayerBacking::notifyAnimationStarted(const GraphicsLayer*, double tim renderer()->animation()->notifyAnimationStarted(renderer(), time); } -void RenderLayerBacking::notifyFlushRequired(const GraphicsLayer*) +void RenderLayerBacking::notifyFlushRequired(const GraphicsLayer* layer) { - if (!renderer()->documentBeingDestroyed()) - compositor()->scheduleLayerFlush(); + if (renderer()->documentBeingDestroyed()) + return; + compositor()->scheduleLayerFlush(layer->canThrottleLayerFlush()); } void RenderLayerBacking::notifyFlushBeforeDisplayRefresh(const GraphicsLayer* layer) @@ -1829,12 +2254,12 @@ void RenderLayerBacking::resumeAnimations() m_graphicsLayer->resumeAnimations(); } -IntRect RenderLayerBacking::compositedBounds() const +LayoutRect RenderLayerBacking::compositedBounds() const { return m_compositedBounds; } -void RenderLayerBacking::setCompositedBounds(const IntRect& bounds) +void RenderLayerBacking::setCompositedBounds(const LayoutRect& bounds) { m_compositedBounds = bounds; } @@ -1885,46 +2310,13 @@ AnimatedPropertyID RenderLayerBacking::cssToGraphicsLayerProperty(CSSPropertyID return AnimatedPropertyInvalid; } -String RenderLayerBacking::nameForLayer() const -{ - StringBuilder name; - name.append(renderer()->renderName()); - if (Node* node = renderer()->node()) { - if (node->isElementNode()) { - name.append(' '); - name.append(static_cast<Element*>(node)->tagName()); - } - if (node->hasID()) { - name.appendLiteral(" id=\'"); - name.append(static_cast<Element*>(node)->getIdAttribute()); - name.append('\''); - } - - if (node->hasClass()) { - name.appendLiteral(" class=\'"); - StyledElement* styledElement = static_cast<StyledElement*>(node); - for (size_t i = 0; i < styledElement->classNames().size(); ++i) { - if (i > 0) - name.append(' '); - name.append(styledElement->classNames()[i]); - } - name.append('\''); - } - } - - if (m_owningLayer->isReflection()) - name.appendLiteral(" (reflection)"); - - return name.toString(); -} - CompositingLayerType RenderLayerBacking::compositingLayerType() const { if (m_graphicsLayer->hasContentsLayer()) return MediaCompositingLayer; if (m_graphicsLayer->drawsContent()) - return m_graphicsLayer->usingTiledLayer() ? TiledCompositingLayer : NormalCompositingLayer; + return m_graphicsLayer->usingTiledBacking() ? TiledCompositingLayer : NormalCompositingLayer; return ContainerCompositingLayer; } @@ -1933,10 +2325,12 @@ double RenderLayerBacking::backingStoreMemoryEstimate() const { double backingMemory; - // m_ancestorClippingLayer and m_containmentLayer are just used for masking or containment, so have no backing. + // m_ancestorClippingLayer, m_contentsContainmentLayer and m_childContainmentLayer are just used for masking or containment, so have no backing. backingMemory = m_graphicsLayer->backingStoreMemoryEstimate(); if (m_foregroundLayer) backingMemory += m_foregroundLayer->backingStoreMemoryEstimate(); + if (m_backgroundLayer) + backingMemory += m_backgroundLayer->backingStoreMemoryEstimate(); if (m_maskLayer) backingMemory += m_maskLayer->backingStoreMemoryEstimate(); @@ -1955,20 +2349,6 @@ double RenderLayerBacking::backingStoreMemoryEstimate() const return backingMemory; } -#if PLATFORM(BLACKBERRY) -bool RenderLayerBacking::contentsVisible(const GraphicsLayer*, const IntRect& localContentRect) const -{ - Frame* frame = renderer()->frame(); - FrameView* view = frame ? frame->view() : 0; - if (!view) - return false; - - IntRect visibleContentRect(view->visibleContentRect()); - FloatQuad absoluteContentQuad = renderer()->localToAbsoluteQuad(FloatRect(localContentRect), SnapOffsetForTransforms); - return absoluteContentQuad.enclosingBoundingBox().intersects(visibleContentRect); -} -#endif - } // namespace WebCore #endif // USE(ACCELERATED_COMPOSITING) |
