Diff
Modified: trunk/LayoutTests/ChangeLog (225017 => 225018)
--- trunk/LayoutTests/ChangeLog 2017-11-18 17:25:28 UTC (rev 225017)
+++ trunk/LayoutTests/ChangeLog 2017-11-18 20:37:33 UTC (rev 225018)
@@ -1,3 +1,15 @@
+2017-11-18 Simon Fraser <[email protected]>
+
+ feTurbulence with stitchTiles is broken
+ https://bugs.webkit.org/show_bug.cgi?id=179862
+
+ Reviewed by Zalan Bujtas.
+
+ Ref test that masks out an empty area of the filter and compares with a green rectangle.
+
+ * svg/filters/feTurbulence-stitchTiles-expected.html: Added.
+ * svg/filters/feTurbulence-stitchTiles.html: Added.
+
2017-11-18 Antti Koivisto <[email protected]>
Add test for a multicolumn render tree update issue
Added: trunk/LayoutTests/svg/filters/feTurbulence-stitchTiles-expected.html (0 => 225018)
--- trunk/LayoutTests/svg/filters/feTurbulence-stitchTiles-expected.html (rev 0)
+++ trunk/LayoutTests/svg/filters/feTurbulence-stitchTiles-expected.html 2017-11-18 20:37:33 UTC (rev 225018)
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+ <body>
+ <p>You should see a solid green square below</p>
+ <svg width="800px" height="800px" xmlns="http://www.w3.org/2000/svg">
+ <defs>
+ <clipPath id="clip-out-middle">
+ <rect x="160" y="160" width="80" height="80" />
+ </clipPath>
+ </defs>
+ <rect x="160" y="160" width="80" height="80" fill="green" clip-path="url(#clip-out-middle)"/>
+ </svg>
+ </div>
+ </body>
+</html>
Added: trunk/LayoutTests/svg/filters/feTurbulence-stitchTiles.html (0 => 225018)
--- trunk/LayoutTests/svg/filters/feTurbulence-stitchTiles.html (rev 0)
+++ trunk/LayoutTests/svg/filters/feTurbulence-stitchTiles.html 2017-11-18 20:37:33 UTC (rev 225018)
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+ <body>
+ <p>You should see a solid green square below</p>
+ <svg width="800px" height="800px" xmlns="http://www.w3.org/2000/svg">
+ <defs>
+ <filter id="light" filterUnits="userSpaceOnUse" x="100" y="100" width="200" height="200">
+ <feTurbulence seed="1" type="turbulence" baseFrequency="0.01" numOctaves="1" stitchTiles="stitch" />
+ <feComponentTransfer>
+ <feFuncR type="discrete" tableValues="0 0.5 0.5 0.5 1" />
+ <feFuncG type="discrete" tableValues="0 0.5 0.5 0.5 1" />
+ <feFuncB type="discrete" tableValues="0 0.5 0.5 0.5 1" />
+ <feFuncA type="discrete" tableValues="0 1 1 1 1" />
+ </feComponentTransfer>
+ </filter>
+ <clipPath id="clip-out-middle">
+ <rect x="160" y="160" width="80" height="80" />
+ </clipPath>
+ </defs>
+ <rect x="160" y="160" width="80" height="80" fill="green" />
+ <rect x="0" y="0" width="400" height="400" filter="url(#light)" clip-path="url(#clip-out-middle)"/>
+ </svg>
+ </div>
+ </body>
+</html>
Modified: trunk/Source/WebCore/ChangeLog (225017 => 225018)
--- trunk/Source/WebCore/ChangeLog 2017-11-18 17:25:28 UTC (rev 225017)
+++ trunk/Source/WebCore/ChangeLog 2017-11-18 20:37:33 UTC (rev 225018)
@@ -1,3 +1,33 @@
+2017-11-18 Simon Fraser <[email protected]>
+
+ feTurbulence with stitchTiles is broken
+ https://bugs.webkit.org/show_bug.cgi?id=179862
+
+ Reviewed by Zalan Bujtas.
+
+ The "stitchTiles" logic was broken, and not equivalent to the spec sample code,
+ because it didn't compute and wrap the bx1 and by1 equivalents separately from
+ bx0 and by0.
+
+ Annotated the code with the equivalent sample code from the spec for ease of
+ comparison.
+
+ Also make some functions const.
+
+ Test: svg/filters/feTurbulence-stitchTiles.html
+
+ * platform/graphics/filters/FETurbulence.cpp:
+ (WebCore::FETurbulence::noise2D const):
+ (WebCore::FETurbulence::calculateTurbulenceValueForPoint const):
+ (WebCore::FETurbulence::fillRegion const):
+ (WebCore::checkNoise): Deleted.
+ (WebCore::FETurbulence::noise2D): Deleted.
+ (WebCore::FETurbulence::calculateTurbulenceValueForPoint): Deleted.
+ (WebCore::FETurbulence::fillRegion): Deleted.
+ * platform/graphics/filters/FETurbulence.h:
+ * platform/graphics/filters/FilterEffect.h:
+ (WebCore::FilterEffect::filter const):
+
2017-11-18 Antti Koivisto <[email protected]>
REGRESSION (r220646): REGRESSION (r220646): RenderTreePosition::computeNextSibling hits assertion with certain first-letter mutations
Modified: trunk/Source/WebCore/platform/graphics/filters/FETurbulence.cpp (225017 => 225018)
--- trunk/Source/WebCore/platform/graphics/filters/FETurbulence.cpp 2017-11-18 17:25:28 UTC (rev 225017)
+++ trunk/Source/WebCore/platform/graphics/filters/FETurbulence.cpp 2017-11-18 20:37:33 UTC (rev 225018)
@@ -179,63 +179,100 @@
}
}
-inline void checkNoise(int& noiseValue, int limitValue, int newValue)
+// This is taken 1:1 from SVG spec: http://www.w3.org/TR/SVG11/filters.html#feTurbulenceElement.
+FloatComponents FETurbulence::noise2D(const PaintingData& paintingData, const StitchData& stitchData, const FloatPoint& noiseVector) const
{
- if (noiseValue >= limitValue)
- noiseValue -= newValue;
- if (noiseValue >= limitValue - 1)
- noiseValue -= newValue - 1;
-}
+ struct NoisePosition {
+ int index; // bx0, by0 in the spec text.
+ int nextIndex; // bx1, by1 in the spec text.
+ float fraction; // rx0, ry0 in the spec text.
-FloatComponents FETurbulence::noise2D(const PaintingData& paintingData, StitchData& stitchData, const FloatPoint& noiseVector)
-{
- struct Noise {
- int noisePositionIntegerValue;
- float noisePositionFractionValue;
-
- Noise(float component)
+ NoisePosition(float component)
{
+ // t = vec[0] + PerlinN;
+ // bx0 = (int)t;
+ // bx1 = bx0+1;
+ // rx0 = t - (int)t;
float position = component + s_perlinNoise;
- noisePositionIntegerValue = static_cast<int>(position);
- noisePositionFractionValue = position - noisePositionIntegerValue;
+ index = static_cast<int>(position);
+ nextIndex = index + 1;
+ fraction = position - index;
}
+
+ void stitch(int size, int wrapSize)
+ {
+ // if (bx0 >= pStitchInfo->nWrapX)
+ // bx0 -= pStitchInfo->nWidth;
+ if (index >= wrapSize)
+ index -= size;
+
+ // if (bx1 >= pStitchInfo->nWrapX)
+ // bx1 -= pStitchInfo->nWidth;
+ if (nextIndex >= wrapSize)
+ nextIndex -= size;
+ }
};
- Noise noiseX(noiseVector.x());
- Noise noiseY(noiseVector.y());
+ NoisePosition noiseX(noiseVector.x());
+ NoisePosition noiseY(noiseVector.y());
// If stitching, adjust lattice points accordingly.
if (m_stitchTiles) {
- checkNoise(noiseX.noisePositionIntegerValue, stitchData.wrapX, stitchData.width);
- checkNoise(noiseY.noisePositionIntegerValue, stitchData.wrapY, stitchData.height);
+ noiseX.stitch(stitchData.width, stitchData.wrapX);
+ noiseY.stitch(stitchData.height, stitchData.wrapY);
}
- noiseX.noisePositionIntegerValue &= s_blockMask;
- noiseY.noisePositionIntegerValue &= s_blockMask;
- int latticeIndex = paintingData.latticeSelector[noiseX.noisePositionIntegerValue];
- int nextLatticeIndex = paintingData.latticeSelector[(noiseX.noisePositionIntegerValue + 1) & s_blockMask];
+ // bx0 &= BM;
+ // bx1 &= BM;
+ // by0 &= BM;
+ // by1 &= BM;
+ noiseX.index &= s_blockMask;
+ noiseX.nextIndex &= s_blockMask;
+ noiseY.index &= s_blockMask;
+ noiseY.nextIndex &= s_blockMask;
- float sx = smoothCurve(noiseX.noisePositionFractionValue);
- float sy = smoothCurve(noiseY.noisePositionFractionValue);
+ // i = uLatticeSelector[bx0];
+ // j = uLatticeSelector[bx1];
+ int latticeIndex = paintingData.latticeSelector[noiseX.index];
+ int nextLatticeIndex = paintingData.latticeSelector[noiseX.nextIndex];
+ // sx = double(s_curve(rx0));
+ // sy = double(s_curve(ry0));
+ float sx = smoothCurve(noiseX.fraction);
+ float sy = smoothCurve(noiseY.fraction);
+
auto noiseForChannel = [&](int channel) {
- // This is taken 1:1 from SVG spec: http://www.w3.org/TR/SVG11/filters.html#feTurbulenceElement.
- int temp = paintingData.latticeSelector[latticeIndex + noiseY.noisePositionIntegerValue];
- const float* q = paintingData.gradient[channel][temp];
+ // b00 = uLatticeSelector[i + by0]
+ int b00 = paintingData.latticeSelector[latticeIndex + noiseY.index];
+ // q = fGradient[nColorChannel][b00]; u = rx0 * q[0] + ry0 * q[1];
+ const float* q = paintingData.gradient[channel][b00];
+ float u = noiseX.fraction * q[0] + noiseY.fraction * q[1];
- float u = noiseX.noisePositionFractionValue * q[0] + noiseY.noisePositionFractionValue * q[1];
- temp = paintingData.latticeSelector[nextLatticeIndex + noiseY.noisePositionIntegerValue];
- q = paintingData.gradient[channel][temp];
- float v = (noiseX.noisePositionFractionValue - 1) * q[0] + noiseY.noisePositionFractionValue * q[1];
+ // b10 = uLatticeSelector[j + by0];
+ int b10 = paintingData.latticeSelector[nextLatticeIndex + noiseY.index];
+ // rx1 = rx0 - 1.0f;
+ // q = fGradient[nColorChannel][b10]; v = rx1 * q[0] + ry0 * q[1];
+ q = paintingData.gradient[channel][b10];
+ float v = (noiseX.fraction - 1) * q[0] + noiseY.fraction * q[1];
+ // a = lerp(sx, u, v);
float a = linearInterpolation(sx, u, v);
- temp = paintingData.latticeSelector[latticeIndex + noiseY.noisePositionIntegerValue + 1];
- q = paintingData.gradient[channel][temp];
- u = noiseX.noisePositionFractionValue * q[0] + (noiseY.noisePositionFractionValue - 1) * q[1];
- temp = paintingData.latticeSelector[nextLatticeIndex + noiseY.noisePositionIntegerValue + 1];
- q = paintingData.gradient[channel][temp];
- v = (noiseX.noisePositionFractionValue - 1) * q[0] + (noiseY.noisePositionFractionValue - 1) * q[1];
+
+ // b01 = uLatticeSelector[i + by1];
+ int b01 = paintingData.latticeSelector[latticeIndex + noiseY.nextIndex];
+ // ry1 = ry0 - 1.0f;
+ // q = fGradient[nColorChannel][b01]; u = rx0 * q[0] + ry1 * q[1];
+ q = paintingData.gradient[channel][b01];
+ u = noiseX.fraction * q[0] + (noiseY.fraction - 1) * q[1];
+
+ // b11 = uLatticeSelector[j + by1];
+ int b11 = paintingData.latticeSelector[nextLatticeIndex + noiseY.nextIndex];
+ // q = fGradient[nColorChannel][b11]; v = rx1 * q[0] + ry1 * q[1];
+ q = paintingData.gradient[channel][b11];
+ v = (noiseX.fraction - 1) * q[0] + (noiseY.fraction - 1) * q[1];
+ // b = lerp(sx, u, v);
float b = linearInterpolation(sx, u, v);
+ // return lerp(sy, a, b);
return linearInterpolation(sy, a, b);
};
@@ -247,11 +284,12 @@
};
}
-ColorComponents FETurbulence::calculateTurbulenceValueForPoint(const PaintingData& paintingData, StitchData& stitchData, const FloatPoint& point)
+ColorComponents FETurbulence::calculateTurbulenceValueForPoint(const PaintingData& paintingData, StitchData& stitchData, const FloatPoint& point) const
{
float tileWidth = paintingData.filterSize.width();
float tileHeight = paintingData.filterSize.height();
ASSERT(tileWidth > 0 && tileHeight > 0);
+
float baseFrequencyX = m_baseFrequencyX;
float baseFrequencyY = m_baseFrequencyY;
@@ -314,7 +352,7 @@
return turbulenceFunctionResult;
}
-void FETurbulence::fillRegion(Uint8ClampedArray* pixelArray, const PaintingData& paintingData, int startY, int endY)
+void FETurbulence::fillRegion(Uint8ClampedArray* pixelArray, const PaintingData& paintingData, int startY, int endY) const
{
IntRect filterRegion = absolutePaintRect();
FloatPoint point(0, filterRegion.y() + startY);
Modified: trunk/Source/WebCore/platform/graphics/filters/FETurbulence.h (225017 => 225018)
--- trunk/Source/WebCore/platform/graphics/filters/FETurbulence.h 2017-11-18 17:25:28 UTC (rev 225017)
+++ trunk/Source/WebCore/platform/graphics/filters/FETurbulence.h 2017-11-18 20:37:33 UTC (rev 225018)
@@ -119,9 +119,9 @@
FETurbulence(Filter&, TurbulenceType, float, float, int, float, bool);
void initPaint(PaintingData&);
- FloatComponents noise2D(const PaintingData&, StitchData&, const FloatPoint&);
- ColorComponents calculateTurbulenceValueForPoint(const PaintingData&, StitchData&, const FloatPoint&);
- void fillRegion(Uint8ClampedArray*, const PaintingData&, int, int);
+ FloatComponents noise2D(const PaintingData&, const StitchData&, const FloatPoint&) const;
+ ColorComponents calculateTurbulenceValueForPoint(const PaintingData&, StitchData&, const FloatPoint&) const;
+ void fillRegion(Uint8ClampedArray*, const PaintingData&, int startY, int endY) const;
TurbulenceType m_type;
float m_baseFrequencyX;
Modified: trunk/Source/WebCore/platform/graphics/filters/FilterEffect.h (225017 => 225018)
--- trunk/Source/WebCore/platform/graphics/filters/FilterEffect.h 2017-11-18 17:25:28 UTC (rev 225017)
+++ trunk/Source/WebCore/platform/graphics/filters/FilterEffect.h 2017-11-18 20:37:33 UTC (rev 225018)
@@ -144,6 +144,7 @@
void setEffectBoundaries(const FloatRect& effectBoundaries) { m_effectBoundaries = effectBoundaries; }
Filter& filter() { return m_filter; }
+ const Filter& filter() const { return m_filter; }
bool clipsToBounds() const { return m_clipsToBounds; }
void setClipsToBounds(bool value) { m_clipsToBounds = value; }