Skip to content

Commit

Permalink
Bug 1518099 - Add support for lighter operator in feComposite r=jrmui…
Browse files Browse the repository at this point in the history
…zel,emilio

Spec: https://www.w3.org/TR/filter-effects-1/#attr-valuedef-operator-lighter

Lighter is defined in the compositing & blending spec as equivalent to porter-duff plus, https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_plus.

The 'lighter' composite mode already works in <canvas> (via globalCompositeOperation), and it's the same there.

Chrome implemented support in https://bugs.chromium.org/p/chromium/issues/detail?id=439037

Per w3c/svgwg#424 we should expose the new value in webidl and Chrome uses 7 too (https://codereview.chromium.org/779963002/patch/120001/130009)

Differential Revision: https://phabricator.services.mozilla.com/D100605
longsonr committed Jan 5, 2021
1 parent 2b537ae commit f518393
Showing 13 changed files with 76 additions and 15 deletions.
1 change: 1 addition & 0 deletions dom/svg/SVGFECompositeElement.cpp
Original file line number Diff line number Diff line change
@@ -32,6 +32,7 @@ SVGEnumMapping SVGFECompositeElement::sOperatorMap[] = {
{nsGkAtoms::atop, SVG_FECOMPOSITE_OPERATOR_ATOP},
{nsGkAtoms::xor_, SVG_FECOMPOSITE_OPERATOR_XOR},
{nsGkAtoms::arithmetic, SVG_FECOMPOSITE_OPERATOR_ARITHMETIC},
{nsGkAtoms::lighter, SVG_FECOMPOSITE_OPERATOR_LIGHTER},
{nullptr, 0}};

SVGElement::EnumInfo SVGFECompositeElement::sEnumInfo[1] = {
1 change: 1 addition & 0 deletions dom/webidl/SVGFECompositeElement.webidl
Original file line number Diff line number Diff line change
@@ -21,6 +21,7 @@ interface SVGFECompositeElement : SVGElement {
const unsigned short SVG_FECOMPOSITE_OPERATOR_ATOP = 4;
const unsigned short SVG_FECOMPOSITE_OPERATOR_XOR = 5;
const unsigned short SVG_FECOMPOSITE_OPERATOR_ARITHMETIC = 6;
const unsigned short SVG_FECOMPOSITE_OPERATOR_LIGHTER = 7;

[Constant]
readonly attribute SVGAnimatedString in1;
2 changes: 2 additions & 0 deletions gfx/2d/FilterNodeD2D1.cpp
Original file line number Diff line number Diff line change
@@ -120,6 +120,8 @@ D2D1_COMPOSITE_MODE D2DFilterCompositionMode(uint32_t aMode) {
return D2D1_COMPOSITE_MODE_SOURCE_ATOP;
case COMPOSITE_OPERATOR_XOR:
return D2D1_COMPOSITE_MODE_XOR;
case COMPOSITE_OPERATOR_LIGHTER:
return D2D1_COMPOSITE_MODE_PLUS;
}

MOZ_CRASH("GFX: Unknown enum value D2DFilterCompositionMode!");
1 change: 1 addition & 0 deletions gfx/2d/FilterNodeSoftware.cpp
Original file line number Diff line number Diff line change
@@ -2937,6 +2937,7 @@ already_AddRefed<DataSourceSurface> FilterNodeCompositeSoftware::Render(
case COMPOSITE_OPERATOR_OVER:
case COMPOSITE_OPERATOR_ATOP:
case COMPOSITE_OPERATOR_XOR:
case COMPOSITE_OPERATOR_LIGHTER:
// dest is unchanged.
break;
case COMPOSITE_OPERATOR_OUT:
20 changes: 20 additions & 0 deletions gfx/2d/FilterProcessingSIMD-inl.h
Original file line number Diff line number Diff line change
@@ -779,6 +779,22 @@ static inline u16x8_t CompositeTwoPixels(u16x8_t source, u16x8_t sourceAlpha,
simd::FastDivideBy255(result2));
}

case COMPOSITE_OPERATOR_LIGHTER: {
// val = dest * sourceAlpha + source * destAlpha;
u16x8_t destSourceInterleaved1 = simd::InterleaveLo16(dest, source);
u16x8_t rightFactor1 = simd::InterleaveLo16(sourceAlpha, destAlpha);
i32x4_t result1 =
simd::MulAdd16x8x2To32x4(destSourceInterleaved1, rightFactor1);

u16x8_t destSourceInterleaved2 = simd::InterleaveHi16(dest, source);
u16x8_t rightFactor2 = simd::InterleaveHi16(sourceAlpha, destAlpha);
i32x4_t result2 =
simd::MulAdd16x8x2To32x4(destSourceInterleaved2, rightFactor2);

return simd::PackAndSaturate32ToU16(simd::FastDivideBy255(result1),
simd::FastDivideBy255(result2));
}

default:
return simd::FromU16<u16x8_t>(0);
}
@@ -850,6 +866,10 @@ static void ApplyComposition_SIMD(DataSourceSurface* aSource,
ApplyComposition<i32x4_t, i16x8_t, u8x16_t, COMPOSITE_OPERATOR_XOR>(
aSource, aDest);
break;
case COMPOSITE_OPERATOR_LIGHTER:
ApplyComposition<i32x4_t, i16x8_t, u8x16_t, COMPOSITE_OPERATOR_LIGHTER>(
aSource, aDest);
break;
default:
MOZ_CRASH("GFX: Incomplete switch");
}
3 changes: 2 additions & 1 deletion gfx/2d/Filters.h
Original file line number Diff line number Diff line change
@@ -233,7 +233,8 @@ enum CompositeOperator {
COMPOSITE_OPERATOR_IN,
COMPOSITE_OPERATOR_OUT,
COMPOSITE_OPERATOR_ATOP,
COMPOSITE_OPERATOR_XOR
COMPOSITE_OPERATOR_XOR,
COMPOSITE_OPERATOR_LIGHTER
};

enum CompositeInputs {
16 changes: 9 additions & 7 deletions gfx/src/FilterSupport.cpp
Original file line number Diff line number Diff line change
@@ -948,13 +948,15 @@ static already_AddRefed<FilterNode> FilterNodeFromPrimitiveDescription(
if (!filter) {
return nullptr;
}
static const uint8_t operators[SVG_FECOMPOSITE_OPERATOR_ARITHMETIC] = {
COMPOSITE_OPERATOR_OVER, // SVG_FECOMPOSITE_OPERATOR_UNKNOWN
COMPOSITE_OPERATOR_OVER, // SVG_FECOMPOSITE_OPERATOR_OVER
COMPOSITE_OPERATOR_IN, // SVG_FECOMPOSITE_OPERATOR_IN
COMPOSITE_OPERATOR_OUT, // SVG_FECOMPOSITE_OPERATOR_OUT
COMPOSITE_OPERATOR_ATOP, // SVG_FECOMPOSITE_OPERATOR_ATOP
COMPOSITE_OPERATOR_XOR // SVG_FECOMPOSITE_OPERATOR_XOR
static const uint8_t operators[SVG_FECOMPOSITE_OPERATOR_LIGHTER + 1] = {
COMPOSITE_OPERATOR_OVER, // SVG_FECOMPOSITE_OPERATOR_UNKNOWN
COMPOSITE_OPERATOR_OVER, // SVG_FECOMPOSITE_OPERATOR_OVER
COMPOSITE_OPERATOR_IN, // SVG_FECOMPOSITE_OPERATOR_IN
COMPOSITE_OPERATOR_OUT, // SVG_FECOMPOSITE_OPERATOR_OUT
COMPOSITE_OPERATOR_ATOP, // SVG_FECOMPOSITE_OPERATOR_ATOP
COMPOSITE_OPERATOR_XOR, // SVG_FECOMPOSITE_OPERATOR_XOR
COMPOSITE_OPERATOR_OVER, // Unused, arithmetic is handled above
COMPOSITE_OPERATOR_LIGHTER // SVG_FECOMPOSITE_OPERATOR_LIGHTER
};
filter->SetAttribute(ATT_COMPOSITE_OPERATOR, (uint32_t)operators[op]);
filter->SetInput(IN_COMPOSITE_IN_START, mSources[1]);
1 change: 1 addition & 0 deletions gfx/src/FilterSupport.h
Original file line number Diff line number Diff line change
@@ -100,6 +100,7 @@ const unsigned short SVG_FECOMPOSITE_OPERATOR_OUT = 3;
const unsigned short SVG_FECOMPOSITE_OPERATOR_ATOP = 4;
const unsigned short SVG_FECOMPOSITE_OPERATOR_XOR = 5;
const unsigned short SVG_FECOMPOSITE_OPERATOR_ARITHMETIC = 6;
const unsigned short SVG_FECOMPOSITE_OPERATOR_LIGHTER = 7;

struct FilterAttribute;

19 changes: 19 additions & 0 deletions layout/reftests/svg/filters/feComposite-operator-lighter-ref.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<!doctype html>
<style>* { margin: 0; padding: 0; }</style>
<canvas id="canvas" width="200" height="200"></canvas>
<script>
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var width = canvas.width;
var height = canvas.height;

ctx.globalCompositeOperation = 'lighter';
ctx.fillStyle = '#f00';
ctx.fillRect(0,0,width,height);

gradient = ctx.createLinearGradient(0, 0, 0, height);
gradient.addColorStop(0, "#0f0");
gradient.addColorStop(1, "#00f");
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, width, height);
</script>
11 changes: 11 additions & 0 deletions layout/reftests/svg/filters/feComposite-operator-lighter.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions layout/reftests/svg/filters/reftest.list
Original file line number Diff line number Diff line change
@@ -96,6 +96,7 @@ fails == filter-marked-line-01.svg pass.svg # bug 477704
== feComponentTransfer-03.svg pass.svg
== feComponentTransfer-04.svg pass.svg
== feComposite-arguments-01.svg pass.svg
fuzzy-if(winWidget&&webrender,0-1,0-39600) == feComposite-operator-lighter.svg feComposite-operator-lighter-ref.html
fuzzy(0-1,0-26732) == feComposite-paint-01.svg feComposite-paint-01-ref.svg
fuzzy(0-1,0-10000) == feConvolveMatrix-bias-01.svg feConvolveMatrix-bias-01-ref.svg
== feConvolveMatrix-order-01.svg feConvolveMatrix-order-01-ref.svg
Original file line number Diff line number Diff line change
@@ -34,13 +34,18 @@
assert_equals(feCompositeElement.operator.baseVal, SVGFECompositeElement.SVG_FECOMPOSITE_OPERATOR_XOR);
assert_equals(feCompositeElement.getAttribute('operator'), "xor");

// Switch to 'lighter'.
feCompositeElement.operator.baseVal = SVGFECompositeElement.SVG_FECOMPOSITE_OPERATOR_LIGHTER;
assert_equals(feCompositeElement.operator.baseVal, SVGFECompositeElement.SVG_FECOMPOSITE_OPERATOR_LIGHTER);
assert_equals(feCompositeElement.getAttribute('operator'), "lighter");

// Switch to 'arithmetic'.
feCompositeElement.operator.baseVal = SVGFECompositeElement.SVG_FECOMPOSITE_OPERATOR_ARITHMETIC;
assert_equals(feCompositeElement.operator.baseVal, SVGFECompositeElement.SVG_FECOMPOSITE_OPERATOR_ARITHMETIC);
assert_equals(feCompositeElement.getAttribute('operator'), "arithmetic");

// Try setting invalid values.
assert_throws_js(TypeError, function() { feCompositeElement.operator.baseVal = 7; });
assert_throws_js(TypeError, function() { feCompositeElement.operator.baseVal = 8; });
assert_equals(feCompositeElement.operator.baseVal, SVGFECompositeElement.SVG_FECOMPOSITE_OPERATOR_ARITHMETIC);
assert_equals(feCompositeElement.getAttribute('operator'), "arithmetic");

@@ -56,10 +61,5 @@
feCompositeElement.operator.baseVal = SVGFECompositeElement.SVG_FECOMPOSITE_OPERATOR_OVER;
assert_equals(feCompositeElement.operator.baseVal, SVGFECompositeElement.SVG_FECOMPOSITE_OPERATOR_OVER);
assert_equals(feCompositeElement.getAttribute('operator'), "over");

// Switch to 'lighter'.
assert_equals(SVGFECompositeElement.SVG_FECOMPOSITE_OPERATOR_LIGHTER, undefined);
feCompositeElement.setAttribute("operator", "lighter");
assert_equals(feCompositeElement.operator.baseVal, SVGFECompositeElement.SVG_FECOMPOSITE_OPERATOR_UNKNOWN);
});
</script>
</script>
1 change: 1 addition & 0 deletions xpcom/ds/StaticAtoms.py
Original file line number Diff line number Diff line change
@@ -1431,6 +1431,7 @@
Atom("lengthAdjust", "lengthAdjust"),
Atom("letter_spacing", "letter-spacing"),
Atom("lighten", "lighten"),
Atom("lighter", "lighter"),
Atom("lighting_color", "lighting-color"),
Atom("limitingConeAngle", "limitingConeAngle"),
Atom("linear", "linear"),

0 comments on commit f518393

Please sign in to comment.