Skip to content

Commit

Permalink
issue #908 - implement missing parts of CSS mask
Browse files Browse the repository at this point in the history
  • Loading branch information
kn-yami committed Feb 2, 2019
1 parent fa311a4 commit b241a84
Show file tree
Hide file tree
Showing 28 changed files with 574 additions and 449 deletions.
215 changes: 171 additions & 44 deletions layout/base/nsCSSRendering.cpp

Large diffs are not rendered by default.

22 changes: 11 additions & 11 deletions layout/base/nsDisplayList.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -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());
Expand Down Expand Up @@ -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);
}
}
Expand Down Expand Up @@ -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;
}
Expand All @@ -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();
}

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

Expand Down
8 changes: 6 additions & 2 deletions layout/base/nsDisplayList.h
Original file line number Diff line number Diff line change
Expand Up @@ -2713,6 +2713,8 @@ class nsDisplaySolidColorRegion : public nsDisplayItem {
*/
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.
Expand Down Expand Up @@ -2790,8 +2792,10 @@ class nsDisplayBackgroundImage : public nsDisplayImageContainer {
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;

Expand Down
127 changes: 126 additions & 1 deletion layout/base/nsLayoutUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@
#include "mozilla/StyleSetHandle.h"
#include "mozilla/StyleSetHandleInlines.h"
#include "RegionBuilder.h"
#include "SVGSVGElement.h"

#ifdef MOZ_XUL
#include "nsXULPopupManager.h"
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}
5 changes: 5 additions & 0 deletions layout/base/nsLayoutUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "mozilla/ReflowOutput.h"
#include "ImageContainer.h"
#include "gfx2DGlue.h"
#include "nsStyleConsts.h"

#include <limits>
#include <algorithm>
Expand Down Expand Up @@ -152,6 +153,7 @@ class nsLayoutUtils
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.
Expand Down Expand Up @@ -2870,6 +2872,9 @@ class nsLayoutUtils
*/
static bool IsInvisibleBreak(nsINode* aNode, nsIFrame** aNextLineFrame = nullptr);

static nsRect ComputeGeometryBox(nsIFrame* aFrame,
StyleGeometryBox aGeometryBox);

private:
static uint32_t sFontSizeInflationEmPerLine;
static uint32_t sFontSizeInflationMinTwips;
Expand Down
2 changes: 1 addition & 1 deletion layout/generic/nsTextFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Expand Down
2 changes: 0 additions & 2 deletions layout/inspector/inDOMUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
39 changes: 13 additions & 26 deletions layout/style/Declaration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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.
Expand All @@ -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.
Expand Down Expand Up @@ -817,7 +806,6 @@ Declaration::GetPropertyValueInternal(
nsStyleImageLayers::kBackgroundLayerTable);
break;
}
#ifdef MOZ_ENABLE_MASK_AS_SHORTHAND
case eCSSProperty_mask: {
GetImageLayerValue(data, aValue, aSerialization,
nsStyleImageLayers::kMaskLayerTable);
Expand All @@ -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
Expand Down
4 changes: 0 additions & 4 deletions layout/style/StyleAnimationValue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 =
Expand Down
Loading

0 comments on commit b241a84

Please sign in to comment.