issue #908 - implement missing parts of CSS mask

This commit is contained in:
yami 2018-12-16 16:17:20 +01:00 committed by Roy Tam
commit b5376e63c5
28 changed files with 574 additions and 449 deletions

View file

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

View file

@ -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();
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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>
@ -6240,7 +6239,7 @@ nsComputedDOMStyle::DoGetMaskOrigin()
return GetBackgroundList(&nsStyleImageLayers::Layer::mOrigin,
&nsStyleImageLayers::mOriginCount,
StyleSVGReset()->mMask,
nsCSSProps::kImageLayerOriginKTable);
nsCSSProps::kMaskOriginKTable);
}
already_AddRefed<CSSValue>
@ -6277,7 +6276,6 @@ nsComputedDOMStyle::DoGetMaskSize()
const nsStyleImageLayers& layers = StyleSVGReset()->mMask;
return DoGetImageLayerSize(layers);
}
#endif
already_AddRefed<CSSValue>
nsComputedDOMStyle::DoGetMaskType()

View file

@ -53,6 +53,7 @@ private:
// Convenience typedefs:
typedef nsCSSProps::KTableEntry KTableEntry;
typedef mozilla::dom::CSSValue CSSValue;
typedef mozilla::StyleGeometryBox StyleGeometryBox;
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
@ -202,12 +203,6 @@ private:
const nscolor& aDefaultColor,
bool aIsBoxShadow);
already_AddRefed<CSSValue> GetBackgroundList(
uint8_t nsStyleImageLayers::Layer::* aMember,
uint32_t nsStyleImageLayers::* aCount,
const nsStyleImageLayers& aLayers,
const KTableEntry aTable[]);
void GetCSSGradientString(const nsStyleGradient* aGradient,
nsAString& aString);
void GetImageRectString(nsIURI* aURI,
@ -310,7 +305,6 @@ private:
/* Mask properties */
already_AddRefed<CSSValue> DoGetMask();
#ifdef MOZ_ENABLE_MASK_AS_SHORTHAND
already_AddRefed<CSSValue> DoGetMaskImage();
already_AddRefed<CSSValue> DoGetMaskPosition();
already_AddRefed<CSSValue> DoGetMaskPositionX();
@ -321,7 +315,7 @@ private:
already_AddRefed<CSSValue> DoGetMaskSize();
already_AddRefed<CSSValue> DoGetMaskMode();
already_AddRefed<CSSValue> DoGetMaskComposite();
#endif
/* Padding properties */
already_AddRefed<CSSValue> DoGetPaddingTop();
already_AddRefed<CSSValue> DoGetPaddingBottom();
@ -582,8 +576,6 @@ private:
/* Custom properties */
already_AddRefed<CSSValue> DoGetCustomProperty(const nsAString& aPropertyName);
nsDOMCSSValueList* GetROCSSValueList(bool aCommaDelimited);
/* Helper functions */
void SetToRGBAColor(nsROCSSPrimitiveValue* aValue, nscolor aColor);
void SetValueFromComplexColor(nsROCSSPrimitiveValue* aValue,

View file

@ -332,7 +332,6 @@ COMPUTED_STYLE_PROP(marker_end, MarkerEnd)
COMPUTED_STYLE_PROP(marker_mid, MarkerMid)
COMPUTED_STYLE_PROP(marker_start, MarkerStart)
COMPUTED_STYLE_PROP(mask, Mask)
#ifdef MOZ_ENABLE_MASK_AS_SHORTHAND
COMPUTED_STYLE_PROP(mask_clip, MaskClip)
COMPUTED_STYLE_PROP(mask_composite, MaskComposite)
COMPUTED_STYLE_PROP(mask_image, MaskImage)
@ -343,7 +342,6 @@ COMPUTED_STYLE_PROP(mask_position_x, MaskPositionX)
COMPUTED_STYLE_PROP(mask_position_y, MaskPositionY)
COMPUTED_STYLE_PROP(mask_repeat, MaskRepeat)
COMPUTED_STYLE_PROP(mask_size, MaskSize)
#endif
COMPUTED_STYLE_PROP(mask_type, MaskType)
COMPUTED_STYLE_PROP(paint_order, PaintOrder)
COMPUTED_STYLE_PROP(shape_rendering, ShapeRendering)

View file

@ -22,6 +22,7 @@
#include "mozilla/Unused.h"
#include "mozilla/css/Declaration.h"
#include "mozilla/TypeTraits.h"
#include "nsAlgorithm.h" // for clamped()
#include "nsRuleNode.h"
@ -6800,6 +6801,21 @@ struct BackgroundItemComputer<nsCSSValueList, RefPtr<css::URLValueData>>
}
};
template <typename T>
struct BackgroundItemComputer<nsCSSValueList, T>
{
typedef typename EnableIf<IsEnum<T>::value, T>::Type ComputedType;
static void ComputeValue(nsStyleContext* aStyleContext,
const nsCSSValueList* aSpecifiedValue,
ComputedType& aComputedValue,
RuleNodeCacheConditions& aConditions)
{
aComputedValue =
static_cast<T>(aSpecifiedValue->mValue.GetIntValue());
}
};
/* Helper function for ComputePositionValue.
* This function computes a single PositionCoord from two nsCSSValue objects,
* which represent an edge and an offset from that edge.
@ -7353,7 +7369,7 @@ nsRuleNode::ComputeBackgroundData(void* aStartStruct,
bg->mImage.mLayers,
parentBG->mImage.mLayers,
&nsStyleImageLayers::Layer::mClip,
uint8_t(NS_STYLE_IMAGELAYER_CLIP_BORDER),
StyleGeometryBox::Border,
parentBG->mImage.mClipCount,
bg->mImage.mClipCount, maxItemCount, rebuild, conditions);
@ -7372,7 +7388,7 @@ nsRuleNode::ComputeBackgroundData(void* aStartStruct,
bg->mImage.mLayers,
parentBG->mImage.mLayers,
&nsStyleImageLayers::Layer::mOrigin,
uint8_t(NS_STYLE_IMAGELAYER_ORIGIN_PADDING),
StyleGeometryBox::Padding,
parentBG->mImage.mOriginCount,
bg->mImage.mOriginCount, maxItemCount, rebuild,
conditions);
@ -10005,7 +10021,6 @@ nsRuleNode::ComputeSVGResetData(void* aStartStruct,
parentSVGReset->mMaskType,
NS_STYLE_MASK_TYPE_LUMINANCE);
#ifdef MOZ_ENABLE_MASK_AS_SHORTHAND
uint32_t maxItemCount = 1;
bool rebuild = false;
@ -10043,7 +10058,7 @@ nsRuleNode::ComputeSVGResetData(void* aStartStruct,
svgReset->mMask.mLayers,
parentSVGReset->mMask.mLayers,
&nsStyleImageLayers::Layer::mClip,
uint8_t(NS_STYLE_IMAGELAYER_CLIP_BORDER),
StyleGeometryBox::Border,
parentSVGReset->mMask.mClipCount,
svgReset->mMask.mClipCount, maxItemCount, rebuild,
conditions);
@ -10053,7 +10068,7 @@ nsRuleNode::ComputeSVGResetData(void* aStartStruct,
svgReset->mMask.mLayers,
parentSVGReset->mMask.mLayers,
&nsStyleImageLayers::Layer::mOrigin,
uint8_t(NS_STYLE_IMAGELAYER_ORIGIN_BORDER),
StyleGeometryBox::Border,
parentSVGReset->mMask.mOriginCount,
svgReset->mMask.mOriginCount, maxItemCount, rebuild,
conditions);
@ -10113,21 +10128,6 @@ nsRuleNode::ComputeSVGResetData(void* aStartStruct,
if (rebuild) {
FillAllBackgroundLists(svgReset->mMask, maxItemCount);
}
#else
// mask: none | <url>
const nsCSSValue* maskValue = aRuleData->ValueForMask();
if (eCSSUnit_URL == maskValue->GetUnit()) {
svgReset->mMask.mLayers[0].mSourceURI = maskValue->GetURLStructValue();
} else if (eCSSUnit_None == maskValue->GetUnit() ||
eCSSUnit_Initial == maskValue->GetUnit() ||
eCSSUnit_Unset == maskValue->GetUnit()) {
svgReset->mMask.mLayers[0].mSourceURI = nullptr;
} else if (eCSSUnit_Inherit == maskValue->GetUnit()) {
conditions.SetUncacheable();
svgReset->mMask.mLayers[0].mSourceURI =
parentSVGReset->mMask.mLayers[0].mSourceURI;
}
#endif
COMPUTE_END_RESET(SVGReset, svgReset)
}

View file

@ -134,16 +134,35 @@ enum class StyleClear : uint8_t {
Max = 13 // Max = (Both | Line)
};
// clip-path geometry box
enum class StyleClipPathGeometryBox : uint8_t {
NoBox,
// Define geometry box for clip-path's reference-box, background-clip,
// background-origin, mask-clip and mask-origin.
enum class StyleGeometryBox : uint8_t {
Content,
Padding,
Border,
Margin,
Fill,
Stroke,
View,
Margin, // XXX Bug 1260094 comment 9.
// Although margin-box is required by mask-origin and mask-clip, we
// do not implement that due to lack of support in other browsers.
// clip-path reference-box only.
Fill, // mask-clip, mask-origin and clip-path reference-box only.
Stroke, // mask-clip, mask-origin and clip-path reference-box only.
View, // mask-clip, mask-origin and clip-path reference-box only.
NoClip, // mask-clip only.
Text, // background-clip only.
NoBox, // Depending on which kind of element this style value applied on,
// the default value of a reference-box can be different.
// For an HTML element, the default value of reference-box is
// border-box; for an SVG element, the default value is fill-box.
// Since we can not determine the default value at parsing time,
// set it as NoBox so that we make a decision later.
// clip-path reference-box only.
MozAlmostPadding = 127 // A magic value that we use for our "pretend that
// background-clip is 'padding' when we have a solid
// border" optimization. This isn't actually equal
// to StyleGeometryBox::Padding because using that
// causes antialiasing seams between the background
// and border.
// background-clip only.
};
// fill-rule
@ -359,14 +378,6 @@ enum class FillMode : uint32_t;
#define NS_STYLE_IMAGELAYER_ATTACHMENT_FIXED 1
#define NS_STYLE_IMAGELAYER_ATTACHMENT_LOCAL 2
// See nsStyleImageLayers
// Code depends on these constants having the same values as IMAGELAYER_ORIGIN_*
#define NS_STYLE_IMAGELAYER_CLIP_BORDER 0
#define NS_STYLE_IMAGELAYER_CLIP_PADDING 1
#define NS_STYLE_IMAGELAYER_CLIP_CONTENT 2
// One extra constant which does not exist in IMAGELAYER_ORIGIN_*
#define NS_STYLE_IMAGELAYER_CLIP_TEXT 3
// A magic value that we use for our "pretend that background-clip is
// 'padding' when we have a solid border" optimization. This isn't
// actually equal to NS_STYLE_IMAGELAYER_CLIP_PADDING because using that
@ -374,12 +385,6 @@ enum class FillMode : uint32_t;
// is a backend-only value.
#define NS_STYLE_IMAGELAYER_CLIP_MOZ_ALMOST_PADDING 127
// See nsStyleImageLayers
// Code depends on these constants having the same values as BG_CLIP_*
#define NS_STYLE_IMAGELAYER_ORIGIN_BORDER 0
#define NS_STYLE_IMAGELAYER_ORIGIN_PADDING 1
#define NS_STYLE_IMAGELAYER_ORIGIN_CONTENT 2
// See nsStyleImageLayers
// The parser code depends on |ing these values together.
#define NS_STYLE_IMAGELAYER_POSITION_CENTER (1<<0)

View file

@ -2465,7 +2465,6 @@ const nsCSSPropertyID nsStyleImageLayers::kBackgroundLayerTable[] = {
eCSSProperty_UNKNOWN // composite
};
#ifdef MOZ_ENABLE_MASK_AS_SHORTHAND
const nsCSSPropertyID nsStyleImageLayers::kMaskLayerTable[] = {
eCSSProperty_mask, // shorthand
eCSSProperty_UNKNOWN, // color
@ -2480,7 +2479,6 @@ const nsCSSPropertyID nsStyleImageLayers::kMaskLayerTable[] = {
eCSSProperty_mask_mode, // maskMode
eCSSProperty_mask_composite // composite
};
#endif
nsStyleImageLayers::nsStyleImageLayers(nsStyleImageLayers::LayerType aType)
: mAttachmentCount(1)
@ -2787,7 +2785,7 @@ nsStyleImageLayers::Size::operator==(const Size& aOther) const
}
nsStyleImageLayers::Layer::Layer()
: mClip(NS_STYLE_IMAGELAYER_CLIP_BORDER)
: mClip(StyleGeometryBox::Border)
, mAttachment(NS_STYLE_IMAGELAYER_ATTACHMENT_SCROLL)
, mBlendMode(NS_STYLE_BLEND_NORMAL)
, mComposite(NS_STYLE_MASK_COMPOSITE_ADD)
@ -2809,10 +2807,10 @@ nsStyleImageLayers::Layer::Initialize(nsStyleImageLayers::LayerType aType)
mPosition.SetInitialPercentValues(0.0f);
if (aType == LayerType::Background) {
mOrigin = NS_STYLE_IMAGELAYER_ORIGIN_PADDING;
mOrigin = StyleGeometryBox::Padding;
} else {
MOZ_ASSERT(aType == LayerType::Mask, "unsupported layer type.");
mOrigin = NS_STYLE_IMAGELAYER_ORIGIN_BORDER;
mOrigin = StyleGeometryBox::Border;
}
}

View file

@ -782,6 +782,8 @@ struct nsStyleImageLayers {
struct Layer;
friend struct Layer;
struct Layer {
typedef mozilla::StyleGeometryBox StyleGeometryBox;
nsStyleImage mImage; // [reset]
RefPtr<mozilla::css::URLValueData> mSourceURI; // [reset]
// mask-only property
@ -793,9 +795,9 @@ struct nsStyleImageLayers {
// or an ImageValue.)
mozilla::Position mPosition; // [reset]
Size mSize; // [reset]
uint8_t mClip; // [reset] See nsStyleConsts.h
StyleGeometryBox mClip; // [reset] See nsStyleConsts.h
MOZ_INIT_OUTSIDE_CTOR
uint8_t mOrigin; // [reset] See nsStyleConsts.h
StyleGeometryBox mOrigin; // [reset] See nsStyleConsts.h
uint8_t mAttachment; // [reset] See nsStyleConsts.h
// background-only property
// This property is used for background layer
@ -2755,7 +2757,7 @@ private:
ReferenceBox mReferenceBox = ReferenceBox::NoBox;
};
using StyleClipPath = StyleShapeSource<StyleClipPathGeometryBox>;
using StyleClipPath = StyleShapeSource<StyleGeometryBox>;
using StyleShapeOutside = StyleShapeSource<StyleShapeOutsideShapeBox>;
} // namespace mozilla

View file

@ -62,122 +62,12 @@ nsCSSClipPathInstance::HitTestBasicShapeClip(nsIFrame* aFrame,
return path->ContainsPoint(ToPoint(aPoint) * pixelRatio, Matrix());
}
nsRect
nsCSSClipPathInstance::ComputeSVGReferenceRect()
{
MOZ_ASSERT(mTargetFrame->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 (mClipPathStyle.GetReferenceBox()) {
case StyleClipPathGeometryBox::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(mTargetFrame,
nsSVGUtils::eBBoxIncludeFill | nsSVGUtils::eBBoxIncludeStroke);
r = nsLayoutUtils::RoundGfxRectToAppRect(bbox,
nsPresContext::AppUnitsPerCSSPixel());
break;
}
case StyleClipPathGeometryBox::View: {
nsIContent* content = mTargetFrame->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 StyleClipPathGeometryBox::NoBox:
case StyleClipPathGeometryBox::Border:
case StyleClipPathGeometryBox::Content:
case StyleClipPathGeometryBox::Padding:
case StyleClipPathGeometryBox::Margin:
case StyleClipPathGeometryBox::Fill: {
gfxRect bbox = nsSVGUtils::GetBBox(mTargetFrame,
nsSVGUtils::eBBoxIncludeFill);
r = nsLayoutUtils::RoundGfxRectToAppRect(bbox,
nsPresContext::AppUnitsPerCSSPixel());
break;
}
default:{
MOZ_ASSERT_UNREACHABLE("unknown StyleClipPathGeometryBox type");
gfxRect bbox = nsSVGUtils::GetBBox(mTargetFrame,
nsSVGUtils::eBBoxIncludeFill);
r = nsLayoutUtils::RoundGfxRectToAppRect(bbox,
nsPresContext::AppUnitsPerCSSPixel());
break;
}
}
return r;
}
nsRect
nsCSSClipPathInstance::ComputeHTMLReferenceRect()
{
nsRect r;
// For elements with associated CSS layout box, the used value for fill-box,
// stroke-box and view-box is border-box.
switch (mClipPathStyle.GetReferenceBox()) {
case StyleClipPathGeometryBox::Content:
r = mTargetFrame->GetContentRectRelativeToSelf();
break;
case StyleClipPathGeometryBox::Padding:
r = mTargetFrame->GetPaddingRectRelativeToSelf();
break;
case StyleClipPathGeometryBox::Margin:
r = mTargetFrame->GetMarginRectRelativeToSelf();
break;
case StyleClipPathGeometryBox::NoBox:
case StyleClipPathGeometryBox::Border:
case StyleClipPathGeometryBox::Fill:
case StyleClipPathGeometryBox::Stroke:
case StyleClipPathGeometryBox::View:
r = mTargetFrame->GetRectRelativeToSelf();
break;
default:
MOZ_ASSERT_UNREACHABLE("unknown StyleClipPathGeometryBox type");
r = mTargetFrame->GetRectRelativeToSelf();
break;
}
return r;
}
already_AddRefed<Path>
nsCSSClipPathInstance::CreateClipPath(DrawTarget* aDrawTarget)
{
// 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 = mTargetFrame->IsFrameOfType(nsIFrame::eSVG) &&
(mTargetFrame->GetType() != nsGkAtoms::svgOuterSVGFrame)
? ComputeSVGReferenceRect() : ComputeHTMLReferenceRect();
nsRect r =
nsLayoutUtils::ComputeGeometryBox(mTargetFrame,
mClipPathStyle.GetReferenceBox());
if (mClipPathStyle.GetType() != StyleShapeSourceType::Shape) {
// TODO Clip to border-radius/reference box if no shape

View file

@ -48,10 +48,6 @@ private:
already_AddRefed<Path> CreateClipPathInset(DrawTarget* aDrawTarget,
const nsRect& aRefBox);
nsRect ComputeHTMLReferenceRect();
nsRect ComputeSVGReferenceRect();
/**
* The frame for the element that is currently being clipped.
*/

View file

@ -509,71 +509,108 @@ PaintMaskSurface(const PaintFramesParams& aParams,
return DrawResult::SUCCESS;
}
static DrawResult
struct MaskPaintResult {
RefPtr<SourceSurface> maskSurface;
Matrix maskTransform;
DrawResult result;
bool transparentBlackMask;
bool opacityApplied;
MaskPaintResult()
: result(DrawResult::SUCCESS), transparentBlackMask(false),
opacityApplied(false)
{}
};
static MaskPaintResult
CreateAndPaintMaskSurface(const PaintFramesParams& aParams,
float aOpacity, nsStyleContext* aSC,
const nsTArray<nsSVGMaskFrame*>& aMaskFrames,
const nsPoint& aOffsetToUserSpace,
Matrix& aOutMaskTransform,
RefPtr<SourceSurface>& aOutMaskSurface,
bool& aOpacityApplied)
const nsPoint& aOffsetToUserSpace)
{
const nsStyleSVGReset *svgReset = aSC->StyleSVGReset();
MOZ_ASSERT(aMaskFrames.Length() > 0);
MaskPaintResult paintResult;
gfxContext& ctx = aParams.ctx;
// There is only one SVG mask.
// Optimization for single SVG mask.
if (((aMaskFrames.Length() == 1) && aMaskFrames[0])) {
gfxMatrix cssPxToDevPxMatrix =
nsSVGIntegrationUtils::GetCSSPxToDevPxMatrix(aParams.frame);
paintResult.opacityApplied = true;
aOpacityApplied = true;
aOutMaskSurface =
paintResult.maskSurface =
aMaskFrames[0]->GetMaskForMaskedFrame(&ctx, aParams.frame,
cssPxToDevPxMatrix, aOpacity,
&aOutMaskTransform,
&paintResult.maskTransform,
svgReset->mMask.mLayers[0].mMaskMode);
return DrawResult::SUCCESS;
if (!paintResult.maskSurface) {
paintResult.transparentBlackMask = true;
}
return paintResult;
}
const IntRect& maskSurfaceRect = aParams.maskRect;
if (maskSurfaceRect.IsEmpty()) {
return DrawResult::SUCCESS;
paintResult.transparentBlackMask = true;
return paintResult;
}
RefPtr<DrawTarget> maskDT =
ctx.GetDrawTarget()->CreateSimilarDrawTarget(maskSurfaceRect.Size(),
SurfaceFormat::A8);
if (!maskDT || !maskDT->IsValid()) {
return DrawResult::TEMPORARY_ERROR;
paintResult.result = DrawResult::TEMPORARY_ERROR;
return paintResult;
}
// Set aAppliedOpacity as true only if all mask layers are svg mask.
// In this case, we will apply opacity into the final mask surface, so the
// caller does not need to apply it again.
aOpacityApplied = !HasNonSVGMask(aMaskFrames);
paintResult.opacityApplied = !HasNonSVGMask(aMaskFrames);
// Set context's matrix on maskContext, offset by the maskSurfaceRect's
// position. This makes sure that we combine the masks in device space.
gfxMatrix maskSurfaceMatrix =
ctx.CurrentMatrix() * gfxMatrix::Translation(-aParams.maskRect.TopLeft());
DrawResult result = PaintMaskSurface(aParams, maskDT,
aOpacityApplied ? aOpacity : 1.0,
aSC, aMaskFrames, maskSurfaceMatrix,
aOffsetToUserSpace);
if (result != DrawResult::SUCCESS) {
return result;
paintResult.result = PaintMaskSurface(aParams, maskDT,
paintResult.opacityApplied
? aOpacity : 1.0,
aSC, aMaskFrames, maskSurfaceMatrix,
aOffsetToUserSpace);
if (paintResult.result != DrawResult::SUCCESS) {
// Now we know the status of mask resource since we used it while painting.
// According to the return value of PaintMaskSurface, we know whether mask
// resource is resolvable or not.
//
// For a HTML doc:
// According to css-masking spec, always create a mask surface when
// we have any item in maskFrame even if all of those items are
// non-resolvable <mask-sources> or <images>.
// Set paintResult.transparentBlackMask as true, the caller should stop
// painting masked content as if this mask is a transparent black one.
// For a SVG doc:
// SVG 1.1 say that if we fail to resolve a mask, we should draw the
// object unmasked.
// Left patinResult.maskSurface empty, the caller should paint all
// masked content as if this mask is an opaque white one(no mask).
paintResult.transparentBlackMask =
!(aParams.frame->GetStateBits() & NS_FRAME_SVG_LAYOUT);
MOZ_ASSERT(!paintResult.maskSurface);
return paintResult;
}
paintResult.maskTransform = ToMatrix(maskSurfaceMatrix);
if (!paintResult.maskTransform.Invert()) {
return paintResult;
}
aOutMaskTransform = ToMatrix(maskSurfaceMatrix);
if (!aOutMaskTransform.Invert()) {
return DrawResult::SUCCESS;
}
aOutMaskSurface = maskDT->Snapshot();
return DrawResult::SUCCESS;
paintResult.maskSurface = maskDT->Snapshot();
return paintResult;
}
static bool
@ -783,6 +820,8 @@ nsSVGIntegrationUtils::PaintMaskAndClipPath(const PaintFramesParams& aParams)
maskUsage.shouldGenerateClipMaskLayer ||
maskUsage.shouldGenerateMaskLayer);
bool shouldPushMask = false;
/* Check if we need to do additional operations on this child's
* rendering, which necessitates rendering into another surface. */
if (shouldGenerateMask) {
@ -800,14 +839,23 @@ nsSVGIntegrationUtils::PaintMaskAndClipPath(const PaintFramesParams& aParams)
// instead of the first continuation frame.
SetupContextMatrix(frame, aParams, offsetToBoundingBox,
offsetToUserSpace);
result = CreateAndPaintMaskSurface(aParams, maskUsage.opacity,
firstFrame->StyleContext(),
maskFrames, offsetToUserSpace,
maskTransform, maskSurface,
opacityApplied);
if (!maskSurface) {
// Entire surface is clipped out.
return result;
MaskPaintResult paintResult =
CreateAndPaintMaskSurface(aParams, maskUsage.opacity,
firstFrame->StyleContext(),
maskFrames, offsetToUserSpace);
if (paintResult.transparentBlackMask) {
MOZ_ASSERT(paintResult.result != DrawResult::SUCCESS);
return paintResult.result;
}
result &= paintResult.result;
maskSurface = paintResult.maskSurface;
if (maskSurface) {
MOZ_ASSERT(paintResult.result == DrawResult::SUCCESS);
shouldPushMask = true;
maskTransform = paintResult.maskTransform;
opacityApplied = paintResult.opacityApplied;
}
}
@ -831,6 +879,8 @@ nsSVGIntegrationUtils::PaintMaskAndClipPath(const PaintFramesParams& aParams)
// failure in nsSVGClipPathFrame::GetClipMask.
return result;
}
shouldPushMask = true;
}
// opacity != 1.0f.
@ -841,18 +891,22 @@ nsSVGIntegrationUtils::PaintMaskAndClipPath(const PaintFramesParams& aParams)
matSR.SetContext(&context);
SetupContextMatrix(firstFrame, aParams, offsetToBoundingBox,
offsetToUserSpace);
shouldPushMask = true;
}
if (aParams.layerManager->GetRoot()->GetContentFlags() & Layer::CONTENT_COMPONENT_ALPHA) {
context.PushGroupAndCopyBackground(gfxContentType::COLOR_ALPHA,
opacityApplied
? 1.0
: maskUsage.opacity,
maskSurface, maskTransform);
} else {
context.PushGroupForBlendBack(gfxContentType::COLOR_ALPHA,
opacityApplied ? 1.0 : maskUsage.opacity,
maskSurface, maskTransform);
if (shouldPushMask) {
if (aParams.layerManager->GetRoot()->GetContentFlags() &
Layer::CONTENT_COMPONENT_ALPHA) {
context.PushGroupAndCopyBackground(gfxContentType::COLOR_ALPHA,
opacityApplied
? 1.0
: maskUsage.opacity,
maskSurface, maskTransform);
} else {
context.PushGroupForBlendBack(gfxContentType::COLOR_ALPHA,
opacityApplied ? 1.0 : maskUsage.opacity,
maskSurface, maskTransform);
}
}
}
@ -899,7 +953,7 @@ nsSVGIntegrationUtils::PaintMaskAndClipPath(const PaintFramesParams& aParams)
context.PopClip();
}
if (shouldGenerateMask) {
if (shouldPushMask) {
context.PopGroupAndBlend();
}

View file

@ -514,26 +514,7 @@ nsSVGUtils::DetermineMaskUsage(nsIFrame* aFrame, bool aHandleOpacity,
nsTArray<nsSVGMaskFrame*> maskFrames = effectProperties.GetMaskFrames();
#ifdef MOZ_ENABLE_MASK_AS_SHORTHAND
// For a HTML doc:
// According to css-masking spec, always create a mask surface when we
// have any item in maskFrame even if all of those items are
// non-resolvable <mask-sources> or <images>, we still need to create a
// transparent black mask layer under this condition.
// For a SVG doc:
// SVG 1.1 say that if we fail to resolve a mask, we should draw the
// object unmasked.
aUsage.shouldGenerateMaskLayer =
(aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT)
? maskFrames.Length() == 1 && maskFrames[0]
: maskFrames.Length() > 0;
#else
// Since we do not support image mask so far, we should treat any
// unresolvable mask as no mask. Otherwise, any object with a valid image
// mask, e.g. url("xxx.png"), will become invisible just because we can not
// handle image mask correctly. (See bug 1294171)
aUsage.shouldGenerateMaskLayer = maskFrames.Length() == 1 && maskFrames[0];
#endif
aUsage.shouldGenerateMaskLayer = (maskFrames.Length() > 0);
bool isOK = effectProperties.HasNoFilterOrHasValidFilter();
nsSVGClipPathFrame *clipPathFrame = effectProperties.GetClipPathFrame(&isOK);

View file

@ -5680,22 +5680,6 @@ fi
AC_SUBST(PREPROCESS_OPTION)
dnl ========================================================
dnl mask as shorthand property
dnl ========================================================
# The control structure code will be removed as soon as the feature is stable
# Refer to bug 1281101 for more details.
# Enable mask-as-shorthand property by default for nightly and aurora channels
if test -z "$RELEASE_OR_BETA"; then
dnl mask as shorthand property enabled
MOZ_ENABLE_MASK_AS_SHORTHAND=1
AC_DEFINE(MOZ_ENABLE_MASK_AS_SHORTHAND)
fi
AC_SUBST(MOZ_ENABLE_MASK_AS_SHORTHAND)
# Avoid using obsolete NSPR features
AC_DEFINE(NO_NSPR_10_SUPPORT)