issue #908 - implement missing parts of CSS mask

pull/1/head
yami 4 years ago committed by Roy Tam
parent 7b5e5f85de
commit b5376e63c5
  1. 215
      layout/base/nsCSSRendering.cpp
  2. 22
      layout/base/nsDisplayList.cpp
  3. 8
      layout/base/nsDisplayList.h
  4. 127
      layout/base/nsLayoutUtils.cpp
  5. 5
      layout/base/nsLayoutUtils.h
  6. 2
      layout/generic/nsTextFrame.cpp
  7. 2
      layout/inspector/inDOMUtils.cpp
  8. 39
      layout/style/Declaration.cpp
  9. 4
      layout/style/StyleAnimationValue.cpp
  10. 2
      layout/style/nsCSSDataBlock.cpp
  11. 1
      layout/style/nsCSSKeywordList.h
  12. 31
      layout/style/nsCSSParser.cpp
  13. 2
      layout/style/nsCSSPropAliasList.h
  14. 20
      layout/style/nsCSSPropList.h
  15. 62
      layout/style/nsCSSProps.cpp
  16. 3
      layout/style/nsCSSProps.h
  17. 60
      layout/style/nsComputedDOMStyle.cpp
  18. 12
      layout/style/nsComputedDOMStyle.h
  19. 2
      layout/style/nsComputedDOMStylePropertyList.h
  20. 40
      layout/style/nsRuleNode.cpp
  21. 47
      layout/style/nsStyleConsts.h
  22. 8
      layout/style/nsStyleStruct.cpp
  23. 8
      layout/style/nsStyleStruct.h
  24. 116
      layout/svg/nsCSSClipPathInstance.cpp
  25. 4
      layout/svg/nsCSSClipPathInstance.h
  26. 144
      layout/svg/nsSVGIntegrationUtils.cpp
  27. 21
      layout/svg/nsSVGUtils.cpp
  28. 16
      old-configure.in

@ -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;

@ -3014,7 +3014,7 @@ nsDisplayBackgroundImage::ComputeVisibility(nsDisplayListBuilder* aBuilder,
/* static */ nsRegion
nsDisplayBackgroundImage::GetInsideClipRegion(nsDisplayItem* aItem,
uint8_t aClip,
StyleGeometryBox aClip,
const nsRect& aRect,
const nsRect& aBackgroundRect)
{
@ -3028,10 +3028,10 @@ nsDisplayBackgroundImage::GetInsideClipRegion(nsDisplayItem* aItem,
if (frame->GetType() == nsGkAtoms::canvasFrame) {
nsCanvasFrame* canvasFrame = static_cast<nsCanvasFrame*>(frame);
clipRect = canvasFrame->CanvasArea() + aItem->ToReferenceFrame();
} else if (aClip == NS_STYLE_IMAGELAYER_CLIP_PADDING ||
aClip == NS_STYLE_IMAGELAYER_CLIP_CONTENT) {
} else if (aClip == StyleGeometryBox::Padding ||
aClip == StyleGeometryBox::Content) {
nsMargin border = frame->GetUsedBorder();
if (aClip == NS_STYLE_IMAGELAYER_CLIP_CONTENT) {
if (aClip == StyleGeometryBox::Content) {
border += frame->GetUsedPadding();
}
border.ApplySkipSides(frame->GetSkipSides());
@ -3064,7 +3064,7 @@ nsDisplayBackgroundImage::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
if (layer.mImage.IsOpaque() && layer.mBlendMode == NS_STYLE_BLEND_NORMAL &&
layer.mRepeat.mXRepeat != NS_STYLE_IMAGELAYER_REPEAT_SPACE &&
layer.mRepeat.mYRepeat != NS_STYLE_IMAGELAYER_REPEAT_SPACE &&
layer.mClip != NS_STYLE_IMAGELAYER_CLIP_TEXT) {
layer.mClip != StyleGeometryBox::Text) {
result = GetInsideClipRegion(this, layer.mClip, mBounds, mBackgroundRect);
}
}
@ -3143,9 +3143,9 @@ nsDisplayBackgroundImage::PaintInternal(nsDisplayListBuilder* aBuilder,
CheckForBorderItem(this, flags);
gfxContext* ctx = aCtx->ThebesContext();
uint8_t clip = mBackgroundStyle->mImage.mLayers[mLayer].mClip;
StyleGeometryBox clip = mBackgroundStyle->mImage.mLayers[mLayer].mClip;
if (clip == NS_STYLE_IMAGELAYER_CLIP_TEXT) {
if (clip == StyleGeometryBox::Text) {
if (!GenerateAndPushTextMask(mFrame, aCtx, mBackgroundRect, aBuilder)) {
return;
}
@ -3161,7 +3161,7 @@ nsDisplayBackgroundImage::PaintInternal(nsDisplayListBuilder* aBuilder,
image::DrawResult result =
nsCSSRendering::PaintBackground(params);
if (clip == NS_STYLE_IMAGELAYER_CLIP_TEXT) {
if (clip == StyleGeometryBox::Text) {
ctx->PopGroupAndBlend();
}
@ -3583,8 +3583,8 @@ nsDisplayBackgroundColor::Paint(nsDisplayListBuilder* aBuilder,
nsLayoutUtils::RectToGfxRect(mBackgroundRect,
mFrame->PresContext()->AppUnitsPerDevPixel());
uint8_t clip = mBackgroundStyle->mImage.mLayers[0].mClip;
if (clip == NS_STYLE_IMAGELAYER_CLIP_TEXT) {
StyleGeometryBox clip = mBackgroundStyle->mImage.mLayers[0].mClip;
if (clip == StyleGeometryBox::Text) {
if (!GenerateAndPushTextMask(mFrame, aCtx, mBackgroundRect, aBuilder)) {
return;
}
@ -3618,7 +3618,7 @@ nsDisplayBackgroundColor::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
const nsStyleImageLayers::Layer& bottomLayer = mBackgroundStyle->BottomLayer();
if (bottomLayer.mClip == NS_STYLE_IMAGELAYER_CLIP_TEXT) {
if (bottomLayer.mClip == StyleGeometryBox::Text) {
return nsRegion();
}

@ -2713,6 +2713,8 @@ private:
*/
class nsDisplayBackgroundImage : public nsDisplayImageContainer {
public:
typedef mozilla::StyleGeometryBox StyleGeometryBox;
/**
* aLayer signifies which background layer this item represents.
* aIsThemed should be the value of aFrame->IsThemed.
@ -2790,8 +2792,10 @@ public:
virtual already_AddRefed<imgIContainer> GetImage() override;
virtual nsRect GetDestRect() override;
static nsRegion GetInsideClipRegion(nsDisplayItem* aItem, uint8_t aClip,
const nsRect& aRect, const nsRect& aBackgroundRect);
static nsRegion GetInsideClipRegion(nsDisplayItem* aItem,
StyleGeometryBox aClip,
const nsRect& aRect,
const nsRect& aBackgroundRect);
virtual bool ShouldFixToViewport(nsDisplayListBuilder* aBuilder) override;

@ -117,6 +117,7 @@
#include "mozilla/StyleSetHandle.h"
#include "mozilla/StyleSetHandleInlines.h"
#include "RegionBuilder.h"
#include "SVGSVGElement.h"
#ifdef MOZ_XUL
#include "nsXULPopupManager.h"
@ -6935,7 +6936,7 @@ nsLayoutUtils::GetFrameTransparency(nsIFrame* aBackgroundFrame,
const nsStyleBackground* bg = bgSC->StyleBackground();
if (NS_GET_A(bg->mBackgroundColor) < 255 ||
// bottom layer's clip is used for the color
bg->BottomLayer().mClip != NS_STYLE_IMAGELAYER_CLIP_BORDER)
bg->BottomLayer().mClip != StyleGeometryBox::Border)
return eTransparencyTransparent;
return eTransparencyOpaque;
}
@ -9293,3 +9294,127 @@ nsLayoutUtils::IsInvisibleBreak(nsINode* aNode, nsIFrame** aNextLineFrame)
return lineNonEmpty;
}
static nsRect
ComputeSVGReferenceRect(nsIFrame* aFrame,
StyleGeometryBox aGeometryBox)
{
MOZ_ASSERT(aFrame->GetContent()->IsSVGElement());
nsRect r;
// For SVG elements without associated CSS layout box, the used value for
// content-box, padding-box, border-box and margin-box is fill-box.
switch (aGeometryBox) {
case StyleGeometryBox::Stroke: {
// XXX Bug 1299876
// The size of srtoke-box is not correct if this graphic element has
// specific stroke-linejoin or stroke-linecap.
gfxRect bbox = nsSVGUtils::GetBBox(aFrame,
nsSVGUtils::eBBoxIncludeFill | nsSVGUtils::eBBoxIncludeStroke);
r = nsLayoutUtils::RoundGfxRectToAppRect(bbox,
nsPresContext::AppUnitsPerCSSPixel());
break;
}
case StyleGeometryBox::View: {
nsIContent* content = aFrame->GetContent();
nsSVGElement* element = static_cast<nsSVGElement*>(content);
SVGSVGElement* svgElement = element->GetCtx();
MOZ_ASSERT(svgElement);
if (svgElement && svgElement->HasViewBoxRect()) {
// If a ‘viewBox‘ attribute is specified for the SVG viewport creating
// element:
// 1. The reference box is positioned at the origin of the coordinate
// system established by the ‘viewBox‘ attribute.
// 2. The dimension of the reference box is set to the width and height
// values of the ‘viewBox‘ attribute.
nsSVGViewBox* viewBox = svgElement->GetViewBox();
const nsSVGViewBoxRect& value = viewBox->GetAnimValue();
r = nsRect(nsPresContext::CSSPixelsToAppUnits(value.x),
nsPresContext::CSSPixelsToAppUnits(value.y),
nsPresContext::CSSPixelsToAppUnits(value.width),
nsPresContext::CSSPixelsToAppUnits(value.height));
} else {
// No viewBox is specified, uses the nearest SVG viewport as reference
// box.
svgFloatSize viewportSize = svgElement->GetViewportSize();
r = nsRect(0, 0,
nsPresContext::CSSPixelsToAppUnits(viewportSize.width),
nsPresContext::CSSPixelsToAppUnits(viewportSize.height));
}
break;
}
case StyleGeometryBox::NoBox:
case StyleGeometryBox::Border:
case StyleGeometryBox::Content:
case StyleGeometryBox::Padding:
case StyleGeometryBox::Margin:
case StyleGeometryBox::Fill: {
gfxRect bbox = nsSVGUtils::GetBBox(aFrame,
nsSVGUtils::eBBoxIncludeFill);
r = nsLayoutUtils::RoundGfxRectToAppRect(bbox,
nsPresContext::AppUnitsPerCSSPixel());
break;
}
default:{
MOZ_ASSERT_UNREACHABLE("unknown StyleGeometryBox type");
gfxRect bbox = nsSVGUtils::GetBBox(aFrame,
nsSVGUtils::eBBoxIncludeFill);
r = nsLayoutUtils::RoundGfxRectToAppRect(bbox,
nsPresContext::AppUnitsPerCSSPixel());
break;
}
}
return r;
}
static nsRect
ComputeHTMLReferenceRect(nsIFrame* aFrame,
StyleGeometryBox aGeometryBox)
{
nsRect r;
// For elements with associated CSS layout box, the used value for fill-box,
// stroke-box and view-box is border-box.
switch (aGeometryBox) {
case StyleGeometryBox::Content:
r = aFrame->GetContentRectRelativeToSelf();
break;
case StyleGeometryBox::Padding:
r = aFrame->GetPaddingRectRelativeToSelf();
break;
case StyleGeometryBox::Margin:
r = aFrame->GetMarginRectRelativeToSelf();
break;
case StyleGeometryBox::NoBox:
case StyleGeometryBox::Border:
case StyleGeometryBox::Fill:
case StyleGeometryBox::Stroke:
case StyleGeometryBox::View:
r = aFrame->GetRectRelativeToSelf();
break;
default:
MOZ_ASSERT_UNREACHABLE("unknown StyleGeometryBox type");
r = aFrame->GetRectRelativeToSelf();
break;
}
return r;
}
/* static */ nsRect
nsLayoutUtils::ComputeGeometryBox(nsIFrame* aFrame,
StyleGeometryBox aGeometryBox)
{
// We use ComputeSVGReferenceRect for all SVG elements, except <svg>
// element, which does have an associated CSS layout box. In this case we
// should still use ComputeHTMLReferenceRect for region computing.
nsRect r = aFrame->IsFrameOfType(nsIFrame::eSVG) &&
(aFrame->GetType() != nsGkAtoms::svgOuterSVGFrame)
? ComputeSVGReferenceRect(aFrame, aGeometryBox)
: ComputeHTMLReferenceRect(aFrame, aGeometryBox);
return r;
}

@ -30,6 +30,7 @@
#include "mozilla/ReflowOutput.h"
#include "ImageContainer.h"
#include "gfx2DGlue.h"
#include "nsStyleConsts.h"
#include <limits>
#include <algorithm>
@ -152,6 +153,7 @@ public:
typedef mozilla::CSSRect CSSRect;
typedef mozilla::ScreenMargin ScreenMargin;
typedef mozilla::LayoutDeviceIntSize LayoutDeviceIntSize;
typedef mozilla::StyleGeometryBox StyleGeometryBox;
/**
* Finds previously assigned ViewID for the given content element, if any.
@ -2870,6 +2872,9 @@ public:
*/
static bool IsInvisibleBreak(nsINode* aNode, nsIFrame** aNextLineFrame = nullptr);
static nsRect ComputeGeometryBox(nsIFrame* aFrame,
StyleGeometryBox aGeometryBox);
private:
static uint32_t sFontSizeInflationEmPerLine;
static uint32_t sFontSizeInflationMinTwips;

@ -6715,7 +6715,7 @@ ShouldDrawSelection(const nsIFrame* aFrame)
const nsStyleBackground* bg = aFrame->StyleContext()->StyleBackground();
const nsStyleImageLayers& layers = bg->mImage;
NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, layers) {
if (layers.mLayers[i].mClip == NS_STYLE_IMAGELAYER_CLIP_TEXT) {
if (layers.mLayers[i].mClip == StyleGeometryBox::Text) {
return false;
}
}

@ -784,12 +784,10 @@ PropertySupportsVariant(nsCSSPropertyID aPropertyID, uint32_t aVariant)
case eCSSProperty_background_position_x:
case eCSSProperty_background_position_y:
case eCSSProperty_background_size:
#ifdef MOZ_ENABLE_MASK_AS_SHORTHAND
case eCSSProperty_mask_position:
case eCSSProperty_mask_position_x:
case eCSSProperty_mask_position_y:
case eCSSProperty_mask_size:
#endif
case eCSSProperty_grid_auto_columns:
case eCSSProperty_grid_auto_rows:
case eCSSProperty_grid_template_columns:

@ -395,28 +395,25 @@ Declaration::GetImageLayerValue(
origin->mValue.GetUnit() == eCSSUnit_Enumerated,
"should not have inherit/initial within list");
int32_t originDefaultValue =
StyleGeometryBox originDefaultValue =
(aTable == nsStyleImageLayers::kBackgroundLayerTable)
? NS_STYLE_IMAGELAYER_ORIGIN_PADDING : NS_STYLE_IMAGELAYER_ORIGIN_BORDER;
if (clip->mValue.GetIntValue() != NS_STYLE_IMAGELAYER_CLIP_BORDER ||
origin->mValue.GetIntValue() != originDefaultValue) {
? StyleGeometryBox::Padding : StyleGeometryBox::Border;
if (static_cast<StyleGeometryBox>(clip->mValue.GetIntValue()) !=
StyleGeometryBox::Border ||
static_cast<StyleGeometryBox>(origin->mValue.GetIntValue()) !=
originDefaultValue) {
#ifdef DEBUG
for (size_t i = 0; nsCSSProps::kImageLayerOriginKTable[i].mValue != -1; i++) {
const nsCSSProps::KTableEntry* originTable =
nsCSSProps::kKeywordTableTable[aTable[nsStyleImageLayers::origin]];
const nsCSSProps::KTableEntry* clipTable =
nsCSSProps::kKeywordTableTable[aTable[nsStyleImageLayers::clip]];
for (size_t i = 0; originTable[i].mValue != -1; i++) {
// For each keyword & value in kOriginKTable, ensure that
// kBackgroundKTable has a matching entry at the same position.
MOZ_ASSERT(nsCSSProps::kImageLayerOriginKTable[i].mKeyword ==
nsCSSProps::kBackgroundClipKTable[i].mKeyword);
MOZ_ASSERT(nsCSSProps::kImageLayerOriginKTable[i].mValue ==
nsCSSProps::kBackgroundClipKTable[i].mValue);
MOZ_ASSERT(originTable[i].mKeyword == clipTable[i].mKeyword);
MOZ_ASSERT(originTable[i].mValue == clipTable[i].mValue);
}
#endif
static_assert(NS_STYLE_IMAGELAYER_CLIP_BORDER ==
NS_STYLE_IMAGELAYER_ORIGIN_BORDER &&
NS_STYLE_IMAGELAYER_CLIP_PADDING ==
NS_STYLE_IMAGELAYER_ORIGIN_PADDING &&
NS_STYLE_IMAGELAYER_CLIP_CONTENT ==
NS_STYLE_IMAGELAYER_ORIGIN_CONTENT,
"mask-clip and mask-origin style constants must agree");
aValue.Append(char16_t(' '));
origin->mValue.AppendToString(aTable[nsStyleImageLayers::origin], aValue,
aSerialization);
@ -462,11 +459,7 @@ Declaration::GetImageLayerValue(
}
// This layer is an mask layer
} else {
#ifdef MOZ_ENABLE_MASK_AS_SHORTHAND
MOZ_ASSERT(aTable == nsStyleImageLayers::kMaskLayerTable);
#else
MOZ_ASSERT_UNREACHABLE("Should never get here when mask-as-shorthand is disable");
#endif
if (repeat || positionX || positionY || clip || origin || size ||
composite || mode) {
// Uneven length lists, so can't be serialized as shorthand.
@ -487,11 +480,7 @@ Declaration::GetImageLayerValue(
}
// This layer is an mask layer
} else {
#ifdef MOZ_ENABLE_MASK_AS_SHORTHAND
MOZ_ASSERT(aTable == nsStyleImageLayers::kMaskLayerTable);
#else
MOZ_ASSERT_UNREACHABLE("Should never get here when mask-as-shorthand is disable");
#endif
if (!repeat || !positionX || !positionY || !clip || !origin || !size ||
!composite || !mode) {
// Uneven length lists, so can't be serialized as shorthand.
@ -817,7 +806,6 @@ Declaration::GetPropertyValueInternal(
nsStyleImageLayers::kBackgroundLayerTable);
break;
}
#ifdef MOZ_ENABLE_MASK_AS_SHORTHAND
case eCSSProperty_mask: {
GetImageLayerValue(data, aValue, aSerialization,
nsStyleImageLayers::kMaskLayerTable);
@ -828,7 +816,6 @@ Declaration::GetPropertyValueInternal(
nsStyleImageLayers::kMaskLayerTable);
break;
}
#endif
case eCSSProperty_font: {
// systemFont might not be present; other values are guaranteed to be
// available based on the shorthand check at the beginning of the

@ -4255,7 +4255,6 @@ StyleAnimationValue::ExtractComputedValue(nsCSSPropertyID aProperty,
}
#ifdef MOZ_ENABLE_MASK_AS_SHORTHAND
case eCSSProperty_mask_position_x: {
const nsStyleImageLayers& layers =
static_cast<const nsStyleSVGReset*>(styleStruct)->mMask;
@ -4269,21 +4268,18 @@ StyleAnimationValue::ExtractComputedValue(nsCSSPropertyID aProperty,
break;
}
#endif
case eCSSProperty_background_size: {
const nsStyleImageLayers& layers =
static_cast<const nsStyleBackground*>(styleStruct)->mImage;
ExtractImageLayerSizePairList(layers, aComputedValue);
break;
}
#ifdef MOZ_ENABLE_MASK_AS_SHORTHAND
case eCSSProperty_mask_size: {
const nsStyleImageLayers& layers =
static_cast<const nsStyleSVGReset*>(styleStruct)->mMask;
ExtractImageLayerSizePairList(layers, aComputedValue);
break;
}
#endif
case eCSSProperty_clip_path: {
const nsStyleSVGReset* svgReset =

@ -61,7 +61,6 @@ TryToStartImageLoadOnValue(const nsCSSValue& aValue, nsIDocument* aDocument,
MOZ_ASSERT(aDocument);
if (aValue.GetUnit() == eCSSUnit_URL) {
#ifdef MOZ_ENABLE_MASK_AS_SHORTHAND
// The 'mask-image' property accepts local reference URIs.
// For example,
// mask-image: url(#mask_id); // refer to a SVG mask element, whose id is
@ -94,7 +93,6 @@ TryToStartImageLoadOnValue(const nsCSSValue& aValue, nsIDocument* aDocument,
}
}
}
#endif
aValue.StartImageLoad(aDocument);
if (aForTokenStream && aContext) {
CSSVariableImageTable::Add(aContext, aProperty,

@ -405,6 +405,7 @@ CSS_KEY(n-resize, n_resize)
CSS_KEY(narrower, narrower)
CSS_KEY(ne-resize, ne_resize)
CSS_KEY(nesw-resize, nesw_resize)
CSS_KEY(no-clip, no_clip)
CSS_KEY(no-close-quote, no_close_quote)
CSS_KEY(no-common-ligatures, no_common_ligatures)
CSS_KEY(no-contextual, no_contextual)

@ -12005,7 +12005,6 @@ CSSParserImpl::ParsePropertyByFunction(nsCSSPropertyID aPropID)
return ParsePaintOrder();
case eCSSProperty_scroll_snap_type:
return ParseScrollSnapType();
#ifdef MOZ_ENABLE_MASK_AS_SHORTHAND
case eCSSProperty_mask:
return ParseImageLayers(nsStyleImageLayers::kMaskLayerTable);
case eCSSProperty_mask_repeat:
@ -12018,7 +12017,6 @@ CSSParserImpl::ParsePropertyByFunction(nsCSSPropertyID aPropID)
aPropID == eCSSProperty_mask_position_x);
case eCSSProperty_mask_size:
return ParseImageLayerSize(eCSSProperty_mask_size);
#endif
case eCSSProperty__webkit_text_stroke:
return ParseWebkitTextStroke();
case eCSSProperty_all:
@ -12424,7 +12422,7 @@ CSSParserImpl::ParseImageLayersItem(
aState.mImage->mValue.SetNoneValue();
aState.mAttachment->mValue.SetIntValue(NS_STYLE_IMAGELAYER_ATTACHMENT_SCROLL,
eCSSUnit_Enumerated);
aState.mClip->mValue.SetIntValue(NS_STYLE_IMAGELAYER_CLIP_BORDER,
aState.mClip->mValue.SetIntValue(StyleGeometryBox::Border,
eCSSUnit_Enumerated);
aState.mRepeat->mXValue.SetIntValue(NS_STYLE_IMAGELAYER_REPEAT_REPEAT,
@ -12437,10 +12435,10 @@ CSSParserImpl::ParseImageLayersItem(
aState.mPositionY->mValue.SetArrayValue(positionYArr, eCSSUnit_Array);
if (eCSSProperty_mask == aTable[nsStyleImageLayers::shorthand]) {
aState.mOrigin->mValue.SetIntValue(NS_STYLE_IMAGELAYER_ORIGIN_BORDER,
aState.mOrigin->mValue.SetIntValue(StyleGeometryBox::Border,
eCSSUnit_Enumerated);
} else {
aState.mOrigin->mValue.SetIntValue(NS_STYLE_IMAGELAYER_ORIGIN_PADDING,
aState.mOrigin->mValue.SetIntValue(StyleGeometryBox::Padding,
eCSSUnit_Enumerated);
}
positionXArr->Item(1).SetPercentValue(0.0f);
@ -12462,6 +12460,8 @@ CSSParserImpl::ParseImageLayersItem(
haveMode = false,
haveSomething = false;
const KTableEntry* originTable =
nsCSSProps::kKeywordTableTable[aTable[nsStyleImageLayers::origin]];
while (GetToken(true)) {
nsCSSTokenType tt = mToken.mType;
UngetToken(); // ...but we'll still cheat and use mToken
@ -12531,8 +12531,7 @@ CSSParserImpl::ParseImageLayersItem(
aState.mSize->mXValue = scratch.mXValue;
aState.mSize->mYValue = scratch.mYValue;
}
} else if (nsCSSProps::FindKeyword(keyword,
nsCSSProps::kImageLayerOriginKTable, dummy)) {
} else if (nsCSSProps::FindKeyword(keyword, originTable, dummy)) {
if (haveOrigin)
return false;
haveOrigin = true;
@ -12547,23 +12546,15 @@ CSSParserImpl::ParseImageLayersItem(
// immediately following the first one (for background-origin).
#ifdef DEBUG
for (size_t i = 0; nsCSSProps::kImageLayerOriginKTable[i].mValue != -1; i++) {
const KTableEntry* clipTable =
nsCSSProps::kKeywordTableTable[aTable[nsStyleImageLayers::clip]];
for (size_t i = 0; originTable[i].mValue != -1; i++) {
// For each keyword & value in kOriginKTable, ensure that
// kBackgroundKTable has a matching entry at the same position.
MOZ_ASSERT(nsCSSProps::kImageLayerOriginKTable[i].mKeyword ==
nsCSSProps::kBackgroundClipKTable[i].mKeyword);
MOZ_ASSERT(nsCSSProps::kImageLayerOriginKTable[i].mValue ==
nsCSSProps::kBackgroundClipKTable[i].mValue);
MOZ_ASSERT(originTable[i].mKeyword == clipTable[i].mKeyword);
MOZ_ASSERT(originTable[i].mValue == clipTable[i].mValue);
}
#endif
static_assert(NS_STYLE_IMAGELAYER_CLIP_BORDER ==
NS_STYLE_IMAGELAYER_ORIGIN_BORDER &&
NS_STYLE_IMAGELAYER_CLIP_PADDING ==
NS_STYLE_IMAGELAYER_ORIGIN_PADDING &&
NS_STYLE_IMAGELAYER_CLIP_CONTENT ==
NS_STYLE_IMAGELAYER_ORIGIN_CONTENT,
"bg-clip and bg-origin style constants must agree");
CSSParseResult result =
ParseSingleValueProperty(aState.mClip->mValue,
aTable[nsStyleImageLayers::clip]);

@ -453,7 +453,6 @@ CSS_PROP_ALIAS(-webkit-user-select,
WebkitUserSelect,
WEBKIT_PREFIX_PREF)
#ifdef MOZ_ENABLE_MASK_AS_SHORTHAND
CSS_PROP_ALIAS(-webkit-mask,
mask,
WebkitMask,
@ -494,5 +493,4 @@ CSS_PROP_ALIAS(-webkit-mask-size,
mask_size,
WebkitMaskSize,
WEBKIT_PREFIX_PREF)
#endif
#undef WEBKIT_PREFIX_PREF

@ -564,7 +564,7 @@ CSS_PROP_BACKGROUND(
CSS_PROPERTY_VALUE_LIST_USES_COMMAS,
"",
VARIANT_KEYWORD, // used by list parsing
kImageLayerOriginKTable,
kBackgroundOriginKTable,
CSS_PROP_NO_OFFSET,
eStyleAnimType_Discrete)
CSS_PROP_SHORTHAND(
@ -2645,19 +2645,6 @@ CSS_PROP_SVG(
nullptr,
CSS_PROP_NO_OFFSET,
eStyleAnimType_Discrete)
#ifndef MOZ_ENABLE_MASK_AS_SHORTHAND
CSS_PROP_SVGRESET(
mask,
mask,
Mask,
CSS_PROPERTY_PARSE_VALUE |
CSS_PROPERTY_CREATES_STACKING_CONTEXT,
"",
VARIANT_HUO,
nullptr,
CSS_PROP_NO_OFFSET,
eStyleAnimType_Discrete)
#else
CSS_PROP_SHORTHAND(
mask,
mask,
@ -2672,7 +2659,7 @@ CSS_PROP_SVGRESET(
CSS_PROPERTY_VALUE_LIST_USES_COMMAS,
"",
VARIANT_KEYWORD, // used by list parsing
kImageLayerOriginKTable,
kMaskClipKTable,
CSS_PROP_NO_OFFSET,
eStyleAnimType_Discrete)
CSS_PROP_SVGRESET(
@ -2718,7 +2705,7 @@ CSS_PROP_SVGRESET(
CSS_PROPERTY_VALUE_LIST_USES_COMMAS,
"",
VARIANT_KEYWORD, // used by list parsing
kImageLayerOriginKTable,
kMaskOriginKTable,
CSS_PROP_NO_OFFSET,
eStyleAnimType_Discrete)
CSS_PROP_SHORTHAND(
@ -2776,7 +2763,6 @@ CSS_PROP_SVGRESET(
kImageLayerSizeKTable,
CSS_PROP_NO_OFFSET,
eStyleAnimType_Custom)
#endif // MOZ_ENABLE_MASK_AS_SHORTHAND
CSS_PROP_SVGRESET(
mask-type,
mask_type,

@ -932,33 +932,43 @@ const KTableEntry nsCSSProps::kImageLayerAttachmentKTable[] = {
{ eCSSKeyword_UNKNOWN, -1 }
};
static_assert(NS_STYLE_IMAGELAYER_CLIP_BORDER == NS_STYLE_IMAGELAYER_ORIGIN_BORDER &&
NS_STYLE_IMAGELAYER_CLIP_PADDING == NS_STYLE_IMAGELAYER_ORIGIN_PADDING &&
NS_STYLE_IMAGELAYER_CLIP_CONTENT == NS_STYLE_IMAGELAYER_ORIGIN_CONTENT,
"Except background-clip:text, all {background,mask}-clip and "
"{background,mask}-origin style constants must agree");
const KTableEntry nsCSSProps::kImageLayerOriginKTable[] = {
{ eCSSKeyword_border_box, NS_STYLE_IMAGELAYER_ORIGIN_BORDER },
{ eCSSKeyword_padding_box, NS_STYLE_IMAGELAYER_ORIGIN_PADDING },
{ eCSSKeyword_content_box, NS_STYLE_IMAGELAYER_ORIGIN_CONTENT },
const KTableEntry nsCSSProps::kBackgroundOriginKTable[] = {
{ eCSSKeyword_border_box, StyleGeometryBox::Border },
{ eCSSKeyword_padding_box, StyleGeometryBox::Padding },
{ eCSSKeyword_content_box, StyleGeometryBox::Content },
{ eCSSKeyword_UNKNOWN, -1 }
};
KTableEntry nsCSSProps::kBackgroundClipKTable[] = {
{ eCSSKeyword_border_box, NS_STYLE_IMAGELAYER_CLIP_BORDER },
{ eCSSKeyword_padding_box, NS_STYLE_IMAGELAYER_CLIP_PADDING },
{ eCSSKeyword_content_box, NS_STYLE_IMAGELAYER_CLIP_CONTENT },
{ eCSSKeyword_border_box, StyleGeometryBox::Border },
{ eCSSKeyword_padding_box, StyleGeometryBox::Padding },
{ eCSSKeyword_content_box, StyleGeometryBox::Content },
// The next entry is controlled by the layout.css.background-clip-text.enabled
// pref.
{ eCSSKeyword_text, NS_STYLE_IMAGELAYER_CLIP_TEXT },
{ eCSSKeyword_text, StyleGeometryBox::Text },
{ eCSSKeyword_UNKNOWN, -1 }
};
static_assert(MOZ_ARRAY_LENGTH(nsCSSProps::kImageLayerOriginKTable) ==
MOZ_ARRAY_LENGTH(nsCSSProps::kBackgroundClipKTable) - 1,
"background-clip has one extra value, which is text, compared"
"to {background,mask}-origin");
const KTableEntry nsCSSProps::kMaskOriginKTable[] = {
{ eCSSKeyword_border_box, StyleGeometryBox::Border },
{ eCSSKeyword_padding_box, StyleGeometryBox::Padding },
{ eCSSKeyword_content_box, StyleGeometryBox::Content },
{ eCSSKeyword_fill_box, StyleGeometryBox::Fill },
{ eCSSKeyword_stroke_box, StyleGeometryBox::Stroke },
{ eCSSKeyword_view_box, StyleGeometryBox::View },
{ eCSSKeyword_UNKNOWN, -1 }
};
const KTableEntry nsCSSProps::kMaskClipKTable[] = {
{ eCSSKeyword_border_box, StyleGeometryBox::Border },
{ eCSSKeyword_padding_box, StyleGeometryBox::Padding },
{ eCSSKeyword_content_box, StyleGeometryBox::Content },
{ eCSSKeyword_fill_box, StyleGeometryBox::Fill },
{ eCSSKeyword_stroke_box, StyleGeometryBox::Stroke },
{ eCSSKeyword_view_box, StyleGeometryBox::View },
{ eCSSKeyword_no_clip, StyleGeometryBox::NoClip },
{ eCSSKeyword_UNKNOWN, -1 }
};
// Note: Don't change this table unless you update
// ParseImageLayerPosition!
@ -2346,13 +2356,13 @@ const KTableEntry nsCSSProps::kFillRuleKTable[] = {
};
const KTableEntry nsCSSProps::kClipPathGeometryBoxKTable[] = {
{ eCSSKeyword_content_box, StyleClipPathGeometryBox::Content },
{ eCSSKeyword_padding_box, StyleClipPathGeometryBox::Padding },
{ eCSSKeyword_border_box, StyleClipPathGeometryBox::Border },
{ eCSSKeyword_margin_box, StyleClipPathGeometryBox::Margin },
{ eCSSKeyword_fill_box, StyleClipPathGeometryBox::Fill },
{ eCSSKeyword_stroke_box, StyleClipPathGeometryBox::Stroke },
{ eCSSKeyword_view_box, StyleClipPathGeometryBox::View },
{ eCSSKeyword_content_box, StyleGeometryBox::Content },
{ eCSSKeyword_padding_box, StyleGeometryBox::Padding },
{ eCSSKeyword_border_box, StyleGeometryBox::Border },
{ eCSSKeyword_margin_box, StyleGeometryBox::Margin },
{ eCSSKeyword_fill_box, StyleGeometryBox::Fill },
{ eCSSKeyword_stroke_box, StyleGeometryBox::Stroke },
{ eCSSKeyword_view_box, StyleGeometryBox::View },
{ eCSSKeyword_UNKNOWN, -1 }
};
@ -3051,7 +3061,6 @@ static const nsCSSPropertyID gScrollSnapTypeSubpropTable[] = {
eCSSProperty_scroll_snap_type_y,
eCSSProperty_UNKNOWN
};
#ifdef MOZ_ENABLE_MASK_AS_SHORTHAND
static const nsCSSPropertyID gMaskSubpropTable[] = {
eCSSProperty_mask_image,
eCSSProperty_mask_repeat,
@ -3069,7 +3078,6 @@ static const nsCSSPropertyID gMaskPositionSubpropTable[] = {
eCSSProperty_mask_position_y,
eCSSProperty_UNKNOWN
};
#endif
// FIXME: mask-border tables should be added when we implement
// mask-border properties.

@ -717,6 +717,8 @@ public:
static const KTableEntry kTransformStyleKTable[];
static const KTableEntry kImageLayerAttachmentKTable[];
static const KTableEntry kImageLayerOriginKTable[];
static const KTableEntry kBackgroundOriginKTable[];
static const KTableEntry kMaskOriginKTable[];
static const KTableEntry kImageLayerPositionKTable[];
static const KTableEntry kImageLayerRepeatKTable[];
static const KTableEntry kImageLayerRepeatPartKTable[];
@ -726,6 +728,7 @@ public:
// Not const because we modify its entries when the pref
// "layout.css.background-clip.text" changes:
static KTableEntry kBackgroundClipKTable[];
static const KTableEntry kMaskClipKTable[];
static const KTableEntry kBlendModeKTable[];
static const KTableEntry kBorderCollapseKTable[];
static const KTableEntry kBorderImageRepeatKTable[];

@ -74,6 +74,30 @@ NS_NewComputedDOMStyle(dom::Element* aElement, const nsAString& aPseudoElt,
return computedStyle.forget();
}
static nsDOMCSSValueList*
GetROCSSValueList(bool aCommaDelimited)
{
return new nsDOMCSSValueList(aCommaDelimited, true);
}
template<typename T>
already_AddRefed<CSSValue>
GetBackgroundList(T nsStyleImageLayers::Layer::* aMember,
uint32_t nsStyleImageLayers::* aCount,
const nsStyleImageLayers& aLayers,
const KTableEntry aTable[])
{
RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
for (uint32_t i = 0, i_end = aLayers.*aCount; i < i_end; ++i) {
RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
val->SetIdent(nsCSSProps::ValueToKeywordEnum(aLayers.mLayers[i].*aMember, aTable));
valueList->AppendCSSValue(val.forget());
}
return valueList.forget();
}
/**
* An object that represents the ordered set of properties that are exposed on
* an nsComputedDOMStyle object and how their computed values can be obtained.
@ -1801,24 +1825,6 @@ nsComputedDOMStyle::DoGetFontVariantPosition()
return val.forget();
}
already_AddRefed<CSSValue>
nsComputedDOMStyle::GetBackgroundList(uint8_t nsStyleImageLayers::Layer::* aMember,
uint32_t nsStyleImageLayers::* aCount,
const nsStyleImageLayers& aLayers,
const KTableEntry aTable[])
{
RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
for (uint32_t i = 0, i_end = aLayers.*aCount; i < i_end; ++i) {
RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
val->SetIdent(nsCSSProps::ValueToKeywordEnum(aLayers.mLayers[i].*aMember,
aTable));
valueList->AppendCSSValue(val.forget());
}
return valueList.forget();
}
already_AddRefed<CSSValue>
nsComputedDOMStyle::DoGetBackgroundAttachment()
{
@ -2366,7 +2372,7 @@ nsComputedDOMStyle::DoGetBackgroundOrigin()
return GetBackgroundList(&nsStyleImageLayers::Layer::mOrigin,
&nsStyleImageLayers::mOriginCount,
StyleBackground()->mImage,
nsCSSProps::kImageLayerOriginKTable);
nsCSSProps::kBackgroundOriginKTable);
}
void
@ -5012,12 +5018,6 @@ nsComputedDOMStyle::DoGetTop()
return GetOffsetWidthFor(NS_SIDE_TOP);
}
nsDOMCSSValueList*
nsComputedDOMStyle::GetROCSSValueList(bool aCommaDelimited)
{
return new nsDOMCSSValueList(aCommaDelimited, true);
}
already_AddRefed<CSSValue>
nsComputedDOMStyle::GetOffsetWidthFor(mozilla::css::Side aSide)
{
@ -6179,8 +6179,8 @@ nsComputedDOMStyle::DoGetMask()
// need to support computed style for the cases where it used to be
// a longhand.
if (svg->mMask.mImageCount > 1 ||
firstLayer.mClip != NS_STYLE_IMAGELAYER_CLIP_BORDER ||
firstLayer.mOrigin != NS_STYLE_IMAGELAYER_ORIGIN_BORDER ||
firstLayer.mClip != StyleGeometryBox::Border ||
firstLayer.mOrigin != StyleGeometryBox::Border ||
firstLayer.mComposite != NS_STYLE_MASK_COMPOSITE_ADD ||
firstLayer.mMaskMode != NS_STYLE_MASK_MODE_MATCH_SOURCE ||
!nsStyleImageLayers::IsInitialPositionForLayerType(
@ -6199,14 +6199,13 @@ nsComputedDOMStyle::DoGetMask()
return val.forget();
}
#ifdef MOZ_ENABLE_MASK_AS_SHORTHAND
already_AddRefed<CSSValue>
nsComputedDOMStyle::DoGetMaskClip()
{
return GetBackgroundList(&nsStyleImageLayers::Layer::mClip,
&nsStyleImageLayers::mClipCount,
StyleSVGReset()->mMask,
nsCSSProps::kImageLayerOriginKTable);
nsCSSProps::kMaskClipKTable);
}
already_AddRefed<CSSValue>