diff options
Diffstat (limited to 'layout')
27 files changed, 574 insertions, 433 deletions
diff --git a/layout/base/nsCSSRendering.cpp b/layout/base/nsCSSRendering.cpp index 71ebfad22..ff9edf742 100644 --- a/layout/base/nsCSSRendering.cpp +++ b/layout/base/nsCSSRendering.cpp @@ -1803,6 +1803,44 @@ SetupDirtyRects(const nsRect& aBGClipArea, const nsRect& aCallerDirtyRect, "second should be empty if first is"); } +static bool +IsSVGStyleGeometryBox(StyleGeometryBox aBox) +{ + return (aBox == StyleGeometryBox::Fill || aBox == StyleGeometryBox::Stroke || + aBox == StyleGeometryBox::View); +} + +static bool +IsHTMLStyleGeometryBox(StyleGeometryBox aBox) +{ + return (aBox == StyleGeometryBox::Content || + aBox == StyleGeometryBox::Padding || + aBox == StyleGeometryBox::Border || + aBox == StyleGeometryBox::Margin); +} + +static StyleGeometryBox +ComputeBoxValue(nsIFrame* aForFrame, StyleGeometryBox aBox) +{ + // Except <svg>, all svg elements are not associate with CSS layout box. + if (aForFrame->IsFrameOfType(nsIFrame::eSVG) && + (aForFrame->GetType() != nsGkAtoms::svgOuterSVGFrame)) { + // For SVG elements without associated CSS layout box, the values + // content-box, padding-box, border-box and margin-box compute to fill-box. + if (IsHTMLStyleGeometryBox(aBox)) { + return StyleGeometryBox::Fill; + } + } else { + // For elements with associated CSS layout box, the values fill-box, + // stroke-box and view-box compute to the initial value of mask-clip. + if (IsSVGStyleGeometryBox(aBox)) { + return StyleGeometryBox::Border; + } + } + + return aBox; +} + /* static */ void nsCSSRendering::GetImageLayerClip(const nsStyleImageLayers::Layer& aLayer, nsIFrame* aForFrame, const nsStyleBorder& aBorder, @@ -1810,6 +1848,55 @@ nsCSSRendering::GetImageLayerClip(const nsStyleImageLayers::Layer& aLayer, bool aWillPaintBorder, nscoord aAppUnitsPerPixel, /* out */ ImageLayerClipState* aClipState) { + StyleGeometryBox layerClip = ComputeBoxValue(aForFrame, aLayer.mClip); + + if (IsSVGStyleGeometryBox(layerClip)) { + MOZ_ASSERT(aForFrame->IsFrameOfType(nsIFrame::eSVG) && + (aForFrame->GetType() != nsGkAtoms::svgOuterSVGFrame)); + + aClipState->mHasAdditionalBGClipArea = false; + aClipState->mCustomClip = false; + + // The coordinate space of clipArea is svg user space. + nsRect clipArea = + nsLayoutUtils::ComputeGeometryBox(aForFrame, layerClip); + + nsRect strokeBox = (layerClip == StyleGeometryBox::Stroke) + ? clipArea + : nsLayoutUtils::ComputeGeometryBox(aForFrame, StyleGeometryBox::Stroke); + nsRect clipAreaRelativeToStrokeBox = clipArea - strokeBox.TopLeft(); + + // aBorderArea is the stroke-box area in a coordinate space defined by + // the caller. This coordinate space can be svg user space of aForFrame, + // the space of aForFrame's reference-frame, or anything else. + // + // Which coordinate space chosen for aBorderArea is not matter. What + // matter is to ensure returning aClipState->mBGClipArea in the consistent + // coordiante space with aBorderArea. So we evaluate the position of clip + // area base on the position of aBorderArea here. + aClipState->mBGClipArea = + clipAreaRelativeToStrokeBox + aBorderArea.TopLeft(); + + SetupDirtyRects(aClipState->mBGClipArea, aCallerDirtyRect, + aAppUnitsPerPixel, &aClipState->mDirtyRect, + &aClipState->mDirtyRectGfx); + return; + } + + if (layerClip == StyleGeometryBox::NoClip) { + aClipState->mBGClipArea = aCallerDirtyRect; + aClipState->mHasAdditionalBGClipArea = false; + aClipState->mCustomClip = false; + + SetupDirtyRects(aClipState->mBGClipArea, aCallerDirtyRect, + aAppUnitsPerPixel, &aClipState->mDirtyRect, + &aClipState->mDirtyRectGfx); + return; + } + + MOZ_ASSERT(!aForFrame->IsFrameOfType(nsIFrame::eSVG) || + aForFrame->GetType() == nsGkAtoms::svgOuterSVGFrame); + // Compute the outermost boundary of the area that might be painted. // Same coordinate space as aBorderArea. Sides skipSides = aForFrame->GetSkipSides(); @@ -1819,16 +1906,15 @@ nsCSSRendering::GetImageLayerClip(const nsStyleImageLayers::Layer& aLayer, bool haveRoundedCorners = GetRadii(aForFrame, aBorder, aBorderArea, clipBorderArea, aClipState->mRadii); - uint8_t backgroundClip = aLayer.mClip; - bool isSolidBorder = aWillPaintBorder && IsOpaqueBorder(aBorder); - if (isSolidBorder && backgroundClip == NS_STYLE_IMAGELAYER_CLIP_BORDER) { + if (isSolidBorder && layerClip == StyleGeometryBox::Border) { // If we have rounded corners, we need to inflate the background // drawing area a bit to avoid seams between the border and // background. - backgroundClip = haveRoundedCorners ? - NS_STYLE_IMAGELAYER_CLIP_MOZ_ALMOST_PADDING : NS_STYLE_IMAGELAYER_CLIP_PADDING; + layerClip = haveRoundedCorners + ? StyleGeometryBox::MozAlmostPadding + : StyleGeometryBox::Padding; } aClipState->mBGClipArea = clipBorderArea; @@ -1844,7 +1930,7 @@ nsCSSRendering::GetImageLayerClip(const nsStyleImageLayers::Layer& aLayer, // but the background is also clipped at a non-scrolling 'padding-box' // like the content. (See below.) // Therefore, only 'content-box' makes a difference here. - if (backgroundClip == NS_STYLE_IMAGELAYER_CLIP_CONTENT) { + if (layerClip == StyleGeometryBox::Content) { nsIScrollableFrame* scrollableFrame = do_QueryFrame(aForFrame); // Clip at a rectangle attached to the scrolled content. aClipState->mHasAdditionalBGClipArea = true; @@ -1864,22 +1950,30 @@ nsCSSRendering::GetImageLayerClip(const nsStyleImageLayers::Layer& aLayer, // Also clip at a non-scrolling, rounded-corner 'padding-box', // same as the scrolled content because of the 'overflow' property. - backgroundClip = NS_STYLE_IMAGELAYER_CLIP_PADDING; + layerClip = StyleGeometryBox::Padding; } - if (backgroundClip != NS_STYLE_IMAGELAYER_CLIP_BORDER && - backgroundClip != NS_STYLE_IMAGELAYER_CLIP_TEXT) { + // See the comment of StyleGeometryBox::Margin. + // Hitting this assertion means we decide to turn on margin-box support for + // positioned mask from CSS parser and style system. In this case, you + // should *inflate* mBGClipArea by the margin returning from + // aForFrame->GetUsedMargin() in the code chunk bellow. + MOZ_ASSERT(layerClip != StyleGeometryBox::Margin, + "StyleGeometryBox::Margin rendering is not supported yet.\n"); + + if (layerClip != StyleGeometryBox::Border && + layerClip != StyleGeometryBox::Text) { nsMargin border = aForFrame->GetUsedBorder(); - if (backgroundClip == NS_STYLE_IMAGELAYER_CLIP_MOZ_ALMOST_PADDING) { + if (layerClip == StyleGeometryBox::MozAlmostPadding) { // Reduce |border| by 1px (device pixels) on all sides, if // possible, so that we don't get antialiasing seams between the - // background and border. + // {background|mask} and border. border.top = std::max(0, border.top - aAppUnitsPerPixel); border.right = std::max(0, border.right - aAppUnitsPerPixel); border.bottom = std::max(0, border.bottom - aAppUnitsPerPixel); border.left = std::max(0, border.left - aAppUnitsPerPixel); - } else if (backgroundClip != NS_STYLE_IMAGELAYER_CLIP_PADDING) { - NS_ASSERTION(backgroundClip == NS_STYLE_IMAGELAYER_CLIP_CONTENT, + } else if (layerClip != StyleGeometryBox::Padding) { + NS_ASSERTION(layerClip == StyleGeometryBox::Content, "unexpected background-clip"); border += aForFrame->GetUsedPadding(); } @@ -3163,7 +3257,7 @@ nsCSSRendering::PaintBackgroundWithSC(const PaintBGParams& aParams, if (drawBackgroundImage) { bool clipSet = false; - uint8_t currentBackgroundClip = NS_STYLE_IMAGELAYER_CLIP_BORDER; + StyleGeometryBox currentBackgroundClip = StyleGeometryBox::Border; NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT_WITH_RANGE(i, layers, layers.mImageCount - 1, nLayers + (layers.mImageCount - startLayer - 1)) { @@ -3239,16 +3333,43 @@ nsCSSRendering::ComputeImageLayerPositioningArea(nsPresContext* aPresContext, nsIFrame** aAttachedToFrame, bool* aOutIsTransformedFixed) { - // Compute background origin area relative to aBorderArea now as we may need - // it to compute the effective image size for a CSS gradient. - nsRect bgPositioningArea; + // Compute {background|mask} origin area relative to aBorderArea now as we + // may need it to compute the effective image size for a CSS gradient. + nsRect positionArea; + + StyleGeometryBox layerOrigin = + ComputeBoxValue(aForFrame, aLayer.mOrigin); + + if (IsSVGStyleGeometryBox(layerOrigin)) { + MOZ_ASSERT(aForFrame->IsFrameOfType(nsIFrame::eSVG) && + (aForFrame->GetType() != nsGkAtoms::svgOuterSVGFrame)); + *aAttachedToFrame = aForFrame; + + positionArea = + nsLayoutUtils::ComputeGeometryBox(aForFrame, layerOrigin); + + nsPoint toStrokeBoxOffset = nsPoint(0, 0); + if (layerOrigin != StyleGeometryBox::Stroke) { + nsRect strokeBox = + nsLayoutUtils::ComputeGeometryBox(aForFrame, + StyleGeometryBox::Stroke); + toStrokeBoxOffset = positionArea.TopLeft() - strokeBox.TopLeft(); + } + + // For SVG frames, the return value is relative to the stroke box + return nsRect(toStrokeBoxOffset, positionArea.Size()); + } + + MOZ_ASSERT(!aForFrame->IsFrameOfType(nsIFrame::eSVG) || + aForFrame->GetType() == nsGkAtoms::svgOuterSVGFrame); + nsIAtom* frameType = aForFrame->GetType(); nsIFrame* geometryFrame = aForFrame; if (MOZ_UNLIKELY(frameType == nsGkAtoms::scrollFrame && NS_STYLE_IMAGELAYER_ATTACHMENT_LOCAL == aLayer.mAttachment)) { nsIScrollableFrame* scrollableFrame = do_QueryFrame(aForFrame); - bgPositioningArea = nsRect( + positionArea = nsRect( scrollableFrame->GetScrolledFrame()->GetPosition() // For the dir=rtl case: + scrollableFrame->GetScrollRange().TopLeft(), @@ -3256,20 +3377,20 @@ nsCSSRendering::ComputeImageLayerPositioningArea(nsPresContext* aPresContext, // The ScrolledRect’s size does not include the borders or scrollbars, // reverse the handling of background-origin // compared to the common case below. - if (aLayer.mOrigin == NS_STYLE_IMAGELAYER_ORIGIN_BORDER) { + if (layerOrigin == StyleGeometryBox::Border) { nsMargin border = geometryFrame->GetUsedBorder(); border.ApplySkipSides(geometryFrame->GetSkipSides()); - bgPositioningArea.Inflate(border); - bgPositioningArea.Inflate(scrollableFrame->GetActualScrollbarSizes()); - } else if (aLayer.mOrigin != NS_STYLE_IMAGELAYER_ORIGIN_PADDING) { + positionArea.Inflate(border); + positionArea.Inflate(scrollableFrame->GetActualScrollbarSizes()); + } else if (layerOrigin != StyleGeometryBox::Padding) { nsMargin padding = geometryFrame->GetUsedPadding(); padding.ApplySkipSides(geometryFrame->GetSkipSides()); - bgPositioningArea.Deflate(padding); - NS_ASSERTION(aLayer.mOrigin == NS_STYLE_IMAGELAYER_ORIGIN_CONTENT, + positionArea.Deflate(padding); + NS_ASSERTION(layerOrigin == StyleGeometryBox::Content, "unknown background-origin value"); } *aAttachedToFrame = aForFrame; - return bgPositioningArea; + return positionArea; } if (MOZ_UNLIKELY(frameType == nsGkAtoms::canvasFrame)) { @@ -3279,25 +3400,31 @@ nsCSSRendering::ComputeImageLayerPositioningArea(nsPresContext* aPresContext, // finished and this page only displays the continuations of // absolutely positioned content). if (geometryFrame) { - bgPositioningArea = geometryFrame->GetRect(); + positionArea = geometryFrame->GetRect(); } } else { - bgPositioningArea = nsRect(nsPoint(0,0), aBorderArea.Size()); + positionArea = nsRect(nsPoint(0,0), aBorderArea.Size()); } - // Background images are tiled over the 'background-clip' area - // but the origin of the tiling is based on the 'background-origin' area - // XXX: Bug 1303623 will bring in new origin value, we should iterate from - // NS_STYLE_IMAGELAYER_ORIGIN_MARGIN instead of - // NS_STYLE_IMAGELAYER_ORIGIN_BORDER. - if (aLayer.mOrigin != NS_STYLE_IMAGELAYER_ORIGIN_BORDER && geometryFrame) { + // See the comment of StyleGeometryBox::Margin. + // Hitting this assertion means we decide to turn on margin-box support for + // positioned mask from CSS parser and style system. In this case, you + // should *inflate* positionArea by the margin returning from + // geometryFrame->GetUsedMargin() in the code chunk bellow. + MOZ_ASSERT(aLayer.mOrigin != StyleGeometryBox::Margin, + "StyleGeometryBox::Margin rendering is not supported yet.\n"); + + // {background|mask} images are tiled over the '{background|mask}-clip' area + // but the origin of the tiling is based on the '{background|mask}-origin' + // area. + if (layerOrigin != StyleGeometryBox::Border && geometryFrame) { nsMargin border = geometryFrame->GetUsedBorder(); - if (aLayer.mOrigin != NS_STYLE_IMAGELAYER_ORIGIN_PADDING) { + if (layerOrigin != StyleGeometryBox::Padding) { border += geometryFrame->GetUsedPadding(); - NS_ASSERTION(aLayer.mOrigin == NS_STYLE_IMAGELAYER_ORIGIN_CONTENT, + NS_ASSERTION(layerOrigin == StyleGeometryBox::Content, "unknown background-origin value"); } - bgPositioningArea.Deflate(border); + positionArea.Deflate(border); } nsIFrame* attachedToFrame = aForFrame; @@ -3325,7 +3452,7 @@ nsCSSRendering::ComputeImageLayerPositioningArea(nsPresContext* aPresContext, } else { // Set the background positioning area to the viewport's area // (relative to aForFrame) - bgPositioningArea = + positionArea = nsRect(-aForFrame->GetOffsetTo(attachedToFrame), attachedToFrame->GetSize()); if (!pageContentFrame) { @@ -3334,14 +3461,14 @@ nsCSSRendering::ComputeImageLayerPositioningArea(nsPresContext* aPresContext, aPresContext->PresShell()->GetRootScrollFrameAsScrollable(); if (scrollableFrame) { nsMargin scrollbars = scrollableFrame->GetActualScrollbarSizes(); - bgPositioningArea.Deflate(scrollbars); + positionArea.Deflate(scrollbars); } } } } *aAttachedToFrame = attachedToFrame; - return bgPositioningArea; + return positionArea; } // Implementation of the formula for computation of background-repeat round @@ -3569,7 +3696,7 @@ nsCSSRendering::PrepareImageLayer(nsPresContext* aPresContext, bool transformedFixed = false; // Compute background origin area relative to aBorderArea now as we may need // it to compute the effective image size for a CSS gradient. - nsRect bgPositioningArea = + nsRect positionArea = ComputeImageLayerPositioningArea(aPresContext, aForFrame, aBorderArea, aLayer, &attachedToFrame, &transformedFixed); if (aOutIsTransformedFixed) { @@ -3594,7 +3721,7 @@ nsCSSRendering::PrepareImageLayer(nsPresContext* aPresContext, // not a pure optimization since it can affect the values of pixels at the // edge of the viewport --- whether they're sampled from a putative "next // tile" or not.) - bgClipRect.IntersectRect(bgClipRect, bgPositioningArea + aBorderArea.TopLeft()); + bgClipRect.IntersectRect(bgClipRect, positionArea + aBorderArea.TopLeft()); } } @@ -3605,7 +3732,7 @@ nsCSSRendering::PrepareImageLayer(nsPresContext* aPresContext, // Also as required for proper background positioning when background-position // is defined with percentages. CSSSizeOrRatio intrinsicSize = state.mImageRenderer.ComputeIntrinsicSize(); - nsSize bgPositionSize = bgPositioningArea.Size(); + nsSize bgPositionSize = positionArea.Size(); nsSize imageSize = ComputeDrawnSizeForBackground(intrinsicSize, bgPositionSize, aLayer.mSize, @@ -3650,8 +3777,8 @@ nsCSSRendering::PrepareImageLayer(nsPresContext* aPresContext, } } - imageTopLeft += bgPositioningArea.TopLeft(); - state.mAnchor += bgPositioningArea.TopLeft(); + imageTopLeft += positionArea.TopLeft(); + state.mAnchor += positionArea.TopLeft(); state.mDestArea = nsRect(imageTopLeft + aBorderArea.TopLeft(), imageSize); state.mFillArea = state.mDestArea; diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index 2b9ad7ff8..d619576ba 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -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(); } diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h index 9603a95b8..c9f773f5b 100644 --- a/layout/base/nsDisplayList.h +++ b/layout/base/nsDisplayList.h @@ -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; diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 19200d5a7..f0341f9ef 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -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; +} diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h index 97fc410b0..63253fd10 100644 --- a/layout/base/nsLayoutUtils.h +++ b/layout/base/nsLayoutUtils.h @@ -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; diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp index fa31443fd..3288d3f2e 100644 --- a/layout/generic/nsTextFrame.cpp +++ b/layout/generic/nsTextFrame.cpp @@ -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; } } diff --git a/layout/inspector/inDOMUtils.cpp b/layout/inspector/inDOMUtils.cpp index 9f1dcaad3..e212e20df 100644 --- a/layout/inspector/inDOMUtils.cpp +++ b/layout/inspector/inDOMUtils.cpp @@ -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: diff --git a/layout/style/Declaration.cpp b/layout/style/Declaration.cpp index c67f6b2a2..b2de159ed 100644 --- a/layout/style/Declaration.cpp +++ b/layout/style/Declaration.cpp @@ -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 diff --git a/layout/style/StyleAnimationValue.cpp b/layout/style/StyleAnimationValue.cpp index eb34c3d83..a0f52b4ea 100644 --- a/layout/style/StyleAnimationValue.cpp +++ b/layout/style/StyleAnimationValue.cpp @@ -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 = diff --git a/layout/style/nsCSSDataBlock.cpp b/layout/style/nsCSSDataBlock.cpp index fe2dc621a..1dfdaed0e 100644 --- a/layout/style/nsCSSDataBlock.cpp +++ b/layout/style/nsCSSDataBlock.cpp @@ -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, diff --git a/layout/style/nsCSSKeywordList.h b/layout/style/nsCSSKeywordList.h index 94968faca..34a46ffce 100644 --- a/layout/style/nsCSSKeywordList.h +++ b/layout/style/nsCSSKeywordList.h @@ -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) diff --git a/layout/style/nsCSSParser.cpp b/layout/style/nsCSSParser.cpp index 736c66f87..a8309314f 100644 --- a/layout/style/nsCSSParser.cpp +++ b/layout/style/nsCSSParser.cpp @@ -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]); diff --git a/layout/style/nsCSSPropAliasList.h b/layout/style/nsCSSPropAliasList.h index 2699549ff..f7938af9e 100644 --- a/layout/style/nsCSSPropAliasList.h +++ b/layout/style/nsCSSPropAliasList.h @@ -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 diff --git a/layout/style/nsCSSPropList.h b/layout/style/nsCSSPropList.h index b04921dcb..2049f70e8 100644 --- a/layout/style/nsCSSPropList.h +++ b/layout/style/nsCSSPropList.h @@ -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, diff --git a/layout/style/nsCSSProps.cpp b/layout/style/nsCSSProps.cpp index 9805eae14..ac2978c27 100644 --- a/layout/style/nsCSSProps.cpp +++ b/layout/style/nsCSSProps.cpp @@ -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. diff --git a/layout/style/nsCSSProps.h b/layout/style/nsCSSProps.h index dfe35afd8..e67e1d41d 100644 --- a/layout/style/nsCSSProps.h +++ b/layout/style/nsCSSProps.h @@ -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[]; diff --git a/layout/style/nsComputedDOMStyle.cpp b/layout/style/nsComputedDOMStyle.cpp index 4f8d3edf6..36c3a6385 100644 --- a/layout/style/nsComputedDOMStyle.cpp +++ b/layout/style/nsComputedDOMStyle.cpp @@ -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. @@ -1803,24 +1827,6 @@ nsComputedDOMStyle::DoGetFontVariantPosition() } 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() { return GetBackgroundList(&nsStyleImageLayers::Layer::mAttachment, @@ -2367,7 +2373,7 @@ nsComputedDOMStyle::DoGetBackgroundOrigin() return GetBackgroundList(&nsStyleImageLayers::Layer::mOrigin, &nsStyleImageLayers::mOriginCount, StyleBackground()->mImage, - nsCSSProps::kImageLayerOriginKTable); + nsCSSProps::kBackgroundOriginKTable); } void @@ -5013,12 +5019,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) { @@ -6180,8 +6180,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( @@ -6200,14 +6200,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> @@ -6241,7 +6240,7 @@ nsComputedDOMStyle::DoGetMaskOrigin() return GetBackgroundList(&nsStyleImageLayers::Layer::mOrigin, &nsStyleImageLayers::mOriginCount, StyleSVGReset()->mMask, - nsCSSProps::kImageLayerOriginKTable); + nsCSSProps::kMaskOriginKTable); } already_AddRefed<CSSValue> @@ -6278,7 +6277,6 @@ nsComputedDOMStyle::DoGetMaskSize() const nsStyleImageLayers& layers = StyleSVGReset()->mMask; return DoGetImageLayerSize(layers); } -#endif already_AddRefed<CSSValue> nsComputedDOMStyle::DoGetMaskType() diff --git a/layout/style/nsComputedDOMStyle.h b/layout/style/nsComputedDOMStyle.h index 27e2086e9..77df71ec8 100644 --- a/layout/style/nsComputedDOMStyle.h +++ b/layout/style/nsComputedDOMStyle.h @@ -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, diff --git a/layout/style/nsComputedDOMStylePropertyList.h b/layout/style/nsComputedDOMStylePropertyList.h index 1983208ac..825976b58 100644 --- a/layout/style/nsComputedDOMStylePropertyList.h +++ b/layout/style/nsComputedDOMStylePropertyList.h @@ -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) diff --git a/layout/style/nsRuleNode.cpp b/layout/style/nsRuleNode.cpp index 9b9fc3948..6bcef02a0 100644 --- a/layout/style/nsRuleNode.cpp +++ b/layout/style/nsRuleNode.cpp @@ -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) } diff --git a/layout/style/nsStyleConsts.h b/layout/style/nsStyleConsts.h index be588113e..6d207aec9 100644 --- a/layout/style/nsStyleConsts.h +++ b/layout/style/nsStyleConsts.h @@ -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 @@ -375,12 +386,6 @@ enum class FillMode : uint32_t; #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) #define NS_STYLE_IMAGELAYER_POSITION_TOP (1<<1) diff --git a/layout/style/nsStyleStruct.cpp b/layout/style/nsStyleStruct.cpp index 52491a288..72c103724 100644 --- a/layout/style/nsStyleStruct.cpp +++ b/layout/style/nsStyleStruct.cpp @@ -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; } } diff --git a/layout/style/nsStyleStruct.h b/layout/style/nsStyleStruct.h index 1cadea840..c8182b8f1 100644 --- a/layout/style/nsStyleStruct.h +++ b/layout/style/nsStyleStruct.h @@ -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 diff --git a/layout/svg/nsCSSClipPathInstance.cpp b/layout/svg/nsCSSClipPathInstance.cpp index 828b10eac..01f7de248 100644 --- a/layout/svg/nsCSSClipPathInstance.cpp +++ b/layout/svg/nsCSSClipPathInstance.cpp @@ -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 diff --git a/layout/svg/nsCSSClipPathInstance.h b/layout/svg/nsCSSClipPathInstance.h index 3b0724dbd..33d92e738 100644 --- a/layout/svg/nsCSSClipPathInstance.h +++ b/layout/svg/nsCSSClipPathInstance.h @@ -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. */ diff --git a/layout/svg/nsSVGIntegrationUtils.cpp b/layout/svg/nsSVGIntegrationUtils.cpp index 498f69393..0003e1a73 100644 --- a/layout/svg/nsSVGIntegrationUtils.cpp +++ b/layout/svg/nsSVGIntegrationUtils.cpp @@ -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; - } - - aOutMaskTransform = ToMatrix(maskSurfaceMatrix); - if (!aOutMaskTransform.Invert()) { - return DrawResult::SUCCESS; + 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; } - 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(); } diff --git a/layout/svg/nsSVGUtils.cpp b/layout/svg/nsSVGUtils.cpp index 344ebf645..0bded21ff 100644 --- a/layout/svg/nsSVGUtils.cpp +++ b/layout/svg/nsSVGUtils.cpp @@ -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); |