- Revision
- 262893
- Author
- commit-qu...@webkit.org
- Date
- 2020-06-10 20:27:40 -0700 (Wed, 10 Jun 2020)
Log Message
Multiple SVG Filters Unexpectedly lightens image using linearRGB
https://bugs.webkit.org/show_bug.cgi?id=212649
Patch by Frank Yang <guowei_y...@apple.com> on 2020-06-10
Reviewed by Myles C. Maxfield, Simon Fraser, Darin Adler
Source/WebCore:
Added color space conversion of input FilterEffect ImageBuffer and ImageData
for filters that directly manipulates pixel values. The conversion
is missing only on CG platforms because on CG platforms,
FilterEffect::transformResultColorSpace doesn't perform any operations
Its author assumed all filters are using CG ImageBuffers, and that
CG will handle the conversion which is not the case. The following filters
operates on the raw pixels inside an ImageBuffer, and this requires an explicit
color space conversion of the pixel values when the ImageData are retrieved
by calling FilterEffect::copy{Pre/Un}multipliedData().
The filters affected are feComponentTransfer, feComposite, feConvolveMatrix
feGaussianBlur, FELighting, feMorphology. The conversion is done
by CG, by drawing the input ImageBuffer to a new ImageBuffer that
has the correct color space tag. The ImageData is then pulled from
this new ImageBuffer and used in platformApplySoftware()
Tests: svg/filters/feComponentTransfer-clipped-expected.svg
svg/filters/feComponentTransfer-clipped.svg
svg/filters/feComposite-clipped-expected.svg
svg/filters/feComposite-clipped.svg
svg/filters/feConvolveMatrix-clipped-expected.svg
svg/filters/feConvolveMatrix-clipped.svg
svg/filters/feGaussianBlur-clipped-expected.svg
svg/filters/feGaussianBlur-clipped.svg
svg/filters/feLighting-clipped-expected.svg
svg/filters/feLighting-clipped.svg
svg/filters/feMorphology-clipped-expected.svg
svg/filters/feMorphology-clipped.svg
* platform/graphics/filters/FEComponentTransfer.cpp:
(WebCore::FEComponentTransfer::platformApplySoftware): Modified function call to
FilterEffect::premultipliedResult, color space conversion is required on CG
platforms, so operatingColorSpace is passed in and input will be converted to
that color space
* platform/graphics/filters/FEComposite.cpp:
(WebCore::FEComposite::platformApplySoftware): Similarly, color space conversion
Required on CG color space conversion is required on CG
platforms, so operatingColorSpace is passed in and input will be converted to
that color space
* platform/graphics/filters/FEConvolveMatrix.cpp:
(WebCore::FEConvolveMatrix::platformApplySoftware): converting to operating space
* platform/graphics/filters/FEGaussianBlur.cpp:
(WebCore::FEGaussianBlur::platformApplySoftware): converting to operating space
* platform/graphics/filters/FELighting.cpp:
(WebCore::FELighting::platformApplySoftware): converting to operating space
* platform/graphics/filters/FEMorphology.cpp:
(WebCore::FEMorphology::platformApplyDegenerate): converting to operating space
(WebCore::FEMorphology::platformApplySoftware): converting to operating space
* platform/graphics/filters/FilterEffect.cpp:
(WebCore::FilterEffect::unmultipliedResult): modified function signature so that
The Optional ColorSpace enum could be passed in to copyUnmultipliedResult()
(WebCore::FilterEffect::premultipliedResult): modified function signature so that
The Optional ColorSpace enum could be passed in to copyUnmultipliedResult()
(WebCore::FilterEffect::convertImageDataToColorSpace): helper function that takes an ImageData ptr
as input, put it into an ImageBuffer, and calls convertImageBufferToColorSpace to
perform color conversion, and returns the converted ImageData
(WebCore::FilterEffect::convertImageBufferToColorSpace): helper function that takes an ImageBuffer ptr
as input, create a new ImageBuffer with target color space, write input ImageBuffer to this new buffer
(CG backend handles the conversion) and returns the ImageData in the buffer.
(WebCore::FilterEffect::copyConvertedImageBufferToDestination): helper function that copies data from ImageBuffer
whose data is converted to the correct color space, to the destination array
(WebCore::FilterEffect::copyConvertedImageDataToDestination): helper function that copies data from ImageData
whose data is converted to the correct color space, to the destination array
(WebCore::FilterEffect::copyUnmultipliedResult): added an optional argument, colorSpace, which will be passed
into requiresAdditionalColorSpaceConversion, in order to determine if color space conversion is required
when obtaining the unmultiplied result. Then, added code to convert color space before writing to the
destination array
(WebCore::FilterEffect::copyPremultipliedResult): added an optional argument, colorSpace, which will be passed
into requiresAdditionalColorSpaceConversion, in order to determine if color space conversion is required
when obtaining the premultiplied result. Then, added code to convert color space before writing to the
destination array.
(WebCore::FilterEffect::requiresImageDataColorSpaceConversion): unction that only returns true
when 1) destination color space is non-null and is different than current color space AND
2) the code is running on CG platforms
This function will only be called inside copy{Un, Pre}multipliedResult, to address the issue
where color space is needed for filters that modifies raw pixels.
* platform/graphics/filters/FilterEffect.h: Added function declarations
LayoutTests:
Added new tests that checks SVG render results for
feComponentTransfer, feComposite, feConvolveMatrix
feGaussianBlur, feMorphology and lighting
* svg/filters/feComponentTransfer-clipped-expected.svg: Added.
* svg/filters/feComponentTransfer-clipped.svg: Added.
* svg/filters/feComposite-clipped-expected.svg: Added.
* svg/filters/feComposite-clipped.svg: Added.
* svg/filters/feConvolveMatrix-clipped-expected.svg: Added.
* svg/filters/feConvolveMatrix-clipped.svg: Added.
* svg/filters/feGaussianBlur-clipped-expected.svg: Added.
* svg/filters/feGaussianBlur-clipped.svg: Added.
* svg/filters/feLighting-clipped-expected.svg: Added.
* svg/filters/feLighting-clipped.svg: Added.
* svg/filters/feMorphology-clipped-expected.svg: Added.
* svg/filters/feMorphology-clipped.svg: Added.
Modified Paths
Added Paths
Diff
Modified: trunk/LayoutTests/ChangeLog (262892 => 262893)
--- trunk/LayoutTests/ChangeLog 2020-06-11 03:01:49 UTC (rev 262892)
+++ trunk/LayoutTests/ChangeLog 2020-06-11 03:27:40 UTC (rev 262893)
@@ -1,3 +1,27 @@
+2020-06-10 Frank Yang <guowei_y...@apple.com>
+
+ Multiple SVG Filters Unexpectedly lightens image using linearRGB
+ https://bugs.webkit.org/show_bug.cgi?id=212649
+
+ Reviewed by Myles C. Maxfield, Simon Fraser, Darin Adler
+
+ Added new tests that checks SVG render results for
+ feComponentTransfer, feComposite, feConvolveMatrix
+ feGaussianBlur, feMorphology and lighting
+
+ * svg/filters/feComponentTransfer-clipped-expected.svg: Added.
+ * svg/filters/feComponentTransfer-clipped.svg: Added.
+ * svg/filters/feComposite-clipped-expected.svg: Added.
+ * svg/filters/feComposite-clipped.svg: Added.
+ * svg/filters/feConvolveMatrix-clipped-expected.svg: Added.
+ * svg/filters/feConvolveMatrix-clipped.svg: Added.
+ * svg/filters/feGaussianBlur-clipped-expected.svg: Added.
+ * svg/filters/feGaussianBlur-clipped.svg: Added.
+ * svg/filters/feLighting-clipped-expected.svg: Added.
+ * svg/filters/feLighting-clipped.svg: Added.
+ * svg/filters/feMorphology-clipped-expected.svg: Added.
+ * svg/filters/feMorphology-clipped.svg: Added.
+
2020-06-10 Zalan Bujtas <za...@apple.com>
[Line clamp] Do not apply the special anchor handling when the anchor content is visible after clamping
Added: trunk/LayoutTests/svg/filters/feComponentTransfer-clipped-expected.svg (0 => 262893)
--- trunk/LayoutTests/svg/filters/feComponentTransfer-clipped-expected.svg (rev 0)
+++ trunk/LayoutTests/svg/filters/feComponentTransfer-clipped-expected.svg 2020-06-11 03:27:40 UTC (rev 262893)
@@ -0,0 +1,8 @@
+<svg width="480px" height="600px" xmlns="http://www.w3.org/2000/svg">
+<defs>
+ <filter id="filter" filterUnits="objectBoundingBox" x="0" y="0" width="100%" height="100%">
+ <feFlood x="0" y="0" width="300" height="300" flood-color="rgb(93, 200, 54)" result="flood1" />
+ </filter>
+</defs>
+<rect x="0" y="0" width="400" height="400" filter="url(#filter)"/>
+</svg>
Added: trunk/LayoutTests/svg/filters/feComponentTransfer-clipped.svg (0 => 262893)
--- trunk/LayoutTests/svg/filters/feComponentTransfer-clipped.svg (rev 0)
+++ trunk/LayoutTests/svg/filters/feComponentTransfer-clipped.svg 2020-06-11 03:27:40 UTC (rev 262893)
@@ -0,0 +1,11 @@
+<svg width="480px" height="600px" xmlns="http://www.w3.org/2000/svg">
+<defs>
+ <filter id="filter" filterUnits="objectBoundingBox" x="0" y="0" width="100%" height="100%">
+ <feFlood x="0" y="0" width="300" height="300" flood-color="rgb(93, 200, 54)" result="flood1" color-interpolation-filters="sRGB"/>
+ <feComponentTransfer>
+ <feFuncG type="identity" color-interpolation-filter="linearRGB"/>
+ </feComponentTransfer>
+ </filter>
+</defs>
+<rect x="0" y="0" width="400" height="400" filter="url(#filter)"/>
+</svg>
Added: trunk/LayoutTests/svg/filters/feComposite-clipped-expected.svg (0 => 262893)
--- trunk/LayoutTests/svg/filters/feComposite-clipped-expected.svg (rev 0)
+++ trunk/LayoutTests/svg/filters/feComposite-clipped-expected.svg 2020-06-11 03:27:40 UTC (rev 262893)
@@ -0,0 +1,8 @@
+<svg width="480px" height="600px" xmlns="http://www.w3.org/2000/svg">
+<defs>
+ <filter id="filter" filterUnits="objectBoundingBox" x="0" y="0" width="100%" height="100%">
+ <feFlood x="0" y="0" width="300" height="300" flood-color="rgb(120, 0, 54)" result="flood1" />
+ </filter>
+</defs>
+<rect x="0" y="0" width="400" height="400" filter="url(#filter)"/>
+</svg>
Added: trunk/LayoutTests/svg/filters/feComposite-clipped.svg (0 => 262893)
--- trunk/LayoutTests/svg/filters/feComposite-clipped.svg (rev 0)
+++ trunk/LayoutTests/svg/filters/feComposite-clipped.svg 2020-06-11 03:27:40 UTC (rev 262893)
@@ -0,0 +1,10 @@
+<svg width="480px" height="600px" xmlns="http://www.w3.org/2000/svg">
+<defs>
+ <filter id="filter" filterUnits="objectBoundingBox" x="0" y="0" width="100%" height="100%">
+ <feFlood x="0" y="0" width="300" height="300" flood-color="rgb(120, 0, 54)" result="input1" color-interpolation-filters="sRGB"/>
+ <feFlood x="0" y="0" width="300" height="300" flood-color="rgb(120, 0, 54)" result="input2" color-interpolation-filters="sRGB"/>
+ <feComposite id="comp" in="input1" in2="input2" operator="arithmetic" k1="0" k2=".5" k3="0.5" k4="0" color-interpolation-filters="linearRGB"/>
+ </filter>
+</defs>
+<rect x="0" y="0" width="400" height="400" filter="url(#filter)"/>
+</svg>
Added: trunk/LayoutTests/svg/filters/feConvolveMatrix-clipped-expected.svg (0 => 262893)
--- trunk/LayoutTests/svg/filters/feConvolveMatrix-clipped-expected.svg (rev 0)
+++ trunk/LayoutTests/svg/filters/feConvolveMatrix-clipped-expected.svg 2020-06-11 03:27:40 UTC (rev 262893)
@@ -0,0 +1,8 @@
+<svg width="480px" height="600px" xmlns="http://www.w3.org/2000/svg">
+<defs>
+ <filter id="filter" filterUnits="objectBoundingBox" x="0" y="0" width="100%" height="100%">
+ <feFlood x="0" y="0" width="300" height="300" flood-color="rgb(93, 10, 53)" result="flood1" />
+ </filter>
+</defs>
+<rect x="0" y="0" width="400" height="400" filter="url(#filter)"/>
+</svg>
Added: trunk/LayoutTests/svg/filters/feConvolveMatrix-clipped.svg (0 => 262893)
--- trunk/LayoutTests/svg/filters/feConvolveMatrix-clipped.svg (rev 0)
+++ trunk/LayoutTests/svg/filters/feConvolveMatrix-clipped.svg 2020-06-11 03:27:40 UTC (rev 262893)
@@ -0,0 +1,11 @@
+<svg width="480px" height="600px" xmlns="http://www.w3.org/2000/svg">
+<defs>
+ <filter id="filter" filterUnits="objectBoundingBox" x="0" y="0" width="100%" height="100%">
+ <feFlood x="0" y="0" width="300" height="300" flood-color="rgb(93, 10, 53)" result="flood1" color-interpolation-filters="sRGB"/>
+ <feConvolveMatrix order="3,3" divisor="1" kernelMatrix="0 0 0
+ 0 1 0
+ 0 0 0 " preserveAlpha="true"></feConvolveMatrix>
+ </filter>
+</defs>
+<rect x="0" y="0" width="400" height="400" filter="url(#filter)"/>
+</svg>
Added: trunk/LayoutTests/svg/filters/feGaussianBlur-clipped-expected.svg (0 => 262893)
--- trunk/LayoutTests/svg/filters/feGaussianBlur-clipped-expected.svg (rev 0)
+++ trunk/LayoutTests/svg/filters/feGaussianBlur-clipped-expected.svg 2020-06-11 03:27:40 UTC (rev 262893)
@@ -0,0 +1,8 @@
+<svg width="400px" height="400px" xmlns="http://www.w3.org/2000/svg">
+<defs>
+ <filter id="filter" filterUnits="objectBoundingBox" x="0" y="0" width="100%" height="100%">
+ <feFlood x="0" y="0" width="400" height="400" flood-color="rgb(93, 7, 54)" result="flood1" />
+ </filter>
+</defs>
+<rect x="20" y="20" width="400" height="400" filter="url(#filter)"/>
+</svg>
Added: trunk/LayoutTests/svg/filters/feGaussianBlur-clipped.svg (0 => 262893)
--- trunk/LayoutTests/svg/filters/feGaussianBlur-clipped.svg (rev 0)
+++ trunk/LayoutTests/svg/filters/feGaussianBlur-clipped.svg 2020-06-11 03:27:40 UTC (rev 262893)
@@ -0,0 +1,13 @@
+ <svg width="400px" height="400px" xmlns="http://www.w3.org/2000/svg">
+ <defs>
+ <filter id="filter" filterUnits="objectBoundingBox" x="0" y="0" width="100%" height="100%">
+ <feFlood x="0" y="0" width="500" height="500" flood-color="rgb(93, 7, 54)" result="flood1" color-interpolation-filters="sRGB"/>
+ <feGaussianBlur id="blur" stdDeviation="4" x="0" y="0" in="flood1" result="turbRes2" color-interpolation-filters="linearRGB" edgeMode="wrap"/>
+ </filter>
+
+ <clipPath id="clippath">
+ <polygon points="20,20 20,400 400,400 400,20 " />
+ </clipPath>
+ </defs>
+ <rect x="0" y="0" width="500" height="500" filter="url(#filter)" clip-path="url(#clippath)"/>
+</svg>
\ No newline at end of file
Added: trunk/LayoutTests/svg/filters/feLighting-clipped-expected.svg (0 => 262893)
--- trunk/LayoutTests/svg/filters/feLighting-clipped-expected.svg (rev 0)
+++ trunk/LayoutTests/svg/filters/feLighting-clipped-expected.svg 2020-06-11 03:27:40 UTC (rev 262893)
@@ -0,0 +1,8 @@
+<svg width="480px" height="600px" xmlns="http://www.w3.org/2000/svg">
+<defs>
+ <filter id="filter" filterUnits="objectBoundingBox" x="0" y="0" width="100%" height="100%">
+ <feFlood x="0" y="0" width="300" height="300" flood-color="rgb(127, 255, 127)" result="flood1" />
+ </filter>
+</defs>
+<rect x="0" y="0" width="400" height="400" filter="url(#filter)"/>
+</svg>
Added: trunk/LayoutTests/svg/filters/feLighting-clipped.svg (0 => 262893)
--- trunk/LayoutTests/svg/filters/feLighting-clipped.svg (rev 0)
+++ trunk/LayoutTests/svg/filters/feLighting-clipped.svg 2020-06-11 03:27:40 UTC (rev 262893)
@@ -0,0 +1,12 @@
+<svg width="480px" height="600px" xmlns="http://www.w3.org/2000/svg">
+<defs>
+ <filter id="filter" filterUnits="objectBoundingBox" x="0" y="0" width="100%" height="100%">
+ <feFlood x="0" y="0" width="300" height="300" flood-color="rgb(0, 128, 0)" result="flood1" color-interpolation-filters="sRGB"/>
+ <feSpecularLighting result="specOut" lighting-color="rgb(0, 128, 0)" color-interpolation-filters="sRGB">
+ <fePointLight x="150" y="150" z="2000000"/>
+ </feSpecularLighting>
+
+ </filter>
+</defs>
+<rect x="0" y="0" width="400" height="400" filter="url(#filter)"/>
+</svg>
Added: trunk/LayoutTests/svg/filters/feMorphology-clipped-expected.svg (0 => 262893)
--- trunk/LayoutTests/svg/filters/feMorphology-clipped-expected.svg (rev 0)
+++ trunk/LayoutTests/svg/filters/feMorphology-clipped-expected.svg 2020-06-11 03:27:40 UTC (rev 262893)
@@ -0,0 +1,8 @@
+<svg width="480px" height="600px" xmlns="http://www.w3.org/2000/svg">
+<defs>
+ <filter id="filter" filterUnits="objectBoundingBox" x="0" y="0" width="100%" height="100%">
+ <feFlood x="0" y="0" width="300" height="300" flood-color="rgb(93, 71, 54)" result="flood1" />
+ </filter>
+</defs>
+<rect x="0" y="0" width="400" height="400" filter="url(#filter)"/>
+</svg>
Added: trunk/LayoutTests/svg/filters/feMorphology-clipped.svg (0 => 262893)
--- trunk/LayoutTests/svg/filters/feMorphology-clipped.svg (rev 0)
+++ trunk/LayoutTests/svg/filters/feMorphology-clipped.svg 2020-06-11 03:27:40 UTC (rev 262893)
@@ -0,0 +1,9 @@
+<svg width="480px" height="600px" xmlns="http://www.w3.org/2000/svg">
+<defs>
+ <filter id="filter" filterUnits="objectBoundingBox" x="0" y="0" width="100%" height="100%">
+ <feFlood x="0" y="0" width="300" height="300" flood-color="rgb(93, 70, 54)" result="input" color-interpolation-filters="sRGB"/>
+ <feMorphology id="morph" in="input" operator="erode" radius="10" color-interpolation-filters="linearRGB"/>
+ </filter>
+</defs>
+<rect x="0" y="0" width="400" height="400" filter="url(#filter)"/>
+</svg>
Modified: trunk/Source/WebCore/ChangeLog (262892 => 262893)
--- trunk/Source/WebCore/ChangeLog 2020-06-11 03:01:49 UTC (rev 262892)
+++ trunk/Source/WebCore/ChangeLog 2020-06-11 03:27:40 UTC (rev 262893)
@@ -1,3 +1,88 @@
+2020-06-10 Frank Yang <guowei_y...@apple.com>
+
+ Multiple SVG Filters Unexpectedly lightens image using linearRGB
+ https://bugs.webkit.org/show_bug.cgi?id=212649
+
+ Reviewed by Myles C. Maxfield, Simon Fraser, Darin Adler
+
+ Added color space conversion of input FilterEffect ImageBuffer and ImageData
+ for filters that directly manipulates pixel values. The conversion
+ is missing only on CG platforms because on CG platforms,
+ FilterEffect::transformResultColorSpace doesn't perform any operations
+ Its author assumed all filters are using CG ImageBuffers, and that
+ CG will handle the conversion which is not the case. The following filters
+ operates on the raw pixels inside an ImageBuffer, and this requires an explicit
+ color space conversion of the pixel values when the ImageData are retrieved
+ by calling FilterEffect::copy{Pre/Un}multipliedData().
+
+ The filters affected are feComponentTransfer, feComposite, feConvolveMatrix
+ feGaussianBlur, FELighting, feMorphology. The conversion is done
+ by CG, by drawing the input ImageBuffer to a new ImageBuffer that
+ has the correct color space tag. The ImageData is then pulled from
+ this new ImageBuffer and used in platformApplySoftware()
+
+ Tests: svg/filters/feComponentTransfer-clipped-expected.svg
+ svg/filters/feComponentTransfer-clipped.svg
+ svg/filters/feComposite-clipped-expected.svg
+ svg/filters/feComposite-clipped.svg
+ svg/filters/feConvolveMatrix-clipped-expected.svg
+ svg/filters/feConvolveMatrix-clipped.svg
+ svg/filters/feGaussianBlur-clipped-expected.svg
+ svg/filters/feGaussianBlur-clipped.svg
+ svg/filters/feLighting-clipped-expected.svg
+ svg/filters/feLighting-clipped.svg
+ svg/filters/feMorphology-clipped-expected.svg
+ svg/filters/feMorphology-clipped.svg
+
+ * platform/graphics/filters/FEComponentTransfer.cpp:
+ (WebCore::FEComponentTransfer::platformApplySoftware): Modified function call to
+ FilterEffect::premultipliedResult, color space conversion is required on CG
+ platforms, so operatingColorSpace is passed in and input will be converted to
+ that color space
+ * platform/graphics/filters/FEComposite.cpp:
+ (WebCore::FEComposite::platformApplySoftware): Similarly, color space conversion
+ Required on CG color space conversion is required on CG
+ platforms, so operatingColorSpace is passed in and input will be converted to
+ that color space
+ * platform/graphics/filters/FEConvolveMatrix.cpp:
+ (WebCore::FEConvolveMatrix::platformApplySoftware): converting to operating space
+ * platform/graphics/filters/FEGaussianBlur.cpp:
+ (WebCore::FEGaussianBlur::platformApplySoftware): converting to operating space
+ * platform/graphics/filters/FELighting.cpp:
+ (WebCore::FELighting::platformApplySoftware): converting to operating space
+ * platform/graphics/filters/FEMorphology.cpp:
+ (WebCore::FEMorphology::platformApplyDegenerate): converting to operating space
+ (WebCore::FEMorphology::platformApplySoftware): converting to operating space
+ * platform/graphics/filters/FilterEffect.cpp:
+ (WebCore::FilterEffect::unmultipliedResult): modified function signature so that
+ The Optional ColorSpace enum could be passed in to copyUnmultipliedResult()
+ (WebCore::FilterEffect::premultipliedResult): modified function signature so that
+ The Optional ColorSpace enum could be passed in to copyUnmultipliedResult()
+ (WebCore::FilterEffect::convertImageDataToColorSpace): helper function that takes an ImageData ptr
+ as input, put it into an ImageBuffer, and calls convertImageBufferToColorSpace to
+ perform color conversion, and returns the converted ImageData
+ (WebCore::FilterEffect::convertImageBufferToColorSpace): helper function that takes an ImageBuffer ptr
+ as input, create a new ImageBuffer with target color space, write input ImageBuffer to this new buffer
+ (CG backend handles the conversion) and returns the ImageData in the buffer.
+ (WebCore::FilterEffect::copyConvertedImageBufferToDestination): helper function that copies data from ImageBuffer
+ whose data is converted to the correct color space, to the destination array
+ (WebCore::FilterEffect::copyConvertedImageDataToDestination): helper function that copies data from ImageData
+ whose data is converted to the correct color space, to the destination array
+ (WebCore::FilterEffect::copyUnmultipliedResult): added an optional argument, colorSpace, which will be passed
+ into requiresAdditionalColorSpaceConversion, in order to determine if color space conversion is required
+ when obtaining the unmultiplied result. Then, added code to convert color space before writing to the
+ destination array
+ (WebCore::FilterEffect::copyPremultipliedResult): added an optional argument, colorSpace, which will be passed
+ into requiresAdditionalColorSpaceConversion, in order to determine if color space conversion is required
+ when obtaining the premultiplied result. Then, added code to convert color space before writing to the
+ destination array.
+ (WebCore::FilterEffect::requiresImageDataColorSpaceConversion): unction that only returns true
+ when 1) destination color space is non-null and is different than current color space AND
+ 2) the code is running on CG platforms
+ This function will only be called inside copy{Un, Pre}multipliedResult, to address the issue
+ where color space is needed for filters that modifies raw pixels.
+ * platform/graphics/filters/FilterEffect.h: Added function declarations
+
2020-06-10 Zalan Bujtas <za...@apple.com>
[Line clamp] Do not apply the special anchor handling when the anchor content is visible after clamping
Modified: trunk/Source/WebCore/platform/graphics/filters/FEComponentTransfer.cpp (262892 => 262893)
--- trunk/Source/WebCore/platform/graphics/filters/FEComponentTransfer.cpp 2020-06-11 03:01:49 UTC (rev 262892)
+++ trunk/Source/WebCore/platform/graphics/filters/FEComponentTransfer.cpp 2020-06-11 03:27:40 UTC (rev 262893)
@@ -120,8 +120,7 @@
computeLookupTables(redTable, greenTable, blueTable, alphaTable);
IntRect drawingRect = requestedRegionOfInputImageData(in->absolutePaintRect());
- in->copyUnmultipliedResult(*pixelArray, drawingRect);
-
+ in->copyUnmultipliedResult(*pixelArray, drawingRect, operatingColorSpace());
unsigned pixelArrayLength = pixelArray->length();
uint8_t* data = ""
for (unsigned pixelOffset = 0; pixelOffset < pixelArrayLength; pixelOffset += 4) {
Modified: trunk/Source/WebCore/platform/graphics/filters/FEComposite.cpp (262892 => 262893)
--- trunk/Source/WebCore/platform/graphics/filters/FEComposite.cpp 2020-06-11 03:01:49 UTC (rev 262892)
+++ trunk/Source/WebCore/platform/graphics/filters/FEComposite.cpp 2020-06-11 03:27:40 UTC (rev 262893)
@@ -235,12 +235,12 @@
return;
IntRect effectADrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect());
- auto srcPixelArray = in->premultipliedResult(effectADrawingRect);
+ auto srcPixelArray = in->premultipliedResult(effectADrawingRect, operatingColorSpace());
if (!srcPixelArray)
return;
IntRect effectBDrawingRect = requestedRegionOfInputImageData(in2->absolutePaintRect());
- in2->copyPremultipliedResult(*dstPixelArray, effectBDrawingRect);
+ in2->copyPremultipliedResult(*dstPixelArray, effectBDrawingRect, operatingColorSpace());
platformArithmeticSoftware(*srcPixelArray, *dstPixelArray, m_k1, m_k2, m_k3, m_k4);
return;
Modified: trunk/Source/WebCore/platform/graphics/filters/FEConvolveMatrix.cpp (262892 => 262893)
--- trunk/Source/WebCore/platform/graphics/filters/FEConvolveMatrix.cpp 2020-06-11 03:01:49 UTC (rev 262892)
+++ trunk/Source/WebCore/platform/graphics/filters/FEConvolveMatrix.cpp 2020-06-11 03:27:40 UTC (rev 262893)
@@ -384,10 +384,9 @@
RefPtr<Uint8ClampedArray> srcPixelArray;
if (m_preserveAlpha)
- srcPixelArray = in->unmultipliedResult(effectDrawingRect);
+ srcPixelArray = in->unmultipliedResult(effectDrawingRect, operatingColorSpace());
else
- srcPixelArray = in->premultipliedResult(effectDrawingRect);
-
+ srcPixelArray = in->premultipliedResult(effectDrawingRect, operatingColorSpace());
if (!srcPixelArray)
return;
Modified: trunk/Source/WebCore/platform/graphics/filters/FEGaussianBlur.cpp (262892 => 262893)
--- trunk/Source/WebCore/platform/graphics/filters/FEGaussianBlur.cpp 2020-06-11 03:01:49 UTC (rev 262892)
+++ trunk/Source/WebCore/platform/graphics/filters/FEGaussianBlur.cpp 2020-06-11 03:27:40 UTC (rev 262893)
@@ -531,8 +531,7 @@
setIsAlphaImage(in->isAlphaImage());
IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect());
- in->copyPremultipliedResult(*dstPixelArray, effectDrawingRect);
-
+ in->copyPremultipliedResult(*dstPixelArray, effectDrawingRect, operatingColorSpace());
if (!m_stdX && !m_stdY)
return;
Modified: trunk/Source/WebCore/platform/graphics/filters/FELighting.cpp (262892 => 262893)
--- trunk/Source/WebCore/platform/graphics/filters/FELighting.cpp 2020-06-11 03:01:49 UTC (rev 262892)
+++ trunk/Source/WebCore/platform/graphics/filters/FELighting.cpp 2020-06-11 03:27:40 UTC (rev 262893)
@@ -482,8 +482,7 @@
setIsAlphaImage(false);
IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect());
- in->copyPremultipliedResult(*resutPixelArray, effectDrawingRect);
-
+ in->copyPremultipliedResult(*resutPixelArray, effectDrawingRect, operatingColorSpace());
// FIXME: support kernelUnitLengths other than (1,1). The issue here is that the W3
// standard has no test case for them, and other browsers (like Firefox) has strange
// output for various kernelUnitLengths, and I am not sure they are reliable.
Modified: trunk/Source/WebCore/platform/graphics/filters/FEMorphology.cpp (262892 => 262893)
--- trunk/Source/WebCore/platform/graphics/filters/FEMorphology.cpp 2020-06-11 03:01:49 UTC (rev 262892)
+++ trunk/Source/WebCore/platform/graphics/filters/FEMorphology.cpp 2020-06-11 03:27:40 UTC (rev 262893)
@@ -235,10 +235,9 @@
{
if (radiusX < 0 || radiusY < 0 || (!radiusX && !radiusY)) {
FilterEffect* in = inputEffect(0);
- in->copyPremultipliedResult(dstPixelArray, imageRect);
+ in->copyPremultipliedResult(dstPixelArray, imageRect, operatingColorSpace());
return true;
}
-
return false;
}
@@ -260,7 +259,7 @@
return;
Filter& filter = this->filter();
- auto srcPixelArray = in->premultipliedResult(effectDrawingRect);
+ auto srcPixelArray = in->premultipliedResult(effectDrawingRect, operatingColorSpace());
if (!srcPixelArray)
return;
Modified: trunk/Source/WebCore/platform/graphics/filters/FilterEffect.cpp (262892 => 262893)
--- trunk/Source/WebCore/platform/graphics/filters/FilterEffect.cpp 2020-06-11 03:01:49 UTC (rev 262892)
+++ trunk/Source/WebCore/platform/graphics/filters/FilterEffect.cpp 2020-06-11 03:27:40 UTC (rev 262893)
@@ -27,6 +27,7 @@
#include "Color.h"
#include "Filter.h"
#include "GeometryUtilities.h"
+#include "GraphicsContext.h"
#include "ImageBuffer.h"
#include "ImageData.h"
#include "Logging.h"
@@ -286,7 +287,7 @@
return m_imageBufferResult.get();
}
-RefPtr<Uint8ClampedArray> FilterEffect::unmultipliedResult(const IntRect& rect)
+RefPtr<Uint8ClampedArray> FilterEffect::unmultipliedResult(const IntRect& rect, Optional<ColorSpace> colorSpace)
{
IntSize scaledSize(rect.size());
ASSERT(!ImageBuffer::sizeNeedsClamping(scaledSize));
@@ -294,12 +295,11 @@
auto imageData = Uint8ClampedArray::tryCreateUninitialized((scaledSize.area() * 4).unsafeGet());
if (!imageData)
return nullptr;
-
- copyUnmultipliedResult(*imageData, rect);
+ copyUnmultipliedResult(*imageData, rect, colorSpace);
return imageData;
}
-RefPtr<Uint8ClampedArray> FilterEffect::premultipliedResult(const IntRect& rect)
+RefPtr<Uint8ClampedArray> FilterEffect::premultipliedResult(const IntRect& rect, Optional<ColorSpace> colorSpace)
{
IntSize scaledSize(rect.size());
ASSERT(!ImageBuffer::sizeNeedsClamping(scaledSize));
@@ -307,7 +307,7 @@
auto imageData = Uint8ClampedArray::tryCreateUninitialized((scaledSize.area() * 4).unsafeGet());
if (!imageData)
return nullptr;
- copyPremultipliedResult(*imageData, rect);
+ copyPremultipliedResult(*imageData, rect, colorSpace);
return imageData;
}
@@ -435,8 +435,51 @@
#endif
}
-void FilterEffect::copyUnmultipliedResult(Uint8ClampedArray& destination, const IntRect& rect)
+RefPtr<ImageData> FilterEffect::convertImageDataToColorSpace(ColorSpace targetColorSpace, ImageData& inputData, AlphaPremultiplication outputFormat)
{
+ IntRect destinationRect(IntPoint(), inputData.size());
+ FloatSize clampedSize = ImageBuffer::clampedSize(inputData.size());
+ // Create an ImageBuffer to store incoming ImageData
+ auto buffer = ImageBuffer::create(clampedSize, m_filter.renderingMode(), m_filter.filterScale(), operatingColorSpace());
+ if (!buffer)
+ return nullptr;
+ buffer->putImageData(outputFormat, inputData, destinationRect);
+ return convertImageBufferToColorSpace(targetColorSpace, *buffer, destinationRect, outputFormat);
+}
+
+RefPtr<ImageData> FilterEffect::convertImageBufferToColorSpace(ColorSpace targetColorSpace, ImageBuffer& inputBuffer, const IntRect& rect, AlphaPremultiplication outputFormat)
+{
+ FloatSize clampedSize = ImageBuffer::clampedSize(rect.size());
+ // Create an ImageBuffer with the correct color space and utilize CG to handle color space conversion
+ auto convertedBuffer = ImageBuffer::create(clampedSize, m_filter.renderingMode(), m_filter.filterScale(), targetColorSpace);
+ if (!convertedBuffer)
+ return nullptr;
+ // Color space conversion happens internally when drawing from one image buffer to another
+ convertedBuffer->context().drawImageBuffer(inputBuffer, rect);
+ return convertedBuffer->getImageData(outputFormat, rect);
+}
+
+void FilterEffect::copyConvertedImageBufferToDestination(Uint8ClampedArray& destination, ColorSpace colorSpace, AlphaPremultiplication outputFormat, const IntRect& destRect)
+{
+ // Converts the data stored in m_imageBufferResult, and save to destination
+ auto convertedImageData = convertImageBufferToColorSpace(colorSpace, *m_imageBufferResult, { IntPoint(), m_absolutePaintRect.size() }, outputFormat);
+ if (!convertedImageData)
+ return;
+ copyImageBytes(*convertedImageData->data(), destination, destRect);
+}
+
+void FilterEffect::copyConvertedImageDataToDestination(Uint8ClampedArray& destination, ImageData& imageData, ColorSpace colorSpace, AlphaPremultiplication outputFormat, const IntRect& destRect)
+{
+ // Converts the data stored in m_unmultipliedImageResult/m_premultipliedImageResult,
+ // whichever isn't null, and save to destination
+ auto convertedImageData = convertImageDataToColorSpace(colorSpace, imageData, outputFormat);
+ if (!convertedImageData)
+ return;
+ copyImageBytes(*convertedImageData->data(), destination, destRect);
+}
+
+void FilterEffect::copyUnmultipliedResult(Uint8ClampedArray& destination, const IntRect& rect, Optional<ColorSpace> colorSpace)
+{
ASSERT(hasResult());
LOG_WITH_STREAM(Filters, stream << "FilterEffect " << filterName() << " " << this << " copyUnmultipliedResult(). Existing image buffer " << m_imageBufferResult.get() << " m_premultipliedImageResult " << ValueOrNull(m_premultipliedImageResult.get()) << " m_unmultipliedImageResult " << ValueOrNull(m_unmultipliedImageResult.get()));
@@ -444,6 +487,10 @@
if (!m_unmultipliedImageResult) {
// We prefer a conversion from the image buffer.
if (m_imageBufferResult) {
+ if (requiresImageDataColorSpaceConversion(colorSpace)) {
+ copyConvertedImageBufferToDestination(destination, *colorSpace, AlphaPremultiplication::Unpremultiplied, rect);
+ return;
+ }
m_unmultipliedImageResult = m_imageBufferResult->getImageData(AlphaPremultiplication::Unpremultiplied, { IntPoint(), m_absolutePaintRect.size() });
if (!m_unmultipliedImageResult)
return;
@@ -454,14 +501,17 @@
m_unmultipliedImageResult = ImageData::create(inputSize);
if (!m_unmultipliedImageResult)
return;
-
copyUnpremultiplyingAlpha(*m_premultipliedImageResult->data(), *m_unmultipliedImageResult->data(), inputSize);
}
}
+ if (requiresImageDataColorSpaceConversion(colorSpace)) {
+ copyConvertedImageDataToDestination(destination, *m_unmultipliedImageResult, *colorSpace, AlphaPremultiplication::Unpremultiplied, rect);
+ return;
+ }
copyImageBytes(*m_unmultipliedImageResult->data(), destination, rect);
}
-void FilterEffect::copyPremultipliedResult(Uint8ClampedArray& destination, const IntRect& rect)
+void FilterEffect::copyPremultipliedResult(Uint8ClampedArray& destination, const IntRect& rect, Optional<ColorSpace> colorSpace)
{
ASSERT(hasResult());
@@ -470,6 +520,10 @@
if (!m_premultipliedImageResult) {
// We prefer a conversion from the image buffer.
if (m_imageBufferResult) {
+ if (requiresImageDataColorSpaceConversion(colorSpace)) {
+ copyConvertedImageBufferToDestination(destination, *colorSpace, AlphaPremultiplication::Premultiplied, rect);
+ return;
+ }
m_premultipliedImageResult = m_imageBufferResult->getImageData(AlphaPremultiplication::Premultiplied, { IntPoint(), m_absolutePaintRect.size() });
if (!m_premultipliedImageResult)
return;
@@ -480,10 +534,15 @@
m_premultipliedImageResult = ImageData::create(inputSize);
if (!m_premultipliedImageResult)
return;
-
copyPremultiplyingAlpha(*m_unmultipliedImageResult->data(), *m_premultipliedImageResult->data(), inputSize);
}
}
+
+ RefPtr<ImageData> convertedImageData;
+ if (requiresImageDataColorSpaceConversion(colorSpace)) {
+ copyConvertedImageDataToDestination(destination, *m_premultipliedImageResult, *colorSpace, AlphaPremultiplication::Premultiplied, rect);
+ return;
+ }
copyImageBytes(*m_premultipliedImageResult->data(), destination, rect);
}
@@ -533,6 +592,20 @@
return m_premultipliedImageResult.get();
}
+bool FilterEffect::requiresImageDataColorSpaceConversion(Optional<ColorSpace> dstColorSpace)
+{
+#if USE(CG)
+ // This function determines whether we need the step of an extra color space conversion
+ // We only need extra color conversion when 1) color space is different in the input
+ // AND 2) the filter is manipulating raw pixels
+ return dstColorSpace && resultColorSpace() != *dstColorSpace;
+#else
+ // Additional color space conversion is not needed on non-CG
+ UNUSED_PARAM(dstColorSpace);
+ return false;
+#endif
+}
+
void FilterEffect::transformResultColorSpace(ColorSpace dstColorSpace)
{
#if USE(CG)
Modified: trunk/Source/WebCore/platform/graphics/filters/FilterEffect.h (262892 => 262893)
--- trunk/Source/WebCore/platform/graphics/filters/FilterEffect.h 2020-06-11 03:01:49 UTC (rev 262892)
+++ trunk/Source/WebCore/platform/graphics/filters/FilterEffect.h 2020-06-11 03:27:40 UTC (rev 262893)
@@ -21,6 +21,7 @@
#pragma once
+#include "AlphaPremultiplication.h"
#include "ColorSpace.h"
#include "FloatRect.h"
#include "IntRect.h"
@@ -59,12 +60,10 @@
void clearResultsRecursive();
ImageBuffer* imageBufferResult();
- RefPtr<Uint8ClampedArray> unmultipliedResult(const IntRect&);
- RefPtr<Uint8ClampedArray> premultipliedResult(const IntRect&);
-
- void copyUnmultipliedResult(Uint8ClampedArray& destination, const IntRect&);
- void copyPremultipliedResult(Uint8ClampedArray& destination, const IntRect&);
-
+ RefPtr<Uint8ClampedArray> unmultipliedResult(const IntRect&, Optional<ColorSpace> = WTF::nullopt);
+ RefPtr<Uint8ClampedArray> premultipliedResult(const IntRect&, Optional<ColorSpace> = WTF::nullopt);
+ void copyUnmultipliedResult(Uint8ClampedArray& destination, const IntRect&, Optional<ColorSpace> = WTF::nullopt);
+ void copyPremultipliedResult(Uint8ClampedArray& destination, const IntRect&, Optional<ColorSpace> = WTF::nullopt);
FilterEffectVector& inputEffects() { return m_inputEffects; }
FilterEffect* inputEffect(unsigned) const;
unsigned numberOfEffectInputs() const { return m_inputEffects.size(); }
@@ -178,6 +177,12 @@
virtual void platformApplySoftware() = 0;
void copyImageBytes(const Uint8ClampedArray& source, Uint8ClampedArray& destination, const IntRect&) const;
+ void copyConvertedImageBufferToDestination(Uint8ClampedArray&, ColorSpace, AlphaPremultiplication, const IntRect&);
+ void copyConvertedImageDataToDestination(Uint8ClampedArray&, ImageData&, ColorSpace, AlphaPremultiplication, const IntRect&);
+ bool requiresImageDataColorSpaceConversion(Optional<ColorSpace>);
+ RefPtr<ImageData> convertImageDataToColorSpace(ColorSpace, ImageData&, AlphaPremultiplication);
+ RefPtr<ImageData> convertImageBufferToColorSpace(ColorSpace, ImageBuffer&, const IntRect&, AlphaPremultiplication);
+
Filter& m_filter;
FilterEffectVector m_inputEffects;