Skip to content

Commit

Permalink
Unprefix -webkit-mask
Browse files Browse the repository at this point in the history
This patch adds a new `mask` property which is an unprefixed version
of `-webkit-mask`. The new property is behind the experimental flag
CSSMaskingInterop. There was an existing `mask` property for SVG mask
references, and we keep that working by passing the first mask-image
reference to SVG via StyleAdjuster.

The bulk of the implementation is in
`ComputedStyleUtils::ValuesForMaskShorthand`, which is tested by the
new `mask-computed.html` test, and
`StylePropertySerializer::GetLayeredShorthandValue`, which is tested by
the existing `mask-valid.sub.html`.

Syntax (https://drafts.fxtf.org/css-masking/#the-mask):
  mask =
    <mask-layer>#
  <mask-layer> =
    <mask-reference>              ||
    <position> [ / <bg-size> ]?   ||
    <repeat-style>                ||
    <geometry-box>                ||
    [ <geometry-box> | no-clip ]  ||
    <compositing-operator>        ||
    <masking-mode>

Bug: 1418401
Change-Id: I917045c7f466862dd1370d5c0ccb845f0223fa83
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4938375
Reviewed-by: Traian Captan <tcaptan@chromium.org>
Auto-Submit: Philip Rogers <pdr@chromium.org>
Commit-Queue: Philip Rogers <pdr@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1215698}
  • Loading branch information
