Skip to content

Commit

Permalink
Move more painting code to BackgroundPainter
Browse files Browse the repository at this point in the history
https://bugs.webkit.org/show_bug.cgi?id=244927
<rdar://problem/99735898>.

Reviewed by Alan Bujtas.

Move more background painting code out from RenderObjects to a dedicated painter class.

* Source/WebCore/rendering/BackgroundPainter.cpp:
(WebCore::BackgroundImageGeometry::BackgroundImageGeometry):
(WebCore::BackgroundPainter::paintFillLayers):
(WebCore::BackgroundPainter::paintFillLayer):
(WebCore::BackgroundPainter::backgroundRoundedRectAdjustedForBleedAvoidance const):
(WebCore::BackgroundPainter::backgroundRoundedRect const):
(WebCore::getSpace):
(WebCore::resolveEdgeRelativeLength):
(WebCore::pixelSnapBackgroundImageGeometryForPainting):
(WebCore::BackgroundPainter::calculateBackgroundImageGeometry):
(WebCore::BackgroundPainter::calculateFillTileSize):
(WebCore::BackgroundPainter::getBackgroundRoundedRect const): Deleted.
* Source/WebCore/rendering/BackgroundPainter.h:
(WebCore::BackgroundImageGeometry::relativePhase const):
(WebCore::BackgroundImageGeometry::clip):

Make BackgroundImageGeometry a struct and add tileSizeWithoutPixelSnapping so calculateBackgroundImageGeometry
can return it and does not need to deal with updating SVG container context itself.

* Source/WebCore/rendering/InlineBoxPainter.cpp:
(WebCore::InlineBoxPainter::paintFillLayers):
* Source/WebCore/rendering/RenderBox.cpp:
(WebCore::RenderBox::paintRootBoxFillLayers):
(WebCore::RenderBox::paintBackground):
(WebCore::RenderBox::getBackgroundPaintedExtent const):
(WebCore::RenderBox::paintMaskImages):
(WebCore::RenderBox::maskClipRect):
(WebCore::RenderBox::repaintLayerRectsForImage):
(WebCore::RenderBox::paintFillLayers): Deleted.
* Source/WebCore/rendering/RenderBox.h:
* Source/WebCore/rendering/RenderBoxModelObject.cpp:
(WebCore::RenderBoxModelObject::calculateFillTileSize const): Deleted.
(WebCore::pixelSnapBackgroundImageGeometryForPainting): Deleted.
(WebCore::getSpace): Deleted.
(WebCore::resolveEdgeRelativeLength): Deleted.
(WebCore::RenderBoxModelObject::calculateBackgroundImageGeometry const): Deleted.
(WebCore::RenderBoxModelObject::getGeometryForBackgroundImage const): Deleted.
* Source/WebCore/rendering/RenderBoxModelObject.h:
(WebCore::BackgroundImageGeometry::BackgroundImageGeometry): Deleted.
(WebCore::BackgroundImageGeometry::destRect const): Deleted.
(WebCore::BackgroundImageGeometry::phase const): Deleted.
(WebCore::BackgroundImageGeometry::tileSize const): Deleted.
(WebCore::BackgroundImageGeometry::spaceSize const): Deleted.
(WebCore::BackgroundImageGeometry::hasNonLocalGeometry const): Deleted.
(WebCore::BackgroundImageGeometry::relativePhase const): Deleted.
(WebCore::BackgroundImageGeometry::clip): Deleted.
* Source/WebCore/rendering/RenderLayerBacking.cpp:
(WebCore::RenderLayerBacking::updateDirectlyCompositedBackgroundImage):
* Source/WebCore/rendering/RenderTableCell.cpp:
(WebCore::RenderTableCell::paintBackgroundsBehindCell):

Canonical link: https://commits.webkit.org/254301@main
  • Loading branch information
anttijk committed Sep 9, 2022
1 parent 2381699 commit da7f1ab
Show file tree
Hide file tree
Showing 9 changed files with 403 additions and 420 deletions.
362 changes: 354 additions & 8 deletions Source/WebCore/rendering/BackgroundPainter.cpp

Large diffs are not rendered by default.

27 changes: 26 additions & 1 deletion Source/WebCore/rendering/BackgroundPainter.h
Expand Up @@ -27,17 +27,42 @@

namespace WebCore {

struct BackgroundImageGeometry {
BackgroundImageGeometry(const LayoutRect& destinationRect, const LayoutSize& tileSizeWithoutPixelSnapping, const LayoutSize& tileSize, const LayoutSize& phase, const LayoutSize& spaceSize, bool fixedAttachment);

LayoutSize relativePhase() const
{
LayoutSize relativePhase = phase;
relativePhase += destinationRect.location() - destinationOrigin;
return relativePhase;
}

void clip(const LayoutRect& clipRect) { destinationRect.intersect(clipRect); }

LayoutRect destinationRect;
LayoutPoint destinationOrigin;
LayoutSize tileSizeWithoutPixelSnapping;
LayoutSize tileSize;
LayoutSize phase;
LayoutSize spaceSize;
bool hasNonLocalGeometry; // Has background-attachment: fixed. Implies that we can't always cheaply compute destRect.
};

class BackgroundPainter {
public:
BackgroundPainter(RenderBoxModelObject&, const PaintInfo&);

void paintFillLayers(const Color&, const FillLayer&, const LayoutRect&, BackgroundBleedAvoidance, CompositeOperator, RenderElement* backgroundObject = nullptr);
void paintFillLayer(const Color&, const FillLayer&, const LayoutRect&, BackgroundBleedAvoidance, const InlineIterator::InlineBoxIterator&, const LayoutRect& backgroundImageStrip = { }, CompositeOperator = CompositeOperator::SourceOver, RenderElement* backgroundObject = nullptr, BaseBackgroundColorUsage = BaseBackgroundColorUse);

static BackgroundImageGeometry calculateBackgroundImageGeometry(const RenderBoxModelObject&, const RenderLayerModelObject* paintContainer, const FillLayer&, const LayoutPoint& paintOffset, const LayoutRect& borderBoxRect);
static void clipRoundedInnerRect(GraphicsContext&, const FloatRect&, const FloatRoundedRect& clipRect);

private:
RoundedRect backgroundRoundedRectAdjustedForBleedAvoidance(const LayoutRect& borderRect, BackgroundBleedAvoidance, const InlineIterator::InlineBoxIterator&, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const;
RoundedRect getBackgroundRoundedRect(const LayoutRect& borderRect, const InlineIterator::InlineBoxIterator&, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const;
RoundedRect backgroundRoundedRect(const LayoutRect& borderRect, const InlineIterator::InlineBoxIterator&, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const;

static LayoutSize calculateFillTileSize(const RenderBoxModelObject&, const FillLayer&, const LayoutSize& positioningAreaSize);

const Document& document() const;
const RenderView& view() const;
Expand Down
4 changes: 2 additions & 2 deletions Source/WebCore/rendering/InlineBoxPainter.cpp
Expand Up @@ -287,8 +287,8 @@ void InlineBoxPainter::paintFillLayers(const Color& color, const FillLayer& fill
Vector<const FillLayer*, 8> layers;
for (auto* layer = &fillLayer; layer; layer = layer->next())
layers.append(layer);
layers.reverse();
for (auto* layer : layers)

for (auto* layer : makeReversedRange(layers))
paintFillLayer(color, *layer, rect, op);
}

Expand Down
65 changes: 11 additions & 54 deletions Source/WebCore/rendering/RenderBox.cpp
Expand Up @@ -1610,7 +1610,7 @@ void RenderBox::paintRootBoxFillLayers(const PaintInfo& paintInfo)
auto color = style.visitedDependentColor(CSSPropertyBackgroundColor);
auto compositeOp = document().compositeOperatorForBackgroundColor(color, *this);

paintFillLayers(paintInfo, style.colorByApplyingColorFilter(color), style.backgroundLayers(), view().backgroundRect(), BackgroundBleedNone, compositeOp, rootBackgroundRenderer);
BackgroundPainter { *this, paintInfo }.paintFillLayers(style.colorByApplyingColorFilter(color), style.backgroundLayers(), view().backgroundRect(), BackgroundBleedNone, compositeOp, rootBackgroundRenderer);
}

BackgroundBleedAvoidance RenderBox::determineBackgroundBleedAvoidance(GraphicsContext& context) const
Expand Down Expand Up @@ -1736,7 +1736,7 @@ void RenderBox::paintBackground(const PaintInfo& paintInfo, const LayoutRect& pa
auto backgroundColor = style().visitedDependentColor(CSSPropertyBackgroundColor);
auto compositeOp = document().compositeOperatorForBackgroundColor(backgroundColor, *this);

paintFillLayers(paintInfo, style().colorByApplyingColorFilter(backgroundColor), style().backgroundLayers(), paintRect, bleedAvoidance, compositeOp);
BackgroundPainter { *this, paintInfo }.paintFillLayers(style().colorByApplyingColorFilter(backgroundColor), style().backgroundLayers(), paintRect, bleedAvoidance, compositeOp);
}

bool RenderBox::getBackgroundPaintedExtent(const LayoutPoint& paintOffset, LayoutRect& paintedExtent) const
Expand All @@ -1756,9 +1756,9 @@ bool RenderBox::getBackgroundPaintedExtent(const LayoutPoint& paintOffset, Layou
return true;
}

auto geometry = calculateBackgroundImageGeometry(nullptr, layers, paintOffset, backgroundRect);
paintedExtent = geometry.destRect();
return !geometry.hasNonLocalGeometry();
auto geometry = BackgroundPainter::calculateBackgroundImageGeometry(*this, nullptr, layers, paintOffset, backgroundRect);
paintedExtent = geometry.destinationRect;
return !geometry.hasNonLocalGeometry;
}

bool RenderBox::backgroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect) const
Expand Down Expand Up @@ -1947,7 +1947,7 @@ void RenderBox::paintMaskImages(const PaintInfo& paintInfo, const LayoutRect& pa
}

if (allMaskImagesLoaded) {
paintFillLayers(paintInfo, Color(), style().maskLayers(), paintRect, BackgroundBleedNone, compositeOp);
BackgroundPainter { *this, paintInfo }.paintFillLayers(Color(), style().maskLayers(), paintRect, BackgroundBleedNone, compositeOp);
BorderPainter { *this, paintInfo }.paintNinePieceImage(paintRect, style(), style().maskBoxImage(), compositeOp);
}

Expand All @@ -1971,55 +1971,12 @@ LayoutRect RenderBox::maskClipRect(const LayoutPoint& paintOffset)
for (auto* maskLayer = &style().maskLayers(); maskLayer; maskLayer = maskLayer->next()) {
if (maskLayer->image()) {
// Masks should never have fixed attachment, so it's OK for paintContainer to be null.
result.unite(calculateBackgroundImageGeometry(nullptr, *maskLayer, paintOffset, borderBox).destRect());
result.unite(BackgroundPainter::calculateBackgroundImageGeometry(*this, nullptr, *maskLayer, paintOffset, borderBox).destinationRect);
}
}
return result;
}

void RenderBox::paintFillLayers(const PaintInfo& paintInfo, const Color& color, const FillLayer& fillLayer, const LayoutRect& rect,
BackgroundBleedAvoidance bleedAvoidance, CompositeOperator op, RenderElement* backgroundObject)
{
Vector<const FillLayer*, 8> layers;
bool shouldDrawBackgroundInSeparateBuffer = false;

for (auto* layer = &fillLayer; layer; layer = layer->next()) {
layers.append(layer);

if (layer->blendMode() != BlendMode::Normal)
shouldDrawBackgroundInSeparateBuffer = true;

// Stop traversal when an opaque layer is encountered.
// FIXME: It would be possible for the following occlusion culling test to be more aggressive
// on layers with no repeat by testing whether the image covers the layout rect.
// Testing that here would imply duplicating a lot of calculations that are currently done in
// BackgroundPainter::paintFillLayer. A more efficient solution might be to move
// the layer recursion into paintFillLayer, or to compute the layer geometry here
// and pass it down.

// The clipOccludesNextLayers condition must be evaluated first to avoid short-circuiting.
if (layer->clipOccludesNextLayers(layer == &fillLayer) && layer->hasOpaqueImage(*this) && layer->image()->canRender(this, style().effectiveZoom()) && layer->hasRepeatXY() && layer->blendMode() == BlendMode::Normal)
break;
}

auto& context = paintInfo.context();
auto baseBgColorUsage = BaseBackgroundColorUse;

BackgroundPainter backgroundPainter { *this, paintInfo };

if (shouldDrawBackgroundInSeparateBuffer) {
backgroundPainter.paintFillLayer(color, *layers.last(), rect, bleedAvoidance, { }, { }, op, backgroundObject, BaseBackgroundColorOnly);
baseBgColorUsage = BaseBackgroundColorSkip;
context.beginTransparencyLayer(1);
}

for (auto& layer : makeReversedRange(layers))
backgroundPainter.paintFillLayer(color, *layer, rect, bleedAvoidance, { }, { }, op, backgroundObject, baseBgColorUsage);

if (shouldDrawBackgroundInSeparateBuffer)
context.endTransparencyLayer();
}

static StyleImage* findLayerUsedImage(WrappedImagePtr image, const FillLayer& layers)
{
for (auto* layer = &layers; layer; layer = layer->next()) {
Expand Down Expand Up @@ -2107,15 +2064,15 @@ bool RenderBox::repaintLayerRectsForImage(WrappedImagePtr image, const FillLayer
}
}
// FIXME: Figure out how to pass absolute position to calculateBackgroundImageGeometry (for pixel snapping)
BackgroundImageGeometry geometry = layerRenderer->calculateBackgroundImageGeometry(nullptr, *layer, LayoutPoint(), rendererRect);
if (geometry.hasNonLocalGeometry()) {
auto geometry = BackgroundPainter::calculateBackgroundImageGeometry(*layerRenderer, nullptr, *layer, LayoutPoint(), rendererRect);
if (geometry.hasNonLocalGeometry) {
// Rather than incur the costs of computing the paintContainer for renderers with fixed backgrounds
// in order to get the right destRect, just repaint the entire renderer.
layerRenderer->repaint();
return true;
}

LayoutRect rectToRepaint = geometry.destRect();
LayoutRect rectToRepaint = geometry.destinationRect;
bool shouldClipToLayer = true;

// If this is the root background layer, we may need to extend the repaintRect if the FrameView has an
Expand All @@ -2135,7 +2092,7 @@ bool RenderBox::repaintLayerRectsForImage(WrappedImagePtr image, const FillLayer
}

layerRenderer->repaintRectangle(rectToRepaint, shouldClipToLayer);
if (geometry.destRect() == rendererRect)
if (geometry.destinationRect == rendererRect)
return true;
}
}
Expand Down
3 changes: 0 additions & 3 deletions Source/WebCore/rendering/RenderBox.h
Expand Up @@ -691,9 +691,6 @@ override;
bool computeBackgroundIsKnownToBeObscured(const LayoutPoint& paintOffset) override;

void paintBackground(const PaintInfo&, const LayoutRect&, BackgroundBleedAvoidance = BackgroundBleedNone);

void paintFillLayers(const PaintInfo&, const Color&, const FillLayer&, const LayoutRect&, BackgroundBleedAvoidance = BackgroundBleedNone, CompositeOperator = CompositeOperator::SourceOver, RenderElement* backgroundObject = nullptr);

void paintMaskImages(const PaintInfo&, const LayoutRect&);

BackgroundBleedAvoidance determineBackgroundBleedAvoidance(GraphicsContext&) const;
Expand Down

0 comments on commit da7f1ab

Please sign in to comment.