summaryrefslogtreecommitdiffstats
path: root/layout/base/nsCSSRendering.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'layout/base/nsCSSRendering.cpp')
-rw-r--r--layout/base/nsCSSRendering.cpp215
1 files changed, 171 insertions, 44 deletions
diff --git a/layout/base/nsCSSRendering.cpp b/layout/base/nsCSSRendering.cpp
index 71ebfad22..ff9edf742 100644
--- a/layout/base/nsCSSRendering.cpp
+++ b/layout/base/nsCSSRendering.cpp
@@ -1803,6 +1803,44 @@ SetupDirtyRects(const nsRect& aBGClipArea, const nsRect& aCallerDirtyRect,
"second should be empty if first is");
}
+static bool
+IsSVGStyleGeometryBox(StyleGeometryBox aBox)
+{
+ return (aBox == StyleGeometryBox::Fill || aBox == StyleGeometryBox::Stroke ||
+ aBox == StyleGeometryBox::View);
+}
+
+static bool
+IsHTMLStyleGeometryBox(StyleGeometryBox aBox)
+{
+ return (aBox == StyleGeometryBox::Content ||
+ aBox == StyleGeometryBox::Padding ||
+ aBox == StyleGeometryBox::Border ||
+ aBox == StyleGeometryBox::Margin);
+}
+
+static StyleGeometryBox
+ComputeBoxValue(nsIFrame* aForFrame, StyleGeometryBox aBox)
+{
+ // Except <svg>, all svg elements are not associate with CSS layout box.
+ if (aForFrame->IsFrameOfType(nsIFrame::eSVG) &&
+ (aForFrame->GetType() != nsGkAtoms::svgOuterSVGFrame)) {
+ // For SVG elements without associated CSS layout box, the values
+ // content-box, padding-box, border-box and margin-box compute to fill-box.
+ if (IsHTMLStyleGeometryBox(aBox)) {
+ return StyleGeometryBox::Fill;
+ }
+ } else {
+ // For elements with associated CSS layout box, the values fill-box,
+ // stroke-box and view-box compute to the initial value of mask-clip.
+ if (IsSVGStyleGeometryBox(aBox)) {
+ return StyleGeometryBox::Border;
+ }
+ }
+
+ return aBox;
+}
+
/* static */ void
nsCSSRendering::GetImageLayerClip(const nsStyleImageLayers::Layer& aLayer,
nsIFrame* aForFrame, const nsStyleBorder& aBorder,
@@ -1810,6 +1848,55 @@ nsCSSRendering::GetImageLayerClip(const nsStyleImageLayers::Layer& aLayer,
bool aWillPaintBorder, nscoord aAppUnitsPerPixel,
/* out */ ImageLayerClipState* aClipState)
{
+ StyleGeometryBox layerClip = ComputeBoxValue(aForFrame, aLayer.mClip);
+
+ if (IsSVGStyleGeometryBox(layerClip)) {
+ MOZ_ASSERT(aForFrame->IsFrameOfType(nsIFrame::eSVG) &&
+ (aForFrame->GetType() != nsGkAtoms::svgOuterSVGFrame));
+
+ aClipState->mHasAdditionalBGClipArea = false;
+ aClipState->mCustomClip = false;
+
+ // The coordinate space of clipArea is svg user space.
+ nsRect clipArea =
+ nsLayoutUtils::ComputeGeometryBox(aForFrame, layerClip);
+
+ nsRect strokeBox = (layerClip == StyleGeometryBox::Stroke)
+ ? clipArea
+ : nsLayoutUtils::ComputeGeometryBox(aForFrame, StyleGeometryBox::Stroke);
+ nsRect clipAreaRelativeToStrokeBox = clipArea - strokeBox.TopLeft();
+
+ // aBorderArea is the stroke-box area in a coordinate space defined by
+ // the caller. This coordinate space can be svg user space of aForFrame,
+ // the space of aForFrame's reference-frame, or anything else.
+ //
+ // Which coordinate space chosen for aBorderArea is not matter. What
+ // matter is to ensure returning aClipState->mBGClipArea in the consistent
+ // coordiante space with aBorderArea. So we evaluate the position of clip
+ // area base on the position of aBorderArea here.
+ aClipState->mBGClipArea =
+ clipAreaRelativeToStrokeBox + aBorderArea.TopLeft();
+
+ SetupDirtyRects(aClipState->mBGClipArea, aCallerDirtyRect,
+ aAppUnitsPerPixel, &aClipState->mDirtyRect,
+ &aClipState->mDirtyRectGfx);
+ return;
+ }
+
+ if (layerClip == StyleGeometryBox::NoClip) {
+ aClipState->mBGClipArea = aCallerDirtyRect;
+ aClipState->mHasAdditionalBGClipArea = false;
+ aClipState->mCustomClip = false;
+
+ SetupDirtyRects(aClipState->mBGClipArea, aCallerDirtyRect,
+ aAppUnitsPerPixel, &aClipState->mDirtyRect,
+ &aClipState->mDirtyRectGfx);
+ return;
+ }
+
+ MOZ_ASSERT(!aForFrame->IsFrameOfType(nsIFrame::eSVG) ||
+ aForFrame->GetType() == nsGkAtoms::svgOuterSVGFrame);
+
// Compute the outermost boundary of the area that might be painted.
// Same coordinate space as aBorderArea.
Sides skipSides = aForFrame->GetSkipSides();
@@ -1819,16 +1906,15 @@ nsCSSRendering::GetImageLayerClip(const nsStyleImageLayers::Layer& aLayer,
bool haveRoundedCorners = GetRadii(aForFrame, aBorder, aBorderArea,
clipBorderArea, aClipState->mRadii);
- uint8_t backgroundClip = aLayer.mClip;
-
bool isSolidBorder =
aWillPaintBorder && IsOpaqueBorder(aBorder);
- if (isSolidBorder && backgroundClip == NS_STYLE_IMAGELAYER_CLIP_BORDER) {
+ if (isSolidBorder && layerClip == StyleGeometryBox::Border) {
// If we have rounded corners, we need to inflate the background
// drawing area a bit to avoid seams between the border and
// background.
- backgroundClip = haveRoundedCorners ?
- NS_STYLE_IMAGELAYER_CLIP_MOZ_ALMOST_PADDING : NS_STYLE_IMAGELAYER_CLIP_PADDING;
+ layerClip = haveRoundedCorners
+ ? StyleGeometryBox::MozAlmostPadding
+ : StyleGeometryBox::Padding;
}
aClipState->mBGClipArea = clipBorderArea;
@@ -1844,7 +1930,7 @@ nsCSSRendering::GetImageLayerClip(const nsStyleImageLayers::Layer& aLayer,
// but the background is also clipped at a non-scrolling 'padding-box'
// like the content. (See below.)
// Therefore, only 'content-box' makes a difference here.
- if (backgroundClip == NS_STYLE_IMAGELAYER_CLIP_CONTENT) {
+ if (layerClip == StyleGeometryBox::Content) {
nsIScrollableFrame* scrollableFrame = do_QueryFrame(aForFrame);
// Clip at a rectangle attached to the scrolled content.
aClipState->mHasAdditionalBGClipArea = true;
@@ -1864,22 +1950,30 @@ nsCSSRendering::GetImageLayerClip(const nsStyleImageLayers::Layer& aLayer,
// Also clip at a non-scrolling, rounded-corner 'padding-box',
// same as the scrolled content because of the 'overflow' property.
- backgroundClip = NS_STYLE_IMAGELAYER_CLIP_PADDING;
+ layerClip = StyleGeometryBox::Padding;
}
- if (backgroundClip != NS_STYLE_IMAGELAYER_CLIP_BORDER &&
- backgroundClip != NS_STYLE_IMAGELAYER_CLIP_TEXT) {
+ // See the comment of StyleGeometryBox::Margin.
+ // Hitting this assertion means we decide to turn on margin-box support for
+ // positioned mask from CSS parser and style system. In this case, you
+ // should *inflate* mBGClipArea by the margin returning from
+ // aForFrame->GetUsedMargin() in the code chunk bellow.
+ MOZ_ASSERT(layerClip != StyleGeometryBox::Margin,
+ "StyleGeometryBox::Margin rendering is not supported yet.\n");
+
+ if (layerClip != StyleGeometryBox::Border &&
+ layerClip != StyleGeometryBox::Text) {
nsMargin border = aForFrame->GetUsedBorder();
- if (backgroundClip == NS_STYLE_IMAGELAYER_CLIP_MOZ_ALMOST_PADDING) {
+ if (layerClip == StyleGeometryBox::MozAlmostPadding) {
// Reduce |border| by 1px (device pixels) on all sides, if
// possible, so that we don't get antialiasing seams between the
- // background and border.
+ // {background|mask} and border.
border.top = std::max(0, border.top - aAppUnitsPerPixel);
border.right = std::max(0, border.right - aAppUnitsPerPixel);
border.bottom = std::max(0, border.bottom - aAppUnitsPerPixel);
border.left = std::max(0, border.left - aAppUnitsPerPixel);
- } else if (backgroundClip != NS_STYLE_IMAGELAYER_CLIP_PADDING) {
- NS_ASSERTION(backgroundClip == NS_STYLE_IMAGELAYER_CLIP_CONTENT,
+ } else if (layerClip != StyleGeometryBox::Padding) {
+ NS_ASSERTION(layerClip == StyleGeometryBox::Content,
"unexpected background-clip");
border += aForFrame->GetUsedPadding();
}
@@ -3163,7 +3257,7 @@ nsCSSRendering::PaintBackgroundWithSC(const PaintBGParams& aParams,
if (drawBackgroundImage) {
bool clipSet = false;
- uint8_t currentBackgroundClip = NS_STYLE_IMAGELAYER_CLIP_BORDER;
+ StyleGeometryBox currentBackgroundClip = StyleGeometryBox::Border;
NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT_WITH_RANGE(i, layers, layers.mImageCount - 1,
nLayers + (layers.mImageCount -
startLayer - 1)) {
@@ -3239,16 +3333,43 @@ nsCSSRendering::ComputeImageLayerPositioningArea(nsPresContext* aPresContext,
nsIFrame** aAttachedToFrame,
bool* aOutIsTransformedFixed)
{
- // Compute background origin area relative to aBorderArea now as we may need
- // it to compute the effective image size for a CSS gradient.
- nsRect bgPositioningArea;
+ // Compute {background|mask} origin area relative to aBorderArea now as we
+ // may need it to compute the effective image size for a CSS gradient.
+ nsRect positionArea;
+
+ StyleGeometryBox layerOrigin =
+ ComputeBoxValue(aForFrame, aLayer.mOrigin);
+
+ if (IsSVGStyleGeometryBox(layerOrigin)) {
+ MOZ_ASSERT(aForFrame->IsFrameOfType(nsIFrame::eSVG) &&
+ (aForFrame->GetType() != nsGkAtoms::svgOuterSVGFrame));
+ *aAttachedToFrame = aForFrame;
+
+ positionArea =
+ nsLayoutUtils::ComputeGeometryBox(aForFrame, layerOrigin);
+
+ nsPoint toStrokeBoxOffset = nsPoint(0, 0);
+ if (layerOrigin != StyleGeometryBox::Stroke) {
+ nsRect strokeBox =
+ nsLayoutUtils::ComputeGeometryBox(aForFrame,
+ StyleGeometryBox::Stroke);
+ toStrokeBoxOffset = positionArea.TopLeft() - strokeBox.TopLeft();
+ }
+
+ // For SVG frames, the return value is relative to the stroke box
+ return nsRect(toStrokeBoxOffset, positionArea.Size());
+ }
+
+ MOZ_ASSERT(!aForFrame->IsFrameOfType(nsIFrame::eSVG) ||
+ aForFrame->GetType() == nsGkAtoms::svgOuterSVGFrame);
+
nsIAtom* frameType = aForFrame->GetType();
nsIFrame* geometryFrame = aForFrame;
if (MOZ_UNLIKELY(frameType == nsGkAtoms::scrollFrame &&
NS_STYLE_IMAGELAYER_ATTACHMENT_LOCAL == aLayer.mAttachment)) {
nsIScrollableFrame* scrollableFrame = do_QueryFrame(aForFrame);
- bgPositioningArea = nsRect(
+ positionArea = nsRect(
scrollableFrame->GetScrolledFrame()->GetPosition()
// For the dir=rtl case:
+ scrollableFrame->GetScrollRange().TopLeft(),
@@ -3256,20 +3377,20 @@ nsCSSRendering::ComputeImageLayerPositioningArea(nsPresContext* aPresContext,
// The ScrolledRect’s size does not include the borders or scrollbars,
// reverse the handling of background-origin
// compared to the common case below.
- if (aLayer.mOrigin == NS_STYLE_IMAGELAYER_ORIGIN_BORDER) {
+ if (layerOrigin == StyleGeometryBox::Border) {
nsMargin border = geometryFrame->GetUsedBorder();
border.ApplySkipSides(geometryFrame->GetSkipSides());
- bgPositioningArea.Inflate(border);
- bgPositioningArea.Inflate(scrollableFrame->GetActualScrollbarSizes());
- } else if (aLayer.mOrigin != NS_STYLE_IMAGELAYER_ORIGIN_PADDING) {
+ positionArea.Inflate(border);
+ positionArea.Inflate(scrollableFrame->GetActualScrollbarSizes());
+ } else if (layerOrigin != StyleGeometryBox::Padding) {
nsMargin padding = geometryFrame->GetUsedPadding();
padding.ApplySkipSides(geometryFrame->GetSkipSides());
- bgPositioningArea.Deflate(padding);
- NS_ASSERTION(aLayer.mOrigin == NS_STYLE_IMAGELAYER_ORIGIN_CONTENT,
+ positionArea.Deflate(padding);
+ NS_ASSERTION(layerOrigin == StyleGeometryBox::Content,
"unknown background-origin value");
}
*aAttachedToFrame = aForFrame;
- return bgPositioningArea;
+ return positionArea;
}
if (MOZ_UNLIKELY(frameType == nsGkAtoms::canvasFrame)) {
@@ -3279,25 +3400,31 @@ nsCSSRendering::ComputeImageLayerPositioningArea(nsPresContext* aPresContext,
// finished and this page only displays the continuations of
// absolutely positioned content).
if (geometryFrame) {
- bgPositioningArea = geometryFrame->GetRect();
+ positionArea = geometryFrame->GetRect();
}
} else {
- bgPositioningArea = nsRect(nsPoint(0,0), aBorderArea.Size());
+ positionArea = nsRect(nsPoint(0,0), aBorderArea.Size());
}
- // Background images are tiled over the 'background-clip' area
- // but the origin of the tiling is based on the 'background-origin' area
- // XXX: Bug 1303623 will bring in new origin value, we should iterate from
- // NS_STYLE_IMAGELAYER_ORIGIN_MARGIN instead of
- // NS_STYLE_IMAGELAYER_ORIGIN_BORDER.
- if (aLayer.mOrigin != NS_STYLE_IMAGELAYER_ORIGIN_BORDER && geometryFrame) {
+ // See the comment of StyleGeometryBox::Margin.
+ // Hitting this assertion means we decide to turn on margin-box support for
+ // positioned mask from CSS parser and style system. In this case, you
+ // should *inflate* positionArea by the margin returning from
+ // geometryFrame->GetUsedMargin() in the code chunk bellow.
+ MOZ_ASSERT(aLayer.mOrigin != StyleGeometryBox::Margin,
+ "StyleGeometryBox::Margin rendering is not supported yet.\n");
+
+ // {background|mask} images are tiled over the '{background|mask}-clip' area
+ // but the origin of the tiling is based on the '{background|mask}-origin'
+ // area.
+ if (layerOrigin != StyleGeometryBox::Border && geometryFrame) {
nsMargin border = geometryFrame->GetUsedBorder();
- if (aLayer.mOrigin != NS_STYLE_IMAGELAYER_ORIGIN_PADDING) {
+ if (layerOrigin != StyleGeometryBox::Padding) {
border += geometryFrame->GetUsedPadding();
- NS_ASSERTION(aLayer.mOrigin == NS_STYLE_IMAGELAYER_ORIGIN_CONTENT,
+ NS_ASSERTION(layerOrigin == StyleGeometryBox::Content,
"unknown background-origin value");
}
- bgPositioningArea.Deflate(border);
+ positionArea.Deflate(border);
}
nsIFrame* attachedToFrame = aForFrame;
@@ -3325,7 +3452,7 @@ nsCSSRendering::ComputeImageLayerPositioningArea(nsPresContext* aPresContext,
} else {
// Set the background positioning area to the viewport's area
// (relative to aForFrame)
- bgPositioningArea =
+ positionArea =
nsRect(-aForFrame->GetOffsetTo(attachedToFrame), attachedToFrame->GetSize());
if (!pageContentFrame) {
@@ -3334,14 +3461,14 @@ nsCSSRendering::ComputeImageLayerPositioningArea(nsPresContext* aPresContext,
aPresContext->PresShell()->GetRootScrollFrameAsScrollable();
if (scrollableFrame) {
nsMargin scrollbars = scrollableFrame->GetActualScrollbarSizes();
- bgPositioningArea.Deflate(scrollbars);
+ positionArea.Deflate(scrollbars);
}
}
}
}
*aAttachedToFrame = attachedToFrame;
- return bgPositioningArea;
+ return positionArea;
}
// Implementation of the formula for computation of background-repeat round
@@ -3569,7 +3696,7 @@ nsCSSRendering::PrepareImageLayer(nsPresContext* aPresContext,
bool transformedFixed = false;
// Compute background origin area relative to aBorderArea now as we may need
// it to compute the effective image size for a CSS gradient.
- nsRect bgPositioningArea =
+ nsRect positionArea =
ComputeImageLayerPositioningArea(aPresContext, aForFrame, aBorderArea,
aLayer, &attachedToFrame, &transformedFixed);
if (aOutIsTransformedFixed) {
@@ -3594,7 +3721,7 @@ nsCSSRendering::PrepareImageLayer(nsPresContext* aPresContext,
// not a pure optimization since it can affect the values of pixels at the
// edge of the viewport --- whether they're sampled from a putative "next
// tile" or not.)
- bgClipRect.IntersectRect(bgClipRect, bgPositioningArea + aBorderArea.TopLeft());
+ bgClipRect.IntersectRect(bgClipRect, positionArea + aBorderArea.TopLeft());
}
}
@@ -3605,7 +3732,7 @@ nsCSSRendering::PrepareImageLayer(nsPresContext* aPresContext,
// Also as required for proper background positioning when background-position
// is defined with percentages.
CSSSizeOrRatio intrinsicSize = state.mImageRenderer.ComputeIntrinsicSize();
- nsSize bgPositionSize = bgPositioningArea.Size();
+ nsSize bgPositionSize = positionArea.Size();
nsSize imageSize = ComputeDrawnSizeForBackground(intrinsicSize,
bgPositionSize,
aLayer.mSize,
@@ -3650,8 +3777,8 @@ nsCSSRendering::PrepareImageLayer(nsPresContext* aPresContext,
}
}
- imageTopLeft += bgPositioningArea.TopLeft();
- state.mAnchor += bgPositioningArea.TopLeft();
+ imageTopLeft += positionArea.TopLeft();
+ state.mAnchor += positionArea.TopLeft();
state.mDestArea = nsRect(imageTopLeft + aBorderArea.TopLeft(), imageSize);
state.mFillArea = state.mDestArea;