Bug 1915924 - Fix table generation math for func discrete in SVGFEComponentTransfer r=gfx-reviewers,nical

Differential Revision: https://phabricator.services.mozilla.com/D222573
This commit is contained in:
Ashley Hale 2024-09-19 01:33:48 +00:00
parent 58a8b5ee94
commit 1df4efd9df
4 changed files with 52 additions and 13 deletions

View File

@ -0,0 +1,16 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<svg width="200" height="50" xmlns="http://www.w3.org/2000/svg">
<title>Testcase for feComponentTransfer with two discrete values applied to a gradient</title>
<!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=1915924 -->
<defs>
<linearGradient id="Gradient1">
<stop offset="0%" stop-color="red" stop-opacity="100%"/>
<stop offset="100%" stop-color="red" stop-opacity="0%"/>
</linearGradient>
</defs>
<rect x="0" y="0" width="50%" height="50%" fill="red"/>
<rect x="0" y="50%" width="100%" height="50%" fill="url(#Gradient1)"/>
</svg>

After

Width:  |  Height:  |  Size: 689 B

View File

@ -0,0 +1,23 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<svg width="200" height="50" xmlns="http://www.w3.org/2000/svg">
<title>Testcase for feComponentTransfer with two discrete values applied to a gradient</title>
<!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=1915924 -->
<defs>
<linearGradient id="Gradient1">
<stop offset="0%" stop-color="red" stop-opacity="100%"/>
<stop offset="100%" stop-color="red" stop-opacity="0%"/>
</linearGradient>
<filter id="f1" filterUnits="objectBoundingBox" primitiveUnits="objectBoundingBox"
x="0" y="0" width="100%" height="100%">
<feComponentTransfer x="0" y="0" width="100%" height="100%"
in="SourceGraphic" style="color-interpolation-filters:sRGB">
<feFuncA type="discrete" tableValues="0 1" />
</feComponentTransfer>
</filter>
</defs>
<rect x="0" y="0" width="100%" height="50%" fill="url(#Gradient1)" filter="url(#f1)"/>
<rect x="0" y="50%" width="100%" height="50%" fill="url(#Gradient1)"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -28,6 +28,7 @@ fuzzy(0-2,0-1000000) == feColorMatrix-2.svg feColorMatrix-2-ref.svg
== feComponentTransfer-1.svg feComponentTransfer-1-ref.svg
== feComponentTransfer-2.svg feComponentTransfer-2-ref.svg
fuzzy(0-1,0-375) == feComponentTransfer-discrete.svg feComponentTransfer-discrete-ref.svg
fuzzy(0-2,0-1000000) == feComposite-1.svg feComposite-1-ref.svg
fuzzy(0-2,0-1000000) == feComposite-2.svg feComposite-2-ref.svg

View File

@ -687,7 +687,6 @@ static WrFiltersStatus WrFilterOpSVGFEComponentTransfer(
// This builds a single interleaved RGBA table as it is well suited to GPU
// texture fetches without any dynamic component indexing in the shader which
// can confuse buggy shader compilers.
float invScale = 1.0f / (float)(stops - 1);
for (size_t c = 0; c < 4; c++) {
auto f = aAttributes.mTypes[c];
// Check if there's no data (we have crashtests for this).
@ -701,11 +700,13 @@ static WrFiltersStatus WrFilterOpSVGFEComponentTransfer(
}
switch (f) {
case SVG_FECOMPONENTTRANSFER_TYPE_DISCRETE: {
size_t length1 = (size_t)aAttributes.mValues[c].Length() - 1;
size_t length = (size_t)aAttributes.mValues[c].Length();
size_t length1 = length - 1;
float step = (float)length / (float)stops;
for (size_t i = 0; i < stops; i++) {
// find the corresponding color in the table
// this can not overflow due to the length check
float kf = (float)i * invScale * (float)length1;
float kf = (float)i * step;
float floorkf = floor(kf);
size_t k = (size_t)floorkf;
k = std::min(k, length1);
@ -716,34 +717,31 @@ static WrFiltersStatus WrFilterOpSVGFEComponentTransfer(
break;
}
case SVG_FECOMPONENTTRANSFER_TYPE_GAMMA: {
float slope = invScale;
float intercept = 0.0f;
float step = 1.0f / (float)(stops - 1);
float amplitude = aAttributes.mValues[c][0];
float exponent = aAttributes.mValues[c][1];
float offset = aAttributes.mValues[c][2];
for (size_t i = 0; i < stops; i++) {
float v =
amplitude * pow((float)i * slope + intercept, exponent) + offset;
float v = amplitude * pow((float)i * step, exponent) + offset;
v = mozilla::clamped(v, 0.0f, 1.0f);
values[i * 4 + c] = v;
}
break;
}
case SVG_FECOMPONENTTRANSFER_TYPE_IDENTITY: {
float slope = invScale;
float intercept = 0.0f;
float step = 1.0f / (float)(stops - 1);
for (size_t i = 0; i < stops; i++) {
float v = (float)i * slope + intercept;
float v = (float)i * step;
v = mozilla::clamped(v, 0.0f, 1.0f);
values[i * 4 + c] = v;
}
break;
}
case SVG_FECOMPONENTTRANSFER_TYPE_LINEAR: {
float slope = aAttributes.mValues[c][0] * invScale;
float step = aAttributes.mValues[c][0] / (float)(stops - 1);
float intercept = aAttributes.mValues[c][1];
for (size_t i = 0; i < stops; i++) {
float v = (float)i * slope + intercept;
float v = (float)i * step + intercept;
v = mozilla::clamped(v, 0.0f, 1.0f);
values[i * 4 + c] = v;
}
@ -751,9 +749,10 @@ static WrFiltersStatus WrFilterOpSVGFEComponentTransfer(
}
case SVG_FECOMPONENTTRANSFER_TYPE_TABLE: {
size_t length1 = (size_t)aAttributes.mValues[c].Length() - 1;
float step = (float)length1 / (float)(stops - 1);
for (size_t i = 0; i < stops; i++) {
// Find the corresponding color in the table and interpolate
float kf = (float)i * invScale * (float)length1;
float kf = (float)i * step;
float floorkf = floor(kf);
size_t k = (size_t)floorkf;
float v1 = aAttributes.mValues[c][k];