Skip to content
Permalink
Browse files
[web-animations] implement correct accumulation support for the `filt…
…er` property

https://bugs.webkit.org/show_bug.cgi?id=248235

Reviewed by Tim Nguyen.

Implement the specific accumulation behavior for brightness(), contrast(), opacity()
and saturate() operations. We also ensure we have the correct clipping behavior for
various other operations since with accumulation support they could appear out of
bounds.

* LayoutTests/imported/w3c/web-platform-tests/web-animations/animation-model/animation-types/accumulation-per-property-001-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/web-animations/animation-model/keyframe-effects/effect-value-iteration-composite-operation-expected.txt:
* Source/WebCore/platform/graphics/filters/FilterOperation.cpp:
(WebCore::FilterOperation::blendAmounts const):
(WebCore::BasicColorMatrixFilterOperation::blend):
(WebCore::BasicComponentTransferFilterOperation::blend):
* Source/WebCore/platform/graphics/filters/FilterOperation.h:

Canonical link: https://commits.webkit.org/256952@main
  • Loading branch information
graouts committed Nov 22, 2022
1 parent 2a6e74a commit 7b53609d924d002d19d5ddb617596cb9aa5db39e
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 33 deletions.
@@ -197,7 +197,7 @@ PASS fill-rule (type: discrete) has testAccumulation function
PASS fill-rule: "nonzero" onto "evenodd"
PASS fill-rule: "evenodd" onto "nonzero"
PASS filter (type: filterList) has testAccumulation function
FAIL filter: same ordered filter functions assert_equals: The value should be blur(30px) brightness(0) at 0ms expected "blur(30px) brightness(0)" but got "blur(30px) brightness(0.4)"
PASS filter: same ordered filter functions
PASS filter: mismatched ordered filter functions
PASS flex-basis (type: lengthPercentageOrCalc) has testAccumulation function
PASS flex-basis: length
@@ -11,10 +11,10 @@ PASS iteration composition of <calc()> value animation that the values can'tbe r
FAIL iteration composition of opacity animation assert_equals: Animated opacity style at 50s of the third iteration expected "1" but got "0.9"
PASS iteration composition of box-shadow animation
PASS iteration composition of filter blur animation
FAIL iteration composition of filter brightness for different unit animation assert_equals: Animated filter brightness style at 0s of the third iteration expected "brightness(2.6)" but got "brightness(4.6)"
FAIL iteration composition of filter brightness animation assert_equals: Animated filter brightness style at 0s of the third iteration expected "brightness(0)" but got "brightness(2)"
PASS iteration composition of filter brightness for different unit animation
PASS iteration composition of filter brightness animation
PASS iteration composition of filter drop-shadow animation
FAIL iteration composition of same filter list animation assert_equals: Animated filter list at 0s of the third iteration expected "brightness(3) contrast(3)" but got "brightness(5) contrast(5)"
PASS iteration composition of same filter list animation
FAIL iteration composition of discrete filter list because of mismatch of the order assert_equals: Animated filter list at 0s of the third iteration expected "brightness(1) contrast(1)" but got "contrast(2) brightness(2)"
FAIL iteration composition of different length filter list animation assert_equals: Animated filter list at 50s of the first iteration expected "sepia(0.5) contrast(1.5)" but got "sepia(1) contrast(2)"
PASS iteration composition of transform(rotate) animation
@@ -92,29 +92,53 @@ void ReferenceFilterOperation::loadExternalDocumentIfNeeded(CachedResourceLoader
m_cachedSVGDocumentReference->load(cachedResourceLoader, options);
}

double FilterOperation::blendAmounts(double from, double to, const BlendingContext& context) const
{
auto blendedAmount = [&]() {
if (context.compositeOperation == CompositeOperation::Accumulate) {
// The "initial value for interpolation" is 1 for brightness, contrast, opacity and saturate.
// Accumulation works differently for such operations per https://drafts.fxtf.org/filter-effects/#accumulation.
switch (m_type) {
case BRIGHTNESS:
case CONTRAST:
case OPACITY:
case SATURATE:
return from + to - 1;
default:
break;
}
}
return WebCore::blend(from, to, context);
}();

// Make sure blended values remain within bounds as specified by
// https://drafts.fxtf.org/filter-effects/#supported-filter-functions
switch (m_type) {
case GRAYSCALE:
case INVERT:
case OPACITY:
case SEPIA:
return std::clamp(blendedAmount, 0.0, 1.0);
case BRIGHTNESS:
case CONTRAST:
case SATURATE:
return std::max(blendedAmount, 0.0);
default:
return blendedAmount;
}
}

RefPtr<FilterOperation> BasicColorMatrixFilterOperation::blend(const FilterOperation* from, const BlendingContext& context, bool blendToPassthrough)
{
if (from && !from->isSameType(*this))
return this;

if (blendToPassthrough)
return BasicColorMatrixFilterOperation::create(WebCore::blend(m_amount, passthroughAmount(), context), m_type);

const BasicColorMatrixFilterOperation* fromOperation = downcast<BasicColorMatrixFilterOperation>(from);
double fromAmount = fromOperation ? fromOperation->amount() : passthroughAmount();
double blendedAmount = WebCore::blend(fromAmount, m_amount, context);

switch (m_type) {
case GRAYSCALE:
case SEPIA:
blendedAmount = std::clamp(blendedAmount, 0.0, 1.0);
break;
case SATURATE:
blendedAmount = std::max(blendedAmount, 0.0);
break;
default:
break;
}
auto blendedAmount = blendAmounts(fromAmount, m_amount, context);
return BasicColorMatrixFilterOperation::create(blendedAmount, m_type);
}

@@ -183,20 +207,7 @@ RefPtr<FilterOperation> BasicComponentTransferFilterOperation::blend(const Filte

const BasicComponentTransferFilterOperation* fromOperation = downcast<BasicComponentTransferFilterOperation>(from);
double fromAmount = fromOperation ? fromOperation->amount() : passthroughAmount();
double blendedAmount = WebCore::blend(fromAmount, m_amount, context);

switch (m_type) {
case INVERT:
case OPACITY:
blendedAmount = std::clamp(blendedAmount, 0.0, 1.0);
break;
case BRIGHTNESS:
case CONTRAST:
blendedAmount = std::max(blendedAmount, 0.0);
break;
default:
break;
}
auto blendedAmount = blendAmounts(fromAmount, m_amount, context);
return BasicComponentTransferFilterOperation::create(blendedAmount, m_type);
}

@@ -114,6 +114,8 @@ class FilterOperation : public ThreadSafeRefCounted<FilterOperation> {
{
}

double blendAmounts(double from, double to, const BlendingContext&) const;

OperationType m_type;
};

0 comments on commit 7b53609

Please sign in to comment.