DisplayCSSPainter.cpp [plain text]
#include "config.h"
#include "DisplayCSSPainter.h"
#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
#include "DisplayBoxClip.h"
#include "DisplayBoxPainter.h"
#include "DisplayBoxRareGeometry.h"
#include "DisplayContainerBox.h"
#include "DisplayPaintingContext.h"
#include "DisplayStackingItem.h"
#include "DisplayStyle.h"
#include "DisplayTree.h"
#include "GraphicsContext.h"
#include "IntRect.h"
#include "TransformationMatrix.h"
#define SHOW_ITEM_EXTENTS 0
namespace WebCore {
namespace Display {
static void applyClipIfNecessary(const Box& box, PaintingContext& paintingContext, GraphicsContextStateSaver& stateSaver)
{
if (is<BoxModelBox>(box) && box.style().hasClippedOverflow()) {
stateSaver.save();
auto roundedInnerBorder = downcast<BoxModelBox>(box).innerBorderRoundedRect();
paintingContext.context.clipRoundedRect(roundedInnerBorder);
}
}
static void applyAncestorClip(const BoxModelBox& box, PaintingContext& paintingContext)
{
auto* boxClip = box.ancestorClip();
if (!boxClip || !boxClip->clipRect())
return;
if (!boxClip->affectedByBorderRadius()) {
paintingContext.context.clip(*boxClip->clipRect());
return;
}
for (auto& roundedRect : boxClip->clipStack())
paintingContext.context.clipRoundedRect(roundedRect);
}
static void applyEffects(const StackingItem& stackingItem, const Box& box, PaintingContext& paintingContext, TransparencyLayerScope& transparencyScope)
{
if (box.style().opacity() < 1) {
paintingContext.context.clip(stackingItem.paintedBoundsIncludingDescendantItems());
transparencyScope.beginLayer(box.style().opacity());
}
}
void CSSPainter::recursivePaintDescendantsForPhase(const ContainerBox& containerBox, PaintingContext& paintingContext, PaintPhase paintPhase)
{
auto stateSaver = GraphicsContextStateSaver { paintingContext.context, false };
applyClipIfNecessary(containerBox, paintingContext, stateSaver);
for (const auto* child = containerBox.firstChild(); child; child = child->nextSibling()) {
auto& box = *child;
ASSERT(!box.participatesInZOrderSorting());
switch (paintPhase) {
case PaintPhase::BlockBackgrounds:
if (!box.style().isFloating() && !box.style().isPositioned() && is<BoxModelBox>(box))
BoxPainter::paintBoxDecorations(downcast<BoxModelBox>(box), paintingContext);
break;
case PaintPhase::Floats:
if (box.style().isFloating() && !box.style().isPositioned() && is<BoxModelBox>(box))
BoxPainter::paintBoxDecorations(downcast<BoxModelBox>(box), paintingContext);
break;
case PaintPhase::BlockForegrounds:
if (!box.style().isFloating() && !box.style().isPositioned())
BoxPainter::paintBoxContent(box, paintingContext);
};
if (is<ContainerBox>(box))
recursivePaintDescendantsForPhase(downcast<ContainerBox>(box), paintingContext, paintPhase);
}
}
void CSSPainter::recursivePaintDescendants(const ContainerBox& containerBox, PaintingContext& paintingContext)
{
recursivePaintDescendantsForPhase(containerBox, paintingContext, PaintPhase::BlockBackgrounds);
recursivePaintDescendantsForPhase(containerBox, paintingContext, PaintPhase::Floats);
recursivePaintDescendantsForPhase(containerBox, paintingContext, PaintPhase::BlockForegrounds);
}
void CSSPainter::paintAtomicallyPaintedBox(const StackingItem& stackingItem, PaintingContext& paintingContext, const IntRect& dirtyRect, IncludeStackingContextDescendants includeStackingContextDescendants)
{
UNUSED_PARAM(dirtyRect);
auto& box = stackingItem.box();
auto needToSaveState = [](const Box& box) {
if (!is<BoxModelBox>(box))
return false;
auto& boxModelBox = downcast<BoxModelBox>(box);
return boxModelBox.hasAncestorClip() || boxModelBox.style().hasTransform() || boxModelBox.style().opacity() < 1;
};
auto stateSaver = GraphicsContextStateSaver { paintingContext.context, needToSaveState(box) };
if (is<BoxModelBox>(box))
applyAncestorClip(downcast<BoxModelBox>(box), paintingContext);
if (is<BoxModelBox>(box) && box.style().hasTransform()) {
auto transformationMatrix = downcast<BoxModelBox>(box).rareGeometry()->transform();
auto absoluteBorderBox = box.absoluteBoxRect();
transformationMatrix.translateRight(absoluteBorderBox.x(), absoluteBorderBox.y());
transformationMatrix.translate(-absoluteBorderBox.x(), -absoluteBorderBox.y());
auto affineTransform = transformationMatrix.toAffineTransform();
paintingContext.context.concatCTM(affineTransform);
}
auto transparencyScope = TransparencyLayerScope { paintingContext.context, 1, false };
applyEffects(stackingItem, box, paintingContext, transparencyScope);
#if SHOW_ITEM_EXTENTS
{
GraphicsContextStateSaver saver(paintingContext.context);
paintingContext.context.setStrokeColor(Color::gray);
paintingContext.context.strokeRect(stackingItem.paintedBoundsIncludingDescendantItems(), 1);
}
#endif
BoxPainter::paintBox(box, paintingContext, dirtyRect);
if (!is<ContainerBox>(box))
return;
if (includeStackingContextDescendants == IncludeStackingContextDescendants::Yes) {
for (auto& stackingItem : stackingItem.negativeZOrderList())
paintStackingContext(*stackingItem, paintingContext, dirtyRect);
}
auto& containerBox = downcast<ContainerBox>(box);
recursivePaintDescendants(containerBox, paintingContext);
if (includeStackingContextDescendants == IncludeStackingContextDescendants::Yes) {
for (auto& stackingItem : stackingItem.positiveZOrderList()) {
if (stackingItem->isStackingContext())
paintStackingContext(*stackingItem, paintingContext, dirtyRect);
else
paintAtomicallyPaintedBox(*stackingItem, paintingContext, dirtyRect);
}
}
}
void CSSPainter::paintStackingContext(const StackingItem& stackingItem, PaintingContext& paintingContext, const IntRect& dirtyRect)
{
paintAtomicallyPaintedBox(stackingItem, paintingContext, dirtyRect, IncludeStackingContextDescendants::Yes);
}
void CSSPainter::paintTree(const Tree& displayTree, PaintingContext& paintingContext, const IntRect& dirtyRect)
{
paintStackingContext(displayTree.rootStackingItem(), paintingContext, dirtyRect);
}
} }
#endif // ENABLE(LAYOUT_FORMATTING_CONTEXT)