Title: [262893] trunk
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;
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to