mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-03 22:38:41 +09:00
issue #908 - implement missing parts of CSS mask
This commit is contained in:
parent
7b5e5f85de
commit
b5376e63c5
28 changed files with 574 additions and 449 deletions
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue