Bug 1897783 - Fix incorrect rounding in software rendering of feColorMatrix. r=longsonr

This doesn't fix a similar problem in ArithmeticCombineTwoPixels because the fixes there have performance implications, appear wrong, or are wrong for common inputs.

Since hue-rotate is defined in terms of a color matrix, some tests involving hue-rotate behave slightly differently.

Differential Revision: https://phabricator.services.mozilla.com/D211113
This commit is contained in:
Toby 2024-06-20 11:12:44 +00:00
parent 7ebc27abfc
commit 91a13d17d8
7 changed files with 71 additions and 15 deletions

View File

@ -623,7 +623,7 @@ static already_AddRefed<DataSourceSurface> ApplyColorMatrix_SIMD(
Float clampedFloatMatrixElement = std::min(
std::max(floatMatrixElement, -floatElementMax), floatElementMax);
int16_t scaledIntMatrixElement =
int16_t(clampedFloatMatrixElement * factor + 0.5);
int16_t(floorf(clampedFloatMatrixElement * factor + 0.5));
int8_t bg_or_ra = componentOffsets[rowIndex] / 2;
int8_t g_or_a = componentOffsets[rowIndex] % 2;
int8_t B_or_G_or_R_or_A = componentOffsets[colIndex];
@ -633,14 +633,19 @@ static already_AddRefed<DataSourceSurface> ApplyColorMatrix_SIMD(
}
int32_t rowBias[4];
Float biasMax = (INT32_MAX - 4 * 255 * INT16_MAX) / (factor * 255);
Float biasMax =
(INT32_MAX - 4 * 255 * INT16_MAX - (factor / 2)) / (factor * 255);
for (size_t colIndex = 0; colIndex < 4; colIndex++) {
size_t rowIndex = 4;
const Float& floatMatrixElement = floats[rowIndex * 4 + colIndex];
Float clampedFloatMatrixElement =
std::min(std::max(floatMatrixElement, -biasMax), biasMax);
// Add 0.5 before multiplying by factor so that the later bitshift dividing
// by factor is rounding to nearest
Float scaledFloatMatrixElement =
(clampedFloatMatrixElement * 255 + 0.5) * factor;
int32_t scaledIntMatrixElement =
int32_t(clampedFloatMatrixElement * factor * 255 + 0.5);
int32_t(floorf(scaledFloatMatrixElement + 0.5));
rowBias[componentOffsets[colIndex]] = scaledIntMatrixElement;
}

View File

@ -3,14 +3,14 @@
== clip-input.svg clip-input-ref.svg
== clip-original-SourceGraphic.svg clip-original-SourceGraphic-ref.svg
== clip-output.svg clip-output-ref.svg
fuzzy-if(!useDrawSnapshot&&!Android,1-1,10000-10000) == clip-output.svg clip-output-ref.svg
fuzzy(0-5,0-20300) fuzzy-if(Android&&device&&!swgl,5-5,21751-21751) == default-subregion.svg default-subregion-ref.svg
== different-FillPaint-filter-regions.svg different-FillPaint-filter-regions-ref.svg
== different-StrokePaint-filter-regions.svg different-StrokePaint-filter-regions-ref.svg
== dont-clip-previous-primitives.svg dont-clip-previous-primitives-ref.svg
== intersecting-filter-regions.svg intersecting-filter-regions-ref.svg
fuzzy-if(!useDrawSnapshot,9-9,5168-5536) fuzzy-if(!useDrawSnapshot&&swgl,7-7,13170-13184) fuzzy-if(Android&&device&&!swgl,8-8,12391-12391) == long-chain.svg simple-chain-ref.svg
fuzzy-if(!useDrawSnapshot,9-9,5168-5536) fuzzy-if(!useDrawSnapshot&&swgl,7-7,13170-13184) fuzzy-if(Android&&device&&!swgl,8-8,12391-12391) == multiple-primitives-per-filter.svg simple-chain-ref.svg
fuzzy-if(!useDrawSnapshot&&!Android,1-1,40000-40000) == different-FillPaint-filter-regions.svg different-FillPaint-filter-regions-ref.svg
fuzzy-if(!useDrawSnapshot&&!Android,1-1,40000-40000) == different-StrokePaint-filter-regions.svg different-StrokePaint-filter-regions-ref.svg
fuzzy-if(!useDrawSnapshot&&!Android,1-1,10000-10000) == dont-clip-previous-primitives.svg dont-clip-previous-primitives-ref.svg
fuzzy-if(!useDrawSnapshot&&!Android,1-1,10000-10000) == intersecting-filter-regions.svg intersecting-filter-regions-ref.svg
fuzzy(0-9,0-13180) == long-chain.svg simple-chain-ref.svg
fuzzy(0-9,0-13180) == multiple-primitives-per-filter.svg simple-chain-ref.svg
fuzzy-if(winWidget,0-1,0-173) fuzzy-if(!useDrawSnapshot||(winWidget&&isCoverageBuild),9-9,5128-5496) fuzzy-if(!useDrawSnapshot&&swgl,7-7,12820-12830) fuzzy-if(Android&&device&&!swgl,8-8,12355-12355) == second-filter-uses-SourceAlpha.svg second-filter-uses-SourceAlpha-ref.svg
fuzzy-if(!useDrawSnapshot,9-9,5168-5536) fuzzy-if(!useDrawSnapshot&&swgl,7-7,13170-13180) fuzzy-if(Android&&device&&!swgl,8-8,12391-12391) == second-filter-uses-SourceGraphic.svg simple-chain-ref.svg
fuzzy(0-9,0-13180) == second-filter-uses-SourceGraphic.svg simple-chain-ref.svg
== simple-chain.svg simple-chain-ref.svg

View File

@ -0,0 +1,2 @@
[svg-image-root-filter.html]
fuzzy: maxDifference=0-1;totalPixels=0-400

View File

@ -1,2 +0,0 @@
[svg-multiple-filter-functions.html]
expected: FAIL

View File

@ -1,2 +0,0 @@
[svg-mutation-single-to-multiple-002.html]
expected: FAIL

View File

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html>
<head>
<title>Filter Effects: Test feColorMatrix with negative matrix entries</title>
<link rel="author" title="Toby Cathcart Burn" href="mailto:tcathcartburn@gmail.com">
</head>
<body>
<p>You should see a cyan colored rectangle.</p>
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'>
<rect x='0' y='0' width='100' height='100' fill="#00ffff"></rect>
</svg>
</body>
</html>

View File

@ -0,0 +1,35 @@
<!DOCTYPE html>
<html>
<head>
<title>Filter Effects: Test feColorMatrix with negative matrix entries</title>
<link rel="author" title="Toby Cathcart Burn" href="mailto:tcathcartburn@gmail.com">
<link rel="help" href="http://www.w3.org/TR/filter-effects-1/#feColorMatrixElement">
<link rel="help" href="http://www.w3.org/TR/filter-effects-1/#element-attrdef-fecolormatrix-type">
<link rel="match" href="fecolormatrix-negative-ref.html">
<meta name="assert" content="If the test runs, you should see a cyan(#00ffff) colored rectangle.">
</head>
<body>
<p>You should see a cyan colored rectangle.</p>
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'>
<defs>
<filter id='invert' color-interpolation-filters='sRGB'>
<feColorMatrix in='SourceGraphic'
values='-1 0 0 0 1
0 -1 0 0 1
0 0 -1 0 1
0 0 0 1 0' result='ef0'>
</feColorMatrix>
<feComposite in='ef0' in2='ef0' operator='arithmetic' k2='255'>
</feComposite>
</filter>
</defs>
<rect x='0' y='0' width='100' height='100' fill="#ffaa00" filter="url(#invert)"></rect>
</svg>
</body>
</html>