DisplayBoxFactory.cpp [plain text]
#include "config.h"
#include "DisplayBoxFactory.h"
#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
#include "DisplayBoxClip.h"
#include "DisplayBoxDecorationData.h"
#include "DisplayBoxDecorationPainter.h"
#include "DisplayBoxRareGeometry.h"
#include "DisplayContainerBox.h"
#include "DisplayFillLayerImageGeometry.h"
#include "DisplayImageBox.h"
#include "DisplayTextBox.h"
#include "DisplayTree.h"
#include "DisplayTreeBuilder.h"
#include "FloatPoint3D.h"
#include "InlineLineGeometry.h"
#include "LayoutBoxGeometry.h"
#include "LayoutContainerBox.h"
#include "LayoutInitialContainingBlock.h"
#include "LayoutReplacedBox.h"
#include "Logging.h"
#include "TransformationMatrix.h"
namespace WebCore {
namespace Display {
BoxFactory::BoxFactory(TreeBuilder& builder, float pixelSnappingFactor)
: m_treeBuilder(builder)
, m_pixelSnappingFactor(pixelSnappingFactor)
{
}
RootBackgroundPropagation BoxFactory::determineRootBackgroundPropagation(const Layout::ContainerBox& rootLayoutBox)
{
auto* documentElementBox = documentElementBoxFromRootBox(rootLayoutBox);
auto* bodyBox = bodyBoxFromRootBox(rootLayoutBox);
if (documentElementBox && documentElementBox->style().hasBackground())
return RootBackgroundPropagation::None;
if (bodyBox && bodyBox->style().hasBackground())
return RootBackgroundPropagation::BodyToRoot;
return RootBackgroundPropagation::None;
}
std::unique_ptr<ContainerBox> BoxFactory::displayBoxForRootBox(const Layout::ContainerBox& rootLayoutBox, const Layout::BoxGeometry& geometry, RootBackgroundPropagation rootBackgroundPropagation) const
{
ASSERT(is<Layout::InitialContainingBlock>(rootLayoutBox));
auto borderBoxRect = LayoutRect { Layout::BoxGeometry::borderBoxRect(geometry) };
auto* documentElementBox = documentElementBoxFromRootBox(rootLayoutBox);
const RenderStyle* styleForBackground = documentElementBox ? &documentElementBox->style() : nullptr;
if (rootBackgroundPropagation == RootBackgroundPropagation::BodyToRoot) {
if (auto* bodyBox = bodyBoxFromRootBox(rootLayoutBox))
styleForBackground = &bodyBox->style();
}
auto style = Style { rootLayoutBox.style(), styleForBackground };
auto rootBox = makeUnique<ContainerBox>(m_treeBuilder.tree(), snapRectToDevicePixels(borderBoxRect, m_pixelSnappingFactor), WTFMove(style));
setupBoxModelBox(*rootBox, rootLayoutBox, geometry, { *rootBox, { 0, 0 } }, styleForBackground);
return rootBox;
}
std::unique_ptr<Box> BoxFactory::displayBoxForBodyBox(const Layout::Box& layoutBox, const Layout::BoxGeometry& geometry, const ContainingBlockContext& containingBlockContext, RootBackgroundPropagation rootBackgroundPropagation) const
{
const RenderStyle* styleForBackground = &layoutBox.style();
if (rootBackgroundPropagation == RootBackgroundPropagation::BodyToRoot)
styleForBackground = nullptr;
auto style = Style { layoutBox.style(), styleForBackground };
return displayBoxForLayoutBox(layoutBox, geometry, containingBlockContext, styleForBackground, WTFMove(style));
}
std::unique_ptr<Box> BoxFactory::displayBoxForLayoutBox(const Layout::Box& layoutBox, const Layout::BoxGeometry& geometry, const ContainingBlockContext& containingBlockContext) const
{
auto style = Style { layoutBox.style() };
return displayBoxForLayoutBox(layoutBox, geometry, containingBlockContext, &layoutBox.style(), WTFMove(style));
}
std::unique_ptr<Box> BoxFactory::displayBoxForLayoutBox(const Layout::Box& layoutBox, const Layout::BoxGeometry& geometry, const ContainingBlockContext& containingBlockContext, const RenderStyle* styleForBackground, Style&& style) const
{
auto borderBoxRect = LayoutRect { Layout::BoxGeometry::borderBoxRect(geometry) };
borderBoxRect.move(containingBlockContext.offsetFromRoot);
auto pixelSnappedBorderBoxRect = snapRectToDevicePixels(borderBoxRect, m_pixelSnappingFactor);
if (is<Layout::ReplacedBox>(layoutBox)) {
RefPtr<Image> image;
if (auto* cachedImage = downcast<Layout::ReplacedBox>(layoutBox).cachedImage())
image = cachedImage->image();
auto imageBox = makeUnique<ImageBox>(m_treeBuilder.tree(), pixelSnappedBorderBoxRect, WTFMove(style), WTFMove(image));
setupBoxModelBox(*imageBox, layoutBox, geometry, containingBlockContext, styleForBackground);
return imageBox;
}
if (is<Layout::ContainerBox>(layoutBox)) {
auto containerBox = makeUnique<ContainerBox>(m_treeBuilder.tree(), pixelSnappedBorderBoxRect, WTFMove(style));
setupBoxModelBox(*containerBox, layoutBox, geometry, containingBlockContext, styleForBackground);
return containerBox;
}
OptionSet<Box::TypeFlags> flags;
if (layoutBox.isLineBreakBox())
flags.add(Box::TypeFlags::LineBreakBox);
return makeUnique<Box>(m_treeBuilder.tree(), snapRectToDevicePixels(borderBoxRect, m_pixelSnappingFactor), WTFMove(style), flags);
}
std::unique_ptr<Box> BoxFactory::displayBoxForTextRun(const Layout::LineRun& run, const Layout::InlineLineGeometry& lineGeometry, const ContainingBlockContext& containingBlockContext) const
{
ASSERT(run.text());
auto lineRect = lineGeometry.lineBoxLogicalRect();
auto lineLayoutRect = LayoutRect { lineRect.left(), lineRect.top(), lineRect.width(), lineRect.height() };
auto runRect = LayoutRect { run.logicalLeft(), run.logicalTop(), run.logicalWidth(), run.logicalHeight() };
runRect.moveBy(lineLayoutRect.location());
runRect.move(containingBlockContext.offsetFromRoot);
auto style = Style { run.layoutBox().style() };
return makeUnique<TextBox>(m_treeBuilder.tree(), snapRectToDevicePixels(runRect, m_pixelSnappingFactor), WTFMove(style), run);
}
void BoxFactory::setupBoxGeometry(BoxModelBox& box, const Layout::Box&, const Layout::BoxGeometry& layoutGeometry, const ContainingBlockContext& containingBlockContext) const
{
auto borderBoxRect = LayoutRect { Layout::BoxGeometry::borderBoxRect(layoutGeometry) };
borderBoxRect.move(containingBlockContext.offsetFromRoot);
auto paddingBoxRect = LayoutRect { layoutGeometry.paddingBox() };
paddingBoxRect.moveBy(borderBoxRect.location());
box.setAbsolutePaddingBoxRect(snapRectToDevicePixels(paddingBoxRect, m_pixelSnappingFactor));
auto contentBoxRect = LayoutRect { layoutGeometry.contentBox() };
contentBoxRect.moveBy(borderBoxRect.location());
box.setAbsoluteContentBoxRect(snapRectToDevicePixels(contentBoxRect, m_pixelSnappingFactor));
if (is<ReplacedBox>(box)) {
auto& replacedBox = downcast<ReplacedBox>(box);
auto replacedContentRect = LayoutRect { layoutGeometry.contentBoxLeft(), layoutGeometry.contentBoxTop(), layoutGeometry.contentBoxWidth(), layoutGeometry.contentBoxHeight() };
replacedContentRect.moveBy(borderBoxRect.location());
auto pixelSnappedReplacedContentRect = snapRectToDevicePixels(replacedContentRect, m_pixelSnappingFactor);
replacedBox.setReplacedContentRect(pixelSnappedReplacedContentRect);
}
}
std::unique_ptr<BoxDecorationData> BoxFactory::constructBoxDecorationData(const Layout::Box& layoutBox, const Layout::BoxGeometry& layoutGeometry, const RenderStyle* styleForBackground, LayoutSize offsetFromRoot) const
{
auto boxDecorationData = makeUnique<BoxDecorationData>();
if (styleForBackground) {
auto backgroundImageGeometry = calculateFillLayerImageGeometry(*styleForBackground, layoutGeometry, offsetFromRoot, m_pixelSnappingFactor);
boxDecorationData->setBackgroundImageGeometry(WTFMove(backgroundImageGeometry));
}
bool includeLogicalLeftEdge = true; bool includeLogicalRightEdge = true; auto borderEdges = calculateBorderEdges(layoutBox.style(), m_pixelSnappingFactor, includeLogicalLeftEdge, includeLogicalRightEdge);
boxDecorationData->setBorderEdges(WTFMove(borderEdges));
return boxDecorationData;
}
FloatPoint3D BoxFactory::computeTransformOrigin(const BoxModelBox& box, const Layout::BoxGeometry& layoutGeometry, const RenderStyle& renderStyle, LayoutSize offsetFromRoot) const
{
auto transformBoxRect = LayoutRect { Layout::BoxGeometry::borderBoxRect(layoutGeometry) };
auto absoluteOrigin = LayoutPoint {
offsetFromRoot.width() + transformBoxRect.x() + valueForLength(renderStyle.transformOriginX(), transformBoxRect.width()),
offsetFromRoot.height() + transformBoxRect.y() + valueForLength(renderStyle.transformOriginY(), transformBoxRect.height())
};
auto snappedAbsoluteOrigin = roundPointToDevicePixels(absoluteOrigin, m_pixelSnappingFactor);
auto boxRelativeTransformOriginXY = snappedAbsoluteOrigin - box.absoluteBorderBoxRect().location();
return { boxRelativeTransformOriginXY.width(), boxRelativeTransformOriginXY.height(), renderStyle.transformOriginZ() };
}
TransformationMatrix BoxFactory::computeTransformationMatrix(const BoxModelBox& box, const Layout::BoxGeometry& layoutGeometry, const RenderStyle& renderStyle, LayoutSize offsetFromRoot) const
{
auto boxRelativeTransformOrigin = computeTransformOrigin(box, layoutGeometry, renderStyle, offsetFromRoot);
auto transformBoxRect = box.absoluteBorderBoxRect();
auto transform = TransformationMatrix { };
transform.translate3d(boxRelativeTransformOrigin.x(), boxRelativeTransformOrigin.y(), boxRelativeTransformOrigin.z());
for (auto& operation : renderStyle.transform().operations())
operation->apply(transform, transformBoxRect.size());
transform.translate3d(-boxRelativeTransformOrigin.x(), -boxRelativeTransformOrigin.y(), -boxRelativeTransformOrigin.z());
return transform;
}
std::unique_ptr<BoxRareGeometry> BoxFactory::constructBoxRareGeometry(const BoxModelBox& box, const Layout::Box& layoutBox, const Layout::BoxGeometry& layoutGeometry, LayoutSize offsetFromRoot) const
{
auto& renderStyle = layoutBox.style();
if (!box.style().hasTransform() && !renderStyle.hasBorderRadius())
return nullptr;
auto boxRareGeometry = makeUnique<BoxRareGeometry>();
if (renderStyle.hasBorderRadius()) {
bool includeLogicalLeftEdge = true; bool includeLogicalRightEdge = true;
auto borderBoxRect = LayoutRect { Layout::BoxGeometry::borderBoxRect(layoutGeometry) };
auto borderRoundedRect = renderStyle.getRoundedBorderFor(borderBoxRect, includeLogicalLeftEdge, includeLogicalRightEdge);
auto snappedRoundedRect = borderRoundedRect.pixelSnappedRoundedRectForPainting(m_pixelSnappingFactor);
auto borderRadii = makeUnique<FloatRoundedRect::Radii>(snappedRoundedRect.radii());
boxRareGeometry->setBorderRadii(WTFMove(borderRadii));
}
auto transformationMatrix = computeTransformationMatrix(box, layoutGeometry, layoutBox.style(), offsetFromRoot);
boxRareGeometry->setTransform(WTFMove(transformationMatrix));
return boxRareGeometry;
}
void BoxFactory::setupBoxModelBox(BoxModelBox& box, const Layout::Box& layoutBox, const Layout::BoxGeometry& layoutGeometry, const ContainingBlockContext& containingBlockContext, const RenderStyle* styleForBackground) const
{
setupBoxGeometry(box, layoutBox, layoutGeometry, containingBlockContext);
auto boxRareGeometry = constructBoxRareGeometry(box, layoutBox, layoutGeometry, containingBlockContext.offsetFromRoot);
box.setBoxRareGeometry(WTFMove(boxRareGeometry));
auto& renderStyle = layoutBox.style();
if (!(styleForBackground && styleForBackground->hasBackground()) && !renderStyle.hasBorder()) return;
auto boxDecorationData = constructBoxDecorationData(layoutBox, layoutGeometry, styleForBackground, containingBlockContext.offsetFromRoot);
box.setBoxDecorationData(WTFMove(boxDecorationData));
if (box.participatesInZOrderSorting()) {
RefPtr<BoxClip> clip = containingBlockContext.box.clipForDescendants();
box.setAncestorClip(WTFMove(clip));
}
}
const Layout::ContainerBox* BoxFactory::documentElementBoxFromRootBox(const Layout::ContainerBox& rootLayoutBox)
{
auto* documentBox = rootLayoutBox.firstChild();
if (!documentBox || !documentBox->isDocumentBox() || !is<Layout::ContainerBox>(documentBox))
return nullptr;
return downcast<Layout::ContainerBox>(documentBox);
}
const Layout::Box* BoxFactory::bodyBoxFromRootBox(const Layout::ContainerBox& rootLayoutBox)
{
auto* documentBox = rootLayoutBox.firstChild();
if (!documentBox || !documentBox->isDocumentBox() || !is<Layout::ContainerBox>(documentBox))
return nullptr;
auto* bodyBox = downcast<Layout::ContainerBox>(documentBox)->firstChild();
if (!bodyBox || !bodyBox->isBodyBox())
return nullptr;
return bodyBox;
}
} }
#endif // ENABLE(LAYOUT_FORMATTING_CONTEXT)