progers authored and Chromium LUCI CQ committed Oct 26, 2023
1 parent e381e58 commit c3d96dd
Show file tree
Hide file tree
Showing 26 changed files with 505 additions and 104 deletions.
19 changes: 13 additions & 6 deletions third_party/blink/renderer/core/css/css_properties.json5
Original file line number Diff line number Diff line change
Expand Up @@ -7560,6 +7560,18 @@
longhands: ["column-width", "column-count"],
property_methods: ["ParseShorthand", "CSSValueFromComputedStyleInternal"],
},
// This alternative of mask is active when CSSMaskingInterop is enabled.
{
name: "-alternative-mask",
alternative_of: "mask",
longhands: [
"mask-image", "-webkit-mask-position-x",
"-webkit-mask-position-y", "mask-size", "mask-repeat", "mask-origin",
"mask-clip", "mask-composite"
],
property_methods: ["ParseShorthand", "CSSValueFromComputedStyleInternal"],
runtime_flag: "CSSMaskingInterop",
},
{
name: "-webkit-mask",
longhands: [
Expand All @@ -7574,12 +7586,7 @@
{
name: "-webkit-alternative-mask",
alternative_of: "-webkit-mask",
longhands: [
"mask-image", "-webkit-mask-position-x",
"-webkit-mask-position-y", "mask-size", "mask-repeat",
"mask-origin", "mask-clip"
],
property_methods: ["ParseShorthand"],
alias_for: "-alternative-mask",
runtime_flag: "CSSMaskingInterop",
},
{
Expand Down
3 changes: 2 additions & 1 deletion third_party/blink/renderer/core/css/css_property_equality.cc
Original file line number Diff line number Diff line change
Expand Up @@ -932,6 +932,7 @@ bool CSSPropertyEquality::PropertiesEqual(const PropertyHandle& property,
case CSSPropertyID::kAliasWebkitAlternativeAnimationDelay:
case CSSPropertyID::kAliasWebkitAlternativeAnimationWithDelayStartEnd:
case CSSPropertyID::kAliasWebkitAlternativeAnimationWithTimeline:
case CSSPropertyID::kAliasWebkitAlternativeMask:
case CSSPropertyID::kAliasWebkitAlternativeMaskClip:
case CSSPropertyID::kAliasWebkitAlternativeMaskComposite:
case CSSPropertyID::kAliasWebkitAlternativeMaskImage:
Expand Down Expand Up @@ -1238,7 +1239,7 @@ bool CSSPropertyEquality::PropertiesEqual(const PropertyHandle& property,
case CSSPropertyID::kTransition:
case CSSPropertyID::kViewTimeline:
case CSSPropertyID::kAlternativeViewTimelineWithInset:
case CSSPropertyID::kWebkitAlternativeMask:
case CSSPropertyID::kAlternativeMask:
case CSSPropertyID::kWebkitColumnBreakAfter:
case CSSPropertyID::kWebkitColumnBreakBefore:
case CSSPropertyID::kWebkitColumnBreakInside:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ TEST(CSSPropertyNamesTest, WebkitAlternativeMaskSize) {
}
}

TEST(CSSPropertyNamesTest, WebkitAlternativeMask) {
TEST(CSSPropertyNamesTest, AlternativeMask) {
{
ScopedCSSMaskingInteropForTest scoped_feature(false);
CSSPropertyID property_id = UnresolvedCSSPropertyID(
Expand All @@ -111,7 +111,7 @@ TEST(CSSPropertyNamesTest, WebkitAlternativeMask) {
ScopedCSSMaskingInteropForTest scoped_feature(true);
CSSPropertyID property_id = UnresolvedCSSPropertyID(
/* execution_context */ nullptr, "-webkit-mask");
EXPECT_EQ(CSSPropertyID::kWebkitAlternativeMask, property_id);
EXPECT_EQ(CSSPropertyID::kAliasWebkitAlternativeMask, property_id);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1144,7 +1144,7 @@ void TestRepeatStyleViaShorthandsParsing(const String& testValue,
TestRepeatStyleViaShorthandParsing(testValue, expectedCssText,
CSSPropertyID::kBackground);
TestRepeatStyleViaShorthandParsing(testValue, expectedCssText,
CSSPropertyID::kWebkitAlternativeMask);
CSSPropertyID::kAlternativeMask);
}

TEST(CSSPropertyParserTest, RepeatStyleRepeatXViaShorthand) {
Expand Down
101 changes: 101 additions & 0 deletions third_party/blink/renderer/core/css/properties/computed_style_utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,107 @@ const CSSValueList* ComputedStyleUtils::ValuesForBackgroundShorthand(
return result;
}

namespace {

// Append clip and origin vals (https://drafts.fxtf.org/css-masking/#the-mask):
// * If one <geometry-box> value and the no-clip keyword are present then
// <geometry-box> sets mask-origin and no-clip sets mask-clip to that value.
// * If one <geometry-box> value and no no-clip keyword are present then
// <geometry-box> sets both mask-origin and mask-clip to that value.
// * If two <geometry-box> values are present, then the first sets mask-origin
// and the second mask-clip.
// Additionally, simplifies when possible.
void AppendValuesForMaskClipAndOrigin(CSSValueList* result_list,
EFillBox origin,
EFillBox clip) {
if (origin == clip) {
// If both values are border-box, omit everything as it is the default.
if (origin == EFillBox::kBorder) {
return;
}
// If the values are the same, only emit one value. Note that mask-origin
// does not support no-clip, so there is no need to consider no-clip
// special cases.
result_list->Append(*CSSIdentifierValue::Create(origin));
} else if (origin == EFillBox::kBorder && clip == EFillBox::kNoClip) {
// Mask-origin does not support no-clip, so mask-origin can be omitted if it
// is the default.
result_list->Append(*CSSIdentifierValue::Create(clip));
} else {
result_list->Append(*CSSIdentifierValue::Create(origin));
result_list->Append(*CSSIdentifierValue::Create(clip));
}
}

} // namespace

const CSSValueList* ComputedStyleUtils::ValuesForMaskShorthand(
const StylePropertyShorthand&,
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style) {
CHECK(RuntimeEnabledFeatures::CSSMaskingInteropEnabled());
// Canonical order (https://drafts.fxtf.org/css-masking/#typedef-mask-layer):
// <mask-reference> ||
// <position> [ / <bg-size> ]? ||
// <repeat-style> ||
// <geometry-box> ||
// [ <geometry-box> | no-clip ] ||
// <compositing-operator> ||
// <masking-mode>
// The logic below omits initial values due to the following spec:
// https://drafts.csswg.org/cssom/#serialize-a-css-value
// "If component values can be omitted or replaced with a shorter
// representation without changing the meaning of the value, omit/replace
// them".
CSSValueList* result = CSSValueList::CreateCommaSeparated();
const FillLayer* layer = &style.MaskLayers();
for (; layer; layer = layer->Next()) {
CSSValueList* list = CSSValueList::CreateSpaceSeparated();
// <mask-reference>
if (layer->GetImage()) {
list->Append(
*layer->GetImage()->ComputedCSSValue(style, allow_visited_style));
}
// <position> [ / <bg-size> ]?
if (layer->PositionX() !=
FillLayer::InitialFillPositionX(EFillLayerType::kMask) ||
layer->PositionY() !=
FillLayer::InitialFillPositionY(EFillLayerType::kMask) ||
layer->Size() != FillLayer::InitialFillSize(EFillLayerType::kMask)) {
CSSValueList* position_size_list = CSSValueList::CreateSlashSeparated();
position_size_list->Append(*CreatePositionListForLayer(
GetCSSPropertyWebkitMaskPosition(), *layer, style));
if (layer->Size() != FillLayer::InitialFillSize(EFillLayerType::kMask)) {
position_size_list->Append(*ValueForFillSize(layer->Size(), style));
}
list->Append(*position_size_list);
}
// <repeat-style>
if (layer->Repeat() !=
FillLayer::InitialFillRepeat(EFillLayerType::kMask)) {
list->Append(*ValueForFillRepeat(layer));
}
// <geometry-box>
// [ <geometry-box> | no-clip ]
AppendValuesForMaskClipAndOrigin(list, layer->Origin(), layer->Clip());
// <compositing-operator>
if (layer->CompositingOperator() !=
FillLayer::InitialFillCompositingOperator(EFillLayerType::kMask)) {
list->Append(*CSSIdentifierValue::Create(layer->CompositingOperator()));
}
// <masking-mode>
// TODO(crbug.com/1490704): Emit mask-mode here.

if (list->length()) {
result->Append(*list);
} else {
result->Append(*CSSIdentifierValue::Create(CSSValueID::kNone));
}
}
return result;
}

const CSSValue* ComputedStyleUtils::BackgroundPositionOrWebkitMaskPosition(
const CSSProperty& resolved_property,
const ComputedStyle& style,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ class CORE_EXPORT ComputedStyleUtils {
const ComputedStyle&,
const LayoutObject*,
bool allow_visited_style);
static const CSSValueList* ValuesForMaskShorthand(
const StylePropertyShorthand&,
const ComputedStyle&,
const LayoutObject*,
bool allow_visited_style);
static const CSSValue* BackgroundPositionOrWebkitMaskPosition(
const CSSProperty&,
const ComputedStyle&,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4315,14 +4315,16 @@ CSSValue* ConsumeBackgroundComponent(CSSPropertyID resolved_property,
case CSSPropertyID::kMaskRepeat:
case CSSPropertyID::kWebkitMaskRepeat:
return ConsumeRepeatStyleValue(range);
case CSSPropertyID::kMaskComposite:
return ConsumeMaskComposite(range);
default:
return nullptr;
};
}

const StylePropertyShorthand& WebkitMaskShorthand(CSSPropertyID shorthand_id) {
if (shorthand_id == CSSPropertyID::kWebkitAlternativeMask) {
return webkitAlternativeMaskShorthand();
if (shorthand_id == CSSPropertyID::kAlternativeMask) {
return alternativeMaskShorthand();
}
return webkitMaskShorthand();
}
Expand All @@ -4345,7 +4347,7 @@ bool ParseBackgroundOrMask(bool important,
CSSPropertyID shorthand_id = local_context.CurrentShorthand();
DCHECK(shorthand_id == CSSPropertyID::kBackground ||
shorthand_id == CSSPropertyID::kWebkitMask ||
shorthand_id == CSSPropertyID::kWebkitAlternativeMask);
shorthand_id == CSSPropertyID::kAlternativeMask);
const StylePropertyShorthand& shorthand =
shorthand_id == CSSPropertyID::kBackground
? backgroundShorthand()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3784,7 +3784,7 @@ bool WebkitMask::ParseShorthand(
local_context, properties);
}

bool WebkitAlternativeMask::ParseShorthand(
bool AlternativeMask::ParseShorthand(
bool important,
CSSParserTokenRange& range,
const CSSParserContext& context,
Expand All @@ -3795,6 +3795,14 @@ bool WebkitAlternativeMask::ParseShorthand(
local_context, properties);
}

const CSSValue* AlternativeMask::CSSValueFromComputedStyleInternal(
const ComputedStyle& style,
const LayoutObject* layout_object,
bool allow_visited_style) const {
return ComputedStyleUtils::ValuesForMaskShorthand(
alternativeMaskShorthand(), style, layout_object, allow_visited_style);
}

bool MaskPosition::ParseShorthand(
bool important,
CSSParserTokenRange& range,
Expand Down
16 changes: 16 additions & 0 deletions third_party/blink/renderer/core/css/resolver/style_adjuster.cc
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/core/style/computed_style_constants.h"
#include "third_party/blink/renderer/core/style/style_intrinsic_length.h"
#include "third_party/blink/renderer/core/style/style_svg_mask_reference_image.h"
#include "third_party/blink/renderer/core/svg/svg_svg_element.h"
#include "third_party/blink/renderer/core/svg_names.h"
#include "third_party/blink/renderer/platform/geometry/length.h"
Expand Down Expand Up @@ -125,6 +126,16 @@ bool HostIsInputFile(const Element* element) {
return false;
}

StyleSVGResource* GetFirstMaskImageAsSVGResource(const SVGElement& element,
FillLayer& first_layer) {
auto* svg_mask_reference =
DynamicTo<StyleSVGMaskReferenceImage>(first_layer.GetImage());
if (!svg_mask_reference) {
return nullptr;
}
return svg_mask_reference->CreateSVGResourceWrapper();
}

void AdjustStyleForSvgElement(const SVGElement& element,
ComputedStyleBuilder& builder) {
// Disable some of text decoration properties.
Expand All @@ -138,6 +149,11 @@ void AdjustStyleForSvgElement(const SVGElement& element,
builder.SetTextEmphasisMark(TextEmphasisMark::kNone);
builder.SetTextUnderlineOffset(Length()); // crbug.com/1247912
builder.SetTextUnderlinePosition(TextUnderlinePosition::kAuto);

if (RuntimeEnabledFeatures::CSSMaskingInteropEnabled()) {
builder.SetMaskerResource(
GetFirstMaskImageAsSVGResource(element, builder.AccessMaskLayers()));
}
}

bool ElementForcesStackingContext(Element* element) {
Expand Down

0 comments on commit c3d96dd

Please sign in to comment.