Chromium Code Reviews| Index: Source/core/paint/DeprecatedPaintLayerPainter.cpp |
| diff --git a/Source/core/paint/DeprecatedPaintLayerPainter.cpp b/Source/core/paint/DeprecatedPaintLayerPainter.cpp |
| index b3e1e59e9bcc5775b3d71277d7e553ac160d19c4..2202aecab95d1c6ad84411cdcb2394a1dc0eb684 100644 |
| --- a/Source/core/paint/DeprecatedPaintLayerPainter.cpp |
| +++ b/Source/core/paint/DeprecatedPaintLayerPainter.cpp |
| @@ -15,6 +15,7 @@ |
| #include "core/paint/DeprecatedPaintLayer.h" |
| #include "core/paint/FilterPainter.h" |
| #include "core/paint/LayerClipRecorder.h" |
| +#include "core/paint/LayerDescendantClipRecorder.h" |
| #include "core/paint/LayerFixedPositionRecorder.h" |
| #include "core/paint/PaintInfo.h" |
| #include "core/paint/SVGClipPainter.h" |
| @@ -230,7 +231,10 @@ DeprecatedPaintLayerPainter::PaintResult DeprecatedPaintLayerPainter::paintLayer |
| m_paintLayer.stackingNode()->updateLayerListsIfNeeded(); |
| LayoutPoint offsetFromRoot; |
| - m_paintLayer.convertToLayerCoords(paintingInfo.rootLayer, offsetFromRoot); |
| + if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) |
| + m_paintLayer.convertToLayerCoords(paintingInfo.rootLayer, offsetFromRoot, DeprecatedPaintLayer::ExcludeScroll); |
| + else |
| + m_paintLayer.convertToLayerCoords(paintingInfo.rootLayer, offsetFromRoot); |
| if (m_paintLayer.compositingState() == PaintsIntoOwnBacking) |
| offsetFromRoot.move(m_paintLayer.subpixelAccumulation()); |
| @@ -272,10 +276,19 @@ DeprecatedPaintLayerPainter::PaintResult DeprecatedPaintLayerPainter::paintLayer |
| // Collect the fragments. This will compute the clip rectangles and paint offsets for each layer fragment. |
| ClipRectsCacheSlot cacheSlot = (paintFlags & PaintLayerUncachedClipRects) ? UncachedClipRects : PaintingClipRects; |
| ShouldRespectOverflowClip respectOverflowClip = shouldRespectOverflowClip(paintFlags, m_paintLayer.layoutObject()); |
| - if (fragmentPolicy == ForceSingleFragment) |
| + if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) { |
| + // TODO(trchen): Need to handle layer fragmentation. |
|
chrishtr
2015/09/17 18:07:53
How hard will this be? We need a clear plan for it
|
| + DeprecatedPaintLayerFragment fragment; |
| + fragment.layerBounds = LayoutRect(offsetFromRoot, LayoutSize(m_paintLayer.size())); |
| + fragment.backgroundRect = LayoutRect::infiniteRect(); |
| + fragment.foregroundRect = LayoutRect::infiniteRect(); |
| + fragment.outlineRect = LayoutRect::infiniteRect(); |
| + layerFragments.append(fragment); |
| + } else if (fragmentPolicy == ForceSingleFragment) { |
| m_paintLayer.appendSingleFragmentIgnoringPagination(layerFragments, localPaintingInfo.rootLayer, localPaintingInfo.paintDirtyRect, cacheSlot, IgnoreOverlayScrollbarSize, respectOverflowClip, &offsetFromRoot, localPaintingInfo.subPixelAccumulation); |
| - else |
| + } else { |
| m_paintLayer.collectFragments(layerFragments, localPaintingInfo.rootLayer, localPaintingInfo.paintDirtyRect, cacheSlot, IgnoreOverlayScrollbarSize, respectOverflowClip, &offsetFromRoot, localPaintingInfo.subPixelAccumulation); |
| + } |
| if (shouldPaintContent) { |
| // TODO(wangxianzhu): This is for old slow scrolling. Implement similar optimization for slimming paint v2. |
| shouldPaintContent = atLeastOneFragmentIntersectsDamageRect(layerFragments, localPaintingInfo, paintFlags, offsetFromRoot); |
| @@ -350,6 +363,9 @@ DeprecatedPaintLayerPainter::PaintResult DeprecatedPaintLayerPainter::paintLayer |
| bool DeprecatedPaintLayerPainter::needsToClip(const DeprecatedPaintLayerPaintingInfo& localPaintingInfo, const ClipRect& clipRect) |
| { |
| + // With SPv2 a layer clips its descendants so a layer never clips itself. |
| + if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) |
| + return false; |
| return clipRect.rect() != localPaintingInfo.paintDirtyRect || clipRect.hasRadius(); |
| } |
| @@ -473,6 +489,9 @@ DeprecatedPaintLayerPainter::PaintResult DeprecatedPaintLayerPainter::paintChild |
| LayerListMutationDetector mutationChecker(m_paintLayer.stackingNode()); |
| #endif |
| + if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) |
| + return paintChildrenWithFullScrollClipChain(childrenToVisit, context, paintingInfo, paintFlags); |
| + |
| IntSize scrollOffsetAccumulation = paintingInfo.scrollOffsetAccumulation; |
| if (m_paintLayer.layoutObject()->hasOverflowClip()) |
| scrollOffsetAccumulation += m_paintLayer.layoutBox()->scrolledContentOffset(); |
| @@ -499,6 +518,90 @@ DeprecatedPaintLayerPainter::PaintResult DeprecatedPaintLayerPainter::paintChild |
| return result; |
| } |
| +static DeprecatedPaintLayerPainter::PaintResult recursivelyScrollAndPaintChildLayer(Vector<DeprecatedPaintLayer*>& clippingAncestors, DeprecatedPaintLayer& child, GraphicsContext& context, const DeprecatedPaintLayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags, DeprecatedPaintLayer* paintOffsetBase, LayoutPoint paintOffset) |
|
chrishtr
2015/09/17 00:53:46
This looks like a bottom-up approach: when encount
trchen
2015/09/17 01:56:04
Only up to the nearest self-painting ancestor. i.e
|
| +{ |
| + ASSERT(RuntimeEnabledFeatures::slimmingPaintV2Enabled()); |
| + if (clippingAncestors.isEmpty()) |
| + return DeprecatedPaintLayerPainter(child).paintLayer(&context, paintingInfo, paintFlags); |
| + DeprecatedPaintLayer* layer = clippingAncestors.last(); |
| + clippingAncestors.removeLast(); |
| + |
| + ASSERT(layer->layoutObject()->hasOverflowClip() && layer->layoutObject()->isBox()); |
| + layer->convertToLayerCoords(paintOffsetBase, paintOffset, DeprecatedPaintLayer::ExcludeScroll); |
| + LayerDescendantClipRecorder clipRecorder(context, *layer->layoutBox(), paintOffset); |
| +#if ENABLE(ASSERT) |
| + // We want to calculate the current layer position relative to the painting root. |
| + // The conversion above reduces time complexity but is logically incorrect. |
| + // For example if we have layers A, B, C where layer A is the grandparent of layer C, |
| + // we want to first convert from space C->B then B->A. What we do above is actually |
| + // convert from space B->A first then C->B. It works because we assume the conversions |
| + // are all linear translation thus commutative. |
| + LayoutPoint expectedPaintOffset = toLayoutPoint(paintingInfo.subPixelAccumulation); |
| + layer->convertToLayerCoords(paintingInfo.rootLayer, expectedPaintOffset, DeprecatedPaintLayer::ExcludeScroll); |
| + ASSERT(paintOffset == expectedPaintOffset); |
| +#endif |
| + |
| + IntSize scrollOffset = layer->layoutBox()->scrolledContentOffset(); |
| + Optional<ScrollRecorder> scrollRecorder; |
| + if (layer->scrollsOverflow() || !scrollOffset.isZero()) |
| + scrollRecorder.emplace(context, *layer->layoutObject(), PaintPhaseBlockBackground, scrollOffset); |
| + return recursivelyScrollAndPaintChildLayer(clippingAncestors, child, context, paintingInfo, paintFlags, layer, paintOffset); |
| +} |
| + |
| +static void collectClippingLayersBetween(Vector<DeprecatedPaintLayer*> &clippingAncestors, DeprecatedPaintLayer* layer, DeprecatedPaintLayer* ancestor) |
|
chrishtr
2015/09/17 00:53:46
This function is doing almost (exactly?) the same
trchen
2015/09/17 01:56:04
Yep. Albeit we don't try to collapse clip rects ri
|
| +{ |
| + while (layer && layer != ancestor) { |
| + EPosition position = layer->layoutObject()->style()->position(); |
| + ASSERT(position != FixedPosition); |
| + |
| + DeprecatedPaintLayer* container = nullptr; |
| + if (position == AbsolutePosition) { |
| + bool ranPastThisLayer; |
| + container = layer->enclosingPositionedAncestor(ancestor, &ranPastThisLayer); |
| + if (ranPastThisLayer) |
| + break; |
| + } else { |
| + container = layer->parent(); |
| + } |
| + if (!container) |
| + break; |
| + |
| + if (container->layoutObject()->hasOverflowClip()) |
|
chrishtr
2015/09/17 18:07:53
What about css clip and clip-path?
|
| + clippingAncestors.append(container); |
| + |
| + layer = container; |
| + } |
| +} |
| + |
| +// TODO(trchen): Measure performance of this and implement display item de-duping if needed. |
| +// For the pessimistic case this function will generate O(n^2) of clip/scroll pairs, for example: |
| +// <div style="overflow:scroll;"> * repeat 100 times |
| +// <div style="position:relative;"></div> * repeat 100 times |
| +// We will need to generate 100 clip/scroll pairs for each of the in-flow positioned children. |
| +DeprecatedPaintLayerPainter::PaintResult DeprecatedPaintLayerPainter::paintChildrenWithFullScrollClipChain(unsigned childrenToVisit, GraphicsContext* context, const DeprecatedPaintLayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags) |
|
chrishtr
2015/09/22 18:32:56
Let's implement an optimization here: between pain
|
| +{ |
| + PaintResult result = FullyPainted; |
| + ASSERT(RuntimeEnabledFeatures::slimmingPaintV2Enabled()); |
| + |
| + DeprecatedPaintLayerStackingNodeIterator iterator(*m_paintLayer.stackingNode(), childrenToVisit); |
| + while (DeprecatedPaintLayerStackingNode* childNode = iterator.next()) { |
| + DeprecatedPaintLayer* child = childNode->layer(); |
| + EPosition childPosition = child->layoutObject()->style()->position(); |
| + if (childPosition == FixedPosition) { |
| + // TODO(trchen): Fixed position needs to be implemented here. |
|
chrishtr
2015/09/17 18:07:53
We need a plan for how to do it before committing
chrishtr
2015/09/22 18:32:56
On reflection, I think fixed position shouldn't be
|
| + if (DeprecatedPaintLayerPainter(*child).paintLayer(context, paintingInfo, paintFlags) == MaybeNotFullyPainted) |
| + result = MaybeNotFullyPainted; |
| + continue; |
| + } |
| + |
| + Vector<DeprecatedPaintLayer*> clippingAncestors; |
| + collectClippingLayersBetween(clippingAncestors, child, &m_paintLayer); |
| + if (recursivelyScrollAndPaintChildLayer(clippingAncestors, *child, *context, paintingInfo, paintFlags, paintingInfo.rootLayer, toLayoutPoint(paintingInfo.subPixelAccumulation)) == MaybeNotFullyPainted) |
| + result = MaybeNotFullyPainted; |
| + } |
| + return result; |
| +} |
| + |
| // FIXME: inline this. |
| static bool paintForFixedRootBackground(const DeprecatedPaintLayer* layer, PaintLayerFlags paintFlags) |
| { |
| @@ -536,6 +639,13 @@ void DeprecatedPaintLayerPainter::paintFragmentWithPhase(PaintPhase phase, const |
| { |
| ASSERT(m_paintLayer.isSelfPaintingLayer()); |
| + if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) { |
| + PaintInfo paintInfo(context, enclosingIntRect(paintingInfo.paintDirtyRect), phase, paintingInfo.globalPaintFlags(), paintFlags, paintingRootForLayoutObject, paintingInfo.rootLayer->layoutObject()); |
| + LayoutPoint paintOffset = toPoint(fragment.layerBounds.location() - m_paintLayer.layoutBoxLocation()); |
| + m_paintLayer.layoutObject()->paint(paintInfo, paintOffset); |
| + return; |
| + } |
| + |
| Optional<LayerClipRecorder> clipRecorder; |
| if (clipState != HasClipped && paintingInfo.clipToDirtyRect && needsToClip(paintingInfo, clipRect)) { |
| DisplayItem::Type clipType = DisplayItem::paintPhaseToClipLayerFragmentType(phase); |