Title: [277569] trunk
Revision
277569
Author
wei...@apple.com
Date
2021-05-16 08:21:34 -0700 (Sun, 16 May 2021)

Log Message

Add support for creating/accessing/setting non-sRGB ImageData via canvas
https://bugs.webkit.org/show_bug.cgi?id=225841

Reviewed by Darin Adler.

LayoutTests/imported/w3c:

* web-platform-tests/html/canvas/element/wide-gamut-canvas/2d.color.space.p3.to.p3-expected.txt:
Update result to passing.

Source/WebCore:

Test: fast/canvas/canvas-color-space-display-p3-ImageData.html

Add support for accessing non-sRGB (only DisplayP3 for now due
to the specification, but the support is general) pixel data in
HTML canvas.

Updates ImageData constructors and CanvasImageData operations to
take optional ImageDataSettings dictionaries, which contain an
optional color space (otherwise defaulting back to sRGB).

* CMakeLists.txt:
* DerivedSources-input.xcfilelist:
* DerivedSources-output.xcfilelist:
* DerivedSources.make:
* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* html/ImageDataSettings.h: Added.
* html/ImageDataSettings.idl: Added.
Add new ImageDataSettings.idl and related files.

* bindings/js/SerializedScriptValue.cpp:
(WebCore::CloneDeserializer::readImageBitmap):
Fixes FIXME and uses PixelBuffer directly rather than allocating
an unnecessary ImageData. This was done now since the relevent
ImageData constructor has gone away.

* html/ImageData.cpp:
(WebCore::computeDataSize):
(WebCore::ImageData::computeColorSpace):
(WebCore::ImageData::create):
(WebCore::ImageData::createUninitialized):
(WebCore::ImageData::ImageData):
(WebCore::ImageData::pixelBuffer const):
(WebCore::ImageData::dataSize): Deleted.
(WebCore::ImageData::deepClone const): Deleted.
* html/ImageData.h:
(WebCore::ImageData::size const):
(WebCore::ImageData::width const):
(WebCore::ImageData::height const):
(WebCore::ImageData::data const):
(WebCore::ImageData::colorSpace const):
(WebCore::ImageData::pixelBuffer const): Deleted.

- Reworked ImageData to no longer store a PixelBuffer, which has
  extraneous information in it, but rather to store just what it
  needs IntSize, Ref<JSC::Uint8ClampedArray>, and now PredefinedColorSpace.
- Updates create functions for new optional ImageDataSettings.
- Adds createUninitialized which follows spec language for ImageData creation
  and is used by CanvasRenderingContext2D to create ImageData objects of with
  the right color spaces, allowing for fallback to the canvas' own color space
  when no ImageDataSettings color space is provided. It is uninitialized and
  therefore requires the client to initialize the data to allow for support for
  no alpha support in the future, which requires a non-zero initialization pattern.

* html/ImageData.idl:
Add optional ImageDataSettings parameters and the new colorSpace attribute.

* html/canvas/CanvasImageData.idl:
Add optional ImageDataSettings parameters.

* html/canvas/CanvasRenderingContext2DBase.h:
* html/canvas/CanvasRenderingContext2DBase.cpp:
(WebCore::initializeEmptyImageData):
Add helper to initialize the ImageData buffer. Right now it always calls
zeroFill(), but in the future it will need to do more.

(WebCore::CanvasRenderingContext2DBase::createImageData const):
Update to account for this function being able to throw an exception (when
out of memory) and use the new createUninitialized/initializeEmptyImageData
to create a correctly color spaced ImageData.

(WebCore::CanvasRenderingContext2DBase::createImageData const):
Update for new optional ImageDataSettings and use the new createUninitialized
initializeEmptyImageData to create a correctly color spaced ImageData.

(WebCore::CanvasRenderingContext2DBase::getImageData const):
Moves parameter checks to the begining to match the spec, and uses new
createUninitialized/initializeEmptyImageData to create a correctly color
spaced ImageData. Also, use the ImageData's color space when getting
the pixel buffer to actually return the right data!

* html/canvas/PredefinedColorSpace.cpp:
(WebCore::toPredefinedColorSpace):
* html/canvas/PredefinedColorSpace.h:
Add conversion function from DestinationColorSpace to PredefinedColorSpace.
Since DestinationColorSpace is a superset of PredefinedColorSpace, this can
fail, so this conversion returns an Optional.

* inspector/InspectorCanvas.cpp:
* inspector/InspectorCanvasCallTracer.cpp:
* inspector/InspectorCanvasCallTracer.h:
Stub out inspector support for ImageDataSettings.

* platform/graphics/ImageBufferBackend.cpp:
(WebCore::ImageBufferBackend::getPixelBuffer const):
Use the ImageBuffer's actual color space as the source color space
rather than hard coding sRGB. This allows the color space conversion
to take place. Also remove some unnecessary temporary variables.

(WebCore::ImageBufferBackend::putPixelBuffer):
Use the ImageBuffer's actual color space as the destination color space
rather than hard coding sRGB. This allows the color space conversion
to take place. Also remove some unnecessary temporary variables.

* platform/graphics/PixelBuffer.cpp:
(WebCore::PixelBuffer::tryCreate):
(WebCore::PixelBuffer::PixelBuffer):
* platform/graphics/PixelBuffer.h:
(WebCore::PixelBuffer::takeData):
Add a few helpers to allow creationg to/from PixelBuffer
a bit easier.

* platform/graphics/PixelBufferConversion.cpp:
(WebCore::convertImagePixelsAccelerated):
Fix incorrect assertion. We want to assert that there is no error, not that
there is one.

* platform/graphics/filters/FilterEffect.cpp:
(WebCore::FilterEffect::convertImageBufferToColorSpace):
(WebCore::FilterEffect::copyUnmultipliedResult):
(WebCore::FilterEffect::copyPremultipliedResult):
(WebCore::FilterEffect::createUnmultipliedImageResult):
(WebCore::FilterEffect::createPremultipliedImageResult):
Stop hard coding SRGB for PixelBuffer color spaces and use the appropriate
color space for the task. We still do color space conversion through ImageBuffer
so we should come back and simplify code here to not always require that.

* testing/Internals.cpp:
(WebCore::Internals::videoSampleAvailable):
(WebCore::Internals::loadArtworkImage):
Update to specify a color space to maintain existing behavior.

Source/WebKitLegacy/win:

Add support for tests enabling the CanvasColorSpaceEnabled preference.

* WebPreferences.cpp:
(WebPreferences::canvasColorSpaceEnabled):
* WebPreferences.h:
* WebView.cpp:
(WebView::notifyPreferencesChanged):

LayoutTests:

* TestExpectations:
Remove wide-gamut-canvas now that they should pass.

* fast/canvas/canvas-color-space-display-p3-ImageData-expected.txt: Added.
* fast/canvas/canvas-color-space-display-p3-ImageData.html: Added.
Add new test exercising getImageData and putImageData with non-sRGB canvases
and non-sRGB ImageData.

* fast/canvas/canvas-imageData-expected.txt:
Update results for updated error messages, which are a bit worse due additional
ambiguity in signatures.

* platform/glib/TestExpectations:
Mark new test as failing on glib due to lack of display-p3 support.

* platform/win/TestExpectations:
Mark new test as failing on Windows due to lack of display-p3 support.
Unskip CanvasRenderingContext2DSettings-colorSpace-enabled.html which
should now pass due to adding manual preferences support in WebKitLegacy/win.

* storage/indexeddb/modern/objectstore-autoincrement-types-expected.txt:
Update results due to new attribute in ImageData that is auto printed.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (277568 => 277569)


--- trunk/LayoutTests/ChangeLog	2021-05-16 15:00:51 UTC (rev 277568)
+++ trunk/LayoutTests/ChangeLog	2021-05-16 15:21:34 UTC (rev 277569)
@@ -1,3 +1,33 @@
+2021-05-16  Sam Weinig  <wei...@apple.com>
+
+        Add support for creating/accessing/setting non-sRGB ImageData via canvas
+        https://bugs.webkit.org/show_bug.cgi?id=225841
+
+        Reviewed by Darin Adler.
+
+        * TestExpectations:
+        Remove wide-gamut-canvas now that they should pass.
+
+        * fast/canvas/canvas-color-space-display-p3-ImageData-expected.txt: Added.
+        * fast/canvas/canvas-color-space-display-p3-ImageData.html: Added.
+        Add new test exercising getImageData and putImageData with non-sRGB canvases
+        and non-sRGB ImageData.
+ 
+        * fast/canvas/canvas-imageData-expected.txt:
+        Update results for updated error messages, which are a bit worse due additional
+        ambiguity in signatures.
+
+        * platform/glib/TestExpectations:
+        Mark new test as failing on glib due to lack of display-p3 support.
+
+        * platform/win/TestExpectations:
+        Mark new test as failing on Windows due to lack of display-p3 support.
+        Unskip CanvasRenderingContext2DSettings-colorSpace-enabled.html which
+        should now pass due to adding manual preferences support in WebKitLegacy/win. 
+
+        * storage/indexeddb/modern/objectstore-autoincrement-types-expected.txt:
+        Update results due to new attribute in ImageData that is auto printed.
+
 2021-05-16  Tim Nguyen  <n...@apple.com>
 
         Make will-change: transform-style create a containing block

Modified: trunk/LayoutTests/TestExpectations (277568 => 277569)


--- trunk/LayoutTests/TestExpectations	2021-05-16 15:00:51 UTC (rev 277568)
+++ trunk/LayoutTests/TestExpectations	2021-05-16 15:21:34 UTC (rev 277569)
@@ -3994,9 +3994,6 @@
 imported/w3c/web-platform-tests/html/canvas/element/drawing-images-to-the-canvas/image-orientation/drawImage-from-element-swap-width-height.tentative.html [ ImageOnlyFailure ]
 imported/w3c/web-platform-tests/html/canvas/element/drawing-images-to-the-canvas/image-orientation/drawImage-from-element.tentative.html [ ImageOnlyFailure ]
 
-# Sometimes prints weird output at the beginning of the tests.
-imported/w3c/web-platform-tests/html/canvas/element/wide-gamut-canvas [ Failure Pass ]
-
 # CSS Masonry Layout not supported.
 imported/w3c/web-platform-tests/css/css-grid/masonry.tentative [ Skip ]
 webkit.org/b/202115 imported/w3c/web-platform-tests/css/css-grid/subgrid [ Skip ]

Added: trunk/LayoutTests/fast/canvas/canvas-color-space-display-p3-ImageData-expected.txt (0 => 277569)


--- trunk/LayoutTests/fast/canvas/canvas-color-space-display-p3-ImageData-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/canvas/canvas-color-space-display-p3-ImageData-expected.txt	2021-05-16 15:21:34 UTC (rev 277569)
@@ -0,0 +1,159 @@
+Test that pixel access functions work with non-SRGB color spaces.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS imageDataCreatedFromDisplayP3Canvas.colorSpace is "display-p3"
+PASS imageDataCreatedFromDisplayP3CanvasOverridingColorSpaceSRGB.colorSpace is "srgb"
+PASS imageDataCreatedFromDisplayP3CanvasOverridingColorSpaceDisplayP3.colorSpace is "display-p3"
+PASS imageDataCreatedFromSRGBCanvas.colorSpace is "srgb"
+PASS imageDataCreatedFromSRGBCanvasOverridingColorSpaceSRGB.colorSpace is "srgb"
+PASS imageDataCreatedFromSRGBCanvasOverridingColorSpaceDisplayP3.colorSpace is "display-p3"
+PASS imageDataCreatedFromImageDataConstructor.colorSpace is "srgb"
+PASS imageDataCreatedFromImageDataConstructorSettingColorSpaceToSRGB.colorSpace is "srgb"
+PASS imageDataCreatedFromImageDataConstructorSettingColorSpaceToDisplayP3.colorSpace is "display-p3"
+PASS imageDataCreatedFromImageDataConstructorPassingBuffer.colorSpace is "srgb"
+PASS imageDataCreatedFromImageDataConstructorPassingBufferSettingColorSpaceToSRGB.colorSpace is "srgb"
+PASS imageDataCreatedFromImageDataConstructorPassingBufferSettingColorSpaceToDisplayP3.colorSpace is "display-p3"
+
+Testing a display-p3 canvas with color(display-p3 0 1 0) drawn into it
+
+Test getImageData with no specified color space, on a display-p3 canvas (canvas has color(display-p3 0 1 0) drawn in it)
+PASS data.colorSpace is "display-p3"
+PASS data.data[0] is 0
+PASS data.data[1] is 255
+PASS data.data[2] is 0
+PASS data.data[3] is 255
+Test getImageData with srgb specified, on a display-p3 canvas (canvas has color(display-p3 0 1 0) drawn in it)
+PASS data.colorSpace is "srgb"
+PASS data.data[0] is 0
+PASS data.data[1] is 255
+PASS data.data[2] is 0
+PASS data.data[3] is 255
+Test getImageData with display-p3 specified, on a display-p3 canvas (canvas has color(display-p3 0 1 0) drawn in it)
+PASS data.colorSpace is "display-p3"
+PASS data.data[0] is 0
+PASS data.data[1] is 255
+PASS data.data[2] is 0
+PASS data.data[3] is 255
+
+Testing a display-p3 canvas with color(srgb 0 1 0) drawn into it
+
+Test getImageData with no specified color space, on a display-p3 canvas (canvas has color(srgb 0 1 0) drawn in it)
+PASS data.colorSpace is "display-p3"
+PASS data.data[0] is 117
+PASS data.data[1] is 251
+PASS data.data[2] is 76
+PASS data.data[3] is 255
+Test getImageData with srgb specified, on a display-p3 canvas (canvas has color(srgb 0 1 0) drawn in it)
+PASS data.colorSpace is "srgb"
+PASS data.data[0] is 3
+PASS data.data[1] is 255
+PASS data.data[2] is 0
+PASS data.data[3] is 255
+Test getImageData with display-p3 specified, on a display-p3 canvas (canvas has color(srgb 0 1 0) drawn in it)
+PASS data.colorSpace is "display-p3"
+PASS data.data[0] is 117
+PASS data.data[1] is 251
+PASS data.data[2] is 76
+PASS data.data[3] is 255
+
+Testing a srgb canvas with color(display-p3 0 1 0) drawn into it
+
+Test getImageData with no specified color space, on a srgb canvas (canvas has color(display-p3 0 1 0) drawn in it)
+PASS data.colorSpace is "srgb"
+PASS data.data[0] is 0
+PASS data.data[1] is 255
+PASS data.data[2] is 0
+PASS data.data[3] is 255
+Test getImageData with srgb specified, on a srgb canvas (canvas has color(display-p3 0 1 0) drawn in it)
+PASS data.colorSpace is "srgb"
+PASS data.data[0] is 0
+PASS data.data[1] is 255
+PASS data.data[2] is 0
+PASS data.data[3] is 255
+Test getImageData with display-p3 specified, on a srgb canvas (canvas has color(display-p3 0 1 0) drawn in it)
+PASS data.colorSpace is "display-p3"
+PASS data.data[0] is 117
+PASS data.data[1] is 251
+PASS data.data[2] is 76
+PASS data.data[3] is 255
+
+Testing a srgb canvas with color(srgb-p3 0 1 0) drawn into it
+
+Test getImageData with no specified color space, on a srgb canvas (canvas has color(srgb 0 1 0) drawn in it)
+PASS data.colorSpace is "srgb"
+PASS data.data[0] is 0
+PASS data.data[1] is 255
+PASS data.data[2] is 0
+PASS data.data[3] is 255
+Test getImageData with srgb specified, on a srgb canvas (canvas has color(srgb 0 1 0) drawn in it)
+PASS data.colorSpace is "srgb"
+PASS data.data[0] is 0
+PASS data.data[1] is 255
+PASS data.data[2] is 0
+PASS data.data[3] is 255
+Test getImageData with display-p3 specified, on a srgb canvas (canvas has color(srgb 0 1 0) drawn in it)
+PASS data.colorSpace is "display-p3"
+PASS data.data[0] is 117
+PASS data.data[1] is 251
+PASS data.data[2] is 76
+PASS data.data[3] is 255
+
+
+Testing a display-p3 canvas with display-p3 ImageData drawn into it
+
+PASS data.colorSpace is "srgb"
+PASS data.data[0] is 0
+PASS data.data[1] is 255
+PASS data.data[2] is 0
+PASS data.data[3] is 255
+PASS data.colorSpace is "display-p3"
+PASS data.data[0] is 0
+PASS data.data[1] is 255
+PASS data.data[2] is 0
+PASS data.data[3] is 255
+
+Testing a display-p3 canvas with srgb ImageData drawn into it
+
+PASS data.colorSpace is "srgb"
+PASS data.data[0] is 3
+PASS data.data[1] is 255
+PASS data.data[2] is 0
+PASS data.data[3] is 255
+PASS data.colorSpace is "display-p3"
+PASS data.data[0] is 117
+PASS data.data[1] is 251
+PASS data.data[2] is 76
+PASS data.data[3] is 255
+
+Testing a srgb canvas with display-p3 ImageData drawn into it
+
+PASS data.colorSpace is "srgb"
+PASS data.data[0] is 0
+PASS data.data[1] is 255
+PASS data.data[2] is 0
+PASS data.data[3] is 255
+PASS data.colorSpace is "display-p3"
+PASS data.data[0] is 117
+PASS data.data[1] is 251
+PASS data.data[2] is 76
+PASS data.data[3] is 255
+
+Testing a srgb canvas with srgb ImageData drawn into it
+
+PASS data.colorSpace is "srgb"
+PASS data.data[0] is 0
+PASS data.data[1] is 255
+PASS data.data[2] is 0
+PASS data.data[3] is 255
+PASS data.colorSpace is "display-p3"
+PASS data.data[0] is 117
+PASS data.data[1] is 251
+PASS data.data[2] is 76
+PASS data.data[3] is 255
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/fast/canvas/canvas-color-space-display-p3-ImageData.html (0 => 277569)


--- trunk/LayoutTests/fast/canvas/canvas-color-space-display-p3-ImageData.html	                        (rev 0)
+++ trunk/LayoutTests/fast/canvas/canvas-color-space-display-p3-ImageData.html	2021-05-16 15:21:34 UTC (rev 277569)
@@ -0,0 +1,290 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<script>
+description("Test that pixel access functions work with non-SRGB color spaces.");
+
+let canvasDisplayP3 = document.createElement("canvas");
+let contextDisplayP3 = canvasDisplayP3.getContext("2d", { colorSpace: "display-p3" });
+
+let canvasSRGB = document.createElement("canvas");
+let contextSRGB = canvasSRGB.getContext("2d", { colorSpace: "srgb" });
+
+const imageDataCreatedFromDisplayP3Canvas = contextDisplayP3.createImageData(50, 50);
+shouldBe("imageDataCreatedFromDisplayP3Canvas.colorSpace", `"display-p3"`);
+
+const imageDataCreatedFromDisplayP3CanvasOverridingColorSpaceSRGB = contextDisplayP3.createImageData(50, 50, { colorSpace: "srgb" });
+shouldBe("imageDataCreatedFromDisplayP3CanvasOverridingColorSpaceSRGB.colorSpace", `"srgb"`);
+
+const imageDataCreatedFromDisplayP3CanvasOverridingColorSpaceDisplayP3 = contextDisplayP3.createImageData(50, 50, { colorSpace: "display-p3" });
+shouldBe("imageDataCreatedFromDisplayP3CanvasOverridingColorSpaceDisplayP3.colorSpace", `"display-p3"`);
+
+const imageDataCreatedFromSRGBCanvas = contextSRGB.createImageData(50, 50);
+shouldBe("imageDataCreatedFromSRGBCanvas.colorSpace", `"srgb"`);
+
+const imageDataCreatedFromSRGBCanvasOverridingColorSpaceSRGB = contextSRGB.createImageData(50, 50, { colorSpace: "srgb" });
+shouldBe("imageDataCreatedFromSRGBCanvasOverridingColorSpaceSRGB.colorSpace", `"srgb"`);
+
+const imageDataCreatedFromSRGBCanvasOverridingColorSpaceDisplayP3 = contextSRGB.createImageData(50, 50, { colorSpace: "display-p3" });
+shouldBe("imageDataCreatedFromSRGBCanvasOverridingColorSpaceDisplayP3.colorSpace", `"display-p3"`);
+
+const imageDataCreatedFromImageDataConstructor = new ImageData(50, 50, { colorSpace: "srgb" });
+shouldBe("imageDataCreatedFromImageDataConstructor.colorSpace", `"srgb"`);
+
+const imageDataCreatedFromImageDataConstructorSettingColorSpaceToSRGB = new ImageData(50, 50, { colorSpace: "srgb" });
+shouldBe("imageDataCreatedFromImageDataConstructorSettingColorSpaceToSRGB.colorSpace", `"srgb"`);
+
+const imageDataCreatedFromImageDataConstructorSettingColorSpaceToDisplayP3 = new ImageData(50, 50, { colorSpace: "display-p3" });
+shouldBe("imageDataCreatedFromImageDataConstructorSettingColorSpaceToDisplayP3.colorSpace", `"display-p3"`);
+
+const imageDataCreatedFromImageDataConstructorPassingBuffer = new ImageData(new Uint8ClampedArray(400), 10, 10, { colorSpace: "srgb" });
+shouldBe("imageDataCreatedFromImageDataConstructorPassingBuffer.colorSpace", `"srgb"`);
+
+const imageDataCreatedFromImageDataConstructorPassingBufferSettingColorSpaceToSRGB = new ImageData(new Uint8ClampedArray(400), 10, 10, { colorSpace: "srgb" });
+shouldBe("imageDataCreatedFromImageDataConstructorPassingBufferSettingColorSpaceToSRGB.colorSpace", `"srgb"`);
+
+const imageDataCreatedFromImageDataConstructorPassingBufferSettingColorSpaceToDisplayP3 = new ImageData(new Uint8ClampedArray(400), 10, 10, { colorSpace: "display-p3" });
+shouldBe("imageDataCreatedFromImageDataConstructorPassingBufferSettingColorSpaceToDisplayP3.colorSpace", `"display-p3"`);
+
+var data = { };
+
+// NOTE:
+// color(srgb 0 1 0) converted to display-p3 is color(display-p3 0.4584 0.98526 0.29829) or [117, 251, 76, 255] in byte form.
+
+debug("");
+debug("Testing a display-p3 canvas with color(display-p3 0 1 0) drawn into it");
+debug("");
+
+contextDisplayP3.fillStyle = "color(display-p3 0 1 0)";
+contextDisplayP3.fillRect(0, 0, 50, 50);
+
+// No specified color space will default to the canvas' color space, in this case, display-p3
+debug("Test getImageData with no specified color space, on a display-p3 canvas (canvas has color(display-p3 0 1 0) drawn in it)");
+data = "" 0, 1, 1);
+shouldBe("data.colorSpace", `"display-p3"`)
+shouldBe("data.data[0]", "0");
+shouldBe("data.data[1]", "255");
+shouldBe("data.data[2]", "0");
+shouldBe("data.data[3]", "255");
+
+debug("Test getImageData with srgb specified, on a display-p3 canvas (canvas has color(display-p3 0 1 0) drawn in it)");
+// NOTE: color(display-p3 0 1 0) is outside the range of sRGB, so it clipped to 255.
+data = "" 0, 1, 1, { colorSpace: "srgb" });
+shouldBe("data.colorSpace", `"srgb"`)
+shouldBe("data.data[0]", "0");
+shouldBe("data.data[1]", "255");
+shouldBe("data.data[2]", "0");
+shouldBe("data.data[3]", "255");
+
+debug("Test getImageData with display-p3 specified, on a display-p3 canvas (canvas has color(display-p3 0 1 0) drawn in it)");
+data = "" 0, 1, 1, { colorSpace: "display-p3" });
+shouldBe("data.colorSpace", `"display-p3"`)
+shouldBe("data.data[0]", "0");
+shouldBe("data.data[1]", "255");
+shouldBe("data.data[2]", "0");
+shouldBe("data.data[3]", "255");
+
+debug("");
+debug("Testing a display-p3 canvas with color(srgb 0 1 0) drawn into it");
+debug("");
+
+contextDisplayP3.fillStyle = "color(srgb 0 1 0)";
+contextDisplayP3.fillRect(0, 0, 50, 50);
+
+// No specified color space will default to the canvas' color space, in this case, display-p3
+debug("Test getImageData with no specified color space, on a display-p3 canvas (canvas has color(srgb 0 1 0) drawn in it)");
+data = "" 0, 1, 1);
+shouldBe("data.colorSpace", `"display-p3"`)
+shouldBe("data.data[0]", "117");
+shouldBe("data.data[1]", "251");
+shouldBe("data.data[2]", "76");
+shouldBe("data.data[3]", "255");
+
+debug("Test getImageData with srgb specified, on a display-p3 canvas (canvas has color(srgb 0 1 0) drawn in it)");
+data = "" 0, 1, 1, { colorSpace: "srgb" });
+shouldBe("data.colorSpace", `"srgb"`)
+// NOTE: This 3 is odd, but due to lack of precision in 8-bit round-tripping.
+shouldBe("data.data[0]", "3");
+shouldBe("data.data[1]", "255");
+shouldBe("data.data[2]", "0");
+shouldBe("data.data[3]", "255");
+
+debug("Test getImageData with display-p3 specified, on a display-p3 canvas (canvas has color(srgb 0 1 0) drawn in it)");
+data = "" 0, 1, 1, { colorSpace: "display-p3" });
+shouldBe("data.colorSpace", `"display-p3"`)
+shouldBe("data.data[0]", "117");
+shouldBe("data.data[1]", "251");
+shouldBe("data.data[2]", "76");
+shouldBe("data.data[3]", "255");
+
+debug("");
+debug("Testing a srgb canvas with color(display-p3 0 1 0) drawn into it");
+debug("");
+
+contextSRGB.fillStyle = "color(display-p3 0 1 0)";
+contextSRGB.fillRect(0, 0, 50, 50);
+
+// No specified color space will default to the canvas' color space, in this case, srgb
+debug("Test getImageData with no specified color space, on a srgb canvas (canvas has color(display-p3 0 1 0) drawn in it)");
+data = "" 0, 1, 1);
+shouldBe("data.colorSpace", `"srgb"`)
+shouldBe("data.data[0]", "0");
+shouldBe("data.data[1]", "255");
+shouldBe("data.data[2]", "0");
+shouldBe("data.data[3]", "255");
+
+debug("Test getImageData with srgb specified, on a srgb canvas (canvas has color(display-p3 0 1 0) drawn in it)");
+data = "" 0, 1, 1, { colorSpace: "srgb" });
+shouldBe("data.colorSpace", `"srgb"`)
+shouldBe("data.data[0]", "0");
+shouldBe("data.data[1]", "255");
+shouldBe("data.data[2]", "0");
+shouldBe("data.data[3]", "255");
+
+debug("Test getImageData with display-p3 specified, on a srgb canvas (canvas has color(display-p3 0 1 0) drawn in it)");
+data = "" 0, 1, 1, { colorSpace: "display-p3" });
+shouldBe("data.colorSpace", `"display-p3"`)
+shouldBe("data.data[0]", "117");
+shouldBe("data.data[1]", "251");
+shouldBe("data.data[2]", "76");
+shouldBe("data.data[3]", "255");
+
+debug("");
+debug("Testing a srgb canvas with color(srgb-p3 0 1 0) drawn into it");
+debug("");
+
+contextSRGB.fillStyle = "color(srgb 0 1 0)";
+contextSRGB.fillRect(0, 0, 50, 50);
+
+// No specified color space will default to the canvas' color space, in this case, srgb
+debug("Test getImageData with no specified color space, on a srgb canvas (canvas has color(srgb 0 1 0) drawn in it)");
+data = "" 0, 1, 1);
+shouldBe("data.colorSpace", `"srgb"`)
+shouldBe("data.data[0]", "0");
+shouldBe("data.data[1]", "255");
+shouldBe("data.data[2]", "0");
+shouldBe("data.data[3]", "255");
+
+debug("Test getImageData with srgb specified, on a srgb canvas (canvas has color(srgb 0 1 0) drawn in it)");
+data = "" 0, 1, 1, { colorSpace: "srgb" });
+shouldBe("data.colorSpace", `"srgb"`)
+shouldBe("data.data[0]", "0");
+shouldBe("data.data[1]", "255");
+shouldBe("data.data[2]", "0");
+shouldBe("data.data[3]", "255");
+
+debug("Test getImageData with display-p3 specified, on a srgb canvas (canvas has color(srgb 0 1 0) drawn in it)");
+data = "" 0, 1, 1, { colorSpace: "display-p3" });
+shouldBe("data.colorSpace", `"display-p3"`)
+shouldBe("data.data[0]", "117");
+shouldBe("data.data[1]", "251");
+shouldBe("data.data[2]", "76");
+shouldBe("data.data[3]", "255");
+
+
+debug("");
+
+
+const imageDataDisplayP3ToPut = new ImageData(1, 1, { colorSpace: "display-p3" });
+imageDataDisplayP3ToPut.data[0] = 0;
+imageDataDisplayP3ToPut.data[1] = 255;
+imageDataDisplayP3ToPut.data[2] = 0;
+imageDataDisplayP3ToPut.data[3] = 255;
+
+const imageDataSRGBToPut = new ImageData(1, 1, { colorSpace: "srgb" });
+imageDataSRGBToPut.data[0] = 0;
+imageDataSRGBToPut.data[1] = 255;
+imageDataSRGBToPut.data[2] = 0;
+imageDataSRGBToPut.data[3] = 255;
+
+
+debug("");
+debug("Testing a display-p3 canvas with display-p3 ImageData drawn into it");
+debug("");
+
+contextDisplayP3.putImageData(imageDataDisplayP3ToPut, 0, 0);
+
+data = "" 0, 1, 1, { colorSpace: "srgb" });
+shouldBe("data.colorSpace", `"srgb"`)
+shouldBe("data.data[0]", "0");
+shouldBe("data.data[1]", "255");
+shouldBe("data.data[2]", "0");
+shouldBe("data.data[3]", "255");
+
+data = "" 0, 1, 1, { colorSpace: "display-p3" });
+shouldBe("data.colorSpace", `"display-p3"`)
+shouldBe("data.data[0]", "0");
+shouldBe("data.data[1]", "255");
+shouldBe("data.data[2]", "0");
+shouldBe("data.data[3]", "255");
+
+debug("");
+debug("Testing a display-p3 canvas with srgb ImageData drawn into it");
+debug("");
+
+contextDisplayP3.putImageData(imageDataSRGBToPut, 0, 0);
+
+data = "" 0, 1, 1, { colorSpace: "srgb" });
+shouldBe("data.colorSpace", `"srgb"`)
+// NOTE: This 3 is odd, but due to lack of precision in 8-bit round-tripping.
+shouldBe("data.data[0]", "3");
+shouldBe("data.data[1]", "255");
+shouldBe("data.data[2]", "0");
+shouldBe("data.data[3]", "255");
+
+data = "" 0, 1, 1, { colorSpace: "display-p3" });
+shouldBe("data.colorSpace", `"display-p3"`)
+shouldBe("data.data[0]", "117");
+shouldBe("data.data[1]", "251");
+shouldBe("data.data[2]", "76");
+shouldBe("data.data[3]", "255");
+
+debug("");
+debug("Testing a srgb canvas with display-p3 ImageData drawn into it");
+debug("");
+
+contextSRGB.putImageData(imageDataDisplayP3ToPut, 0, 0);
+
+data = "" 0, 1, 1, { colorSpace: "srgb" });
+shouldBe("data.colorSpace", `"srgb"`)
+shouldBe("data.data[0]", "0");
+shouldBe("data.data[1]", "255");
+shouldBe("data.data[2]", "0");
+shouldBe("data.data[3]", "255");
+
+data = "" 0, 1, 1, { colorSpace: "display-p3" });
+shouldBe("data.colorSpace", `"display-p3"`)
+shouldBe("data.data[0]", "117");
+shouldBe("data.data[1]", "251");
+shouldBe("data.data[2]", "76");
+shouldBe("data.data[3]", "255");
+
+
+debug("");
+debug("Testing a srgb canvas with srgb ImageData drawn into it");
+debug("");
+
+contextSRGB.putImageData(imageDataSRGBToPut, 0, 0);
+
+data = "" 0, 1, 1, { colorSpace: "srgb" });
+shouldBe("data.colorSpace", `"srgb"`)
+shouldBe("data.data[0]", "0");
+shouldBe("data.data[1]", "255");
+shouldBe("data.data[2]", "0");
+shouldBe("data.data[3]", "255");
+
+data = "" 0, 1, 1, { colorSpace: "display-p3" });
+shouldBe("data.colorSpace", `"display-p3"`)
+shouldBe("data.data[0]", "117");
+shouldBe("data.data[1]", "251");
+shouldBe("data.data[2]", "76");
+shouldBe("data.data[3]", "255");
+
+debug("");
+</script>
+<script src=""
+</body>
+</html>

Modified: trunk/LayoutTests/fast/canvas/canvas-imageData-expected.txt (277568 => 277569)


--- trunk/LayoutTests/fast/canvas/canvas-imageData-expected.txt	2021-05-16 15:00:51 UTC (rev 277568)
+++ trunk/LayoutTests/fast/canvas/canvas-imageData-expected.txt	2021-05-16 15:21:34 UTC (rev 277569)
@@ -14,20 +14,20 @@
 PASS new ImageData(20, -20) threw exception RangeError: Cannot allocate a buffer of this size.
 PASS new ImageData(null, 20) threw exception IndexSizeError: The index is not in the allowed range..
 PASS new ImageData(32768, 32768) threw exception RangeError: Cannot allocate a buffer of this size.
-PASS new ImageData(null, 20, 20) threw exception TypeError: Argument 1 ('data') to the ImageData constructor must be an instance of Uint8ClampedArray.
-PASS new ImageData(imageData, 20, 20) threw exception TypeError: Argument 1 ('data') to the ImageData constructor must be an instance of Uint8ClampedArray.
+PASS new ImageData(null, 20, 20) threw exception TypeError: Type error.
+PASS new ImageData(imageData, 20, 20) threw exception TypeError: Type error.
 PASS new ImageData(imageData, 0) threw exception IndexSizeError: The index is not in the allowed range..
-PASS new ImageData(imageData, 20, 0) threw exception TypeError: Argument 1 ('data') to the ImageData constructor must be an instance of Uint8ClampedArray.
-PASS new ImageData(imageData, 0, 20) threw exception TypeError: Argument 1 ('data') to the ImageData constructor must be an instance of Uint8ClampedArray.
-PASS new ImageData(imageData, 10, 5) threw exception TypeError: Argument 1 ('data') to the ImageData constructor must be an instance of Uint8ClampedArray.
+PASS new ImageData(imageData, 20, 0) threw exception TypeError: Type error.
+PASS new ImageData(imageData, 0, 20) threw exception TypeError: Type error.
+PASS new ImageData(imageData, 10, 5) threw exception TypeError: Type error.
 PASS new ImageData(imageData.data, 10, 5) threw exception IndexSizeError: sh value is not equal to height.
 PASS new ImageData(imageData.data, -10, 5) threw exception IndexSizeError: Length is not a multiple of sw.
 PASS new ImageData(imageData.data, 10, -10) threw exception IndexSizeError: sh value is not equal to height.
 PASS new ImageData(new Uint8ClampedArray([1,2,3,4,5,6,7,8]),536870913,2); threw exception IndexSizeError: Length is not a multiple of sw.
-PASS new ImageData({},2,2); threw exception TypeError: Argument 1 ('data') to the ImageData constructor must be an instance of Uint8ClampedArray.
-PASS new ImageData(undefined,2,2); threw exception TypeError: Argument 1 ('data') to the ImageData constructor must be an instance of Uint8ClampedArray.
-PASS new ImageData("none",2,2); threw exception TypeError: Argument 1 ('data') to the ImageData constructor must be an instance of Uint8ClampedArray.
-PASS new ImageData(0,2,2); threw exception TypeError: Argument 1 ('data') to the ImageData constructor must be an instance of Uint8ClampedArray.
+PASS new ImageData({},2,2); threw exception TypeError: Type error.
+PASS new ImageData(undefined,2,2); threw exception TypeError: Type error.
+PASS new ImageData("none",2,2); threw exception TypeError: Type error.
+PASS new ImageData(0,2,2); threw exception TypeError: Type error.
 PASS new ImageData(imageData.data, 32768, 32768) threw exception IndexSizeError: Length is not a multiple of sw.
 PASS new ImageData(imageData.data, Infinity, Infinity) threw exception IndexSizeError: Length is not a multiple of sw.
 PASS new ImageData(imageData.data, NaN, NaN) threw exception IndexSizeError: Length is not a multiple of sw.

Modified: trunk/LayoutTests/imported/w3c/ChangeLog (277568 => 277569)


--- trunk/LayoutTests/imported/w3c/ChangeLog	2021-05-16 15:00:51 UTC (rev 277568)
+++ trunk/LayoutTests/imported/w3c/ChangeLog	2021-05-16 15:21:34 UTC (rev 277569)
@@ -1,3 +1,13 @@
+2021-05-16  Sam Weinig  <wei...@apple.com>
+
+        Add support for creating/accessing/setting non-sRGB ImageData via canvas
+        https://bugs.webkit.org/show_bug.cgi?id=225841
+
+        Reviewed by Darin Adler.
+
+        * web-platform-tests/html/canvas/element/wide-gamut-canvas/2d.color.space.p3.to.p3-expected.txt:
+        Update result to passing.
+
 2021-05-15  Said Abou-Hallawa  <s...@apple.com>
 
         Implement CanvasRenderingContext2D.createConicGradient

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/element/wide-gamut-canvas/2d.color.space.p3.to.p3-expected.txt (277568 => 277569)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/element/wide-gamut-canvas/2d.color.space.p3.to.p3-expected.txt	2021-05-16 15:00:51 UTC (rev 277568)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/html/canvas/element/wide-gamut-canvas/2d.color.space.p3.to.p3-expected.txt	2021-05-16 15:21:34 UTC (rev 277569)
@@ -2,5 +2,5 @@
 test getImageData with display-p3 and uint8 from display p3 uint8 canvas
 Actual output:
 
-FAIL test getImageData with display-p3 and uint8 from display p3 uint8 canvas assert_approx_equals: expected 62 +/- 2 but got 50
+PASS test getImageData with display-p3 and uint8 from display p3 uint8 canvas
 

Modified: trunk/LayoutTests/platform/glib/TestExpectations (277568 => 277569)


--- trunk/LayoutTests/platform/glib/TestExpectations	2021-05-16 15:00:51 UTC (rev 277568)
+++ trunk/LayoutTests/platform/glib/TestExpectations	2021-05-16 15:21:34 UTC (rev 277569)
@@ -2358,6 +2358,7 @@
 webkit.org/b/224112 media/video-as-img-output-pts.html [ Timeout Pass ]
 
 webkit.org/b/225423 fast/canvas/canvas-color-space-display-p3.html [ ImageOnlyFailure ]
+webkit.org/b/225423 fast/canvas/canvas-color-space-display-p3-ImageData.html [ Failure ]
 webkit.org/b/225423 fast/canvas/canvas-composite-text-alpha.html [ Failure ]
 
 # Failing after r277073.

Modified: trunk/LayoutTests/platform/win/TestExpectations (277568 => 277569)


--- trunk/LayoutTests/platform/win/TestExpectations	2021-05-16 15:00:51 UTC (rev 277568)
+++ trunk/LayoutTests/platform/win/TestExpectations	2021-05-16 15:21:34 UTC (rev 277569)
@@ -4635,4 +4635,6 @@
 
 fast/text/line-break-with-locale.html [ ImageOnlyFailure ]
 
-fast/canvas/CanvasRenderingContext2DSettings-colorSpace-enabled.html [ Skip ]
+# Non-SRGB color spaces are not currently supported by the Windows port.
+fast/canvas/canvas-color-space-display-p3.html [ Skip ]
+fast/canvas/canvas-color-space-display-p3-ImageData.html [ Skip ]

Modified: trunk/LayoutTests/storage/indexeddb/modern/objectstore-autoincrement-types-expected.txt (277568 => 277569)


--- trunk/LayoutTests/storage/indexeddb/modern/objectstore-autoincrement-types-expected.txt	2021-05-16 15:00:51 UTC (rev 277568)
+++ trunk/LayoutTests/storage/indexeddb/modern/objectstore-autoincrement-types-expected.txt	2021-05-16 15:21:34 UTC (rev 277569)
@@ -26,6 +26,7 @@
 PASS request.result.primaryKey is imageData.primaryKey
 PASS request.result.width is imageData.width
 PASS request.result.height is imageData.height
+PASS request.result.colorSpace is imageData.colorSpace
 PASS key is 4
 PASS request.result.primaryKey is fileList.primaryKey
 PASS request.result.length is fileList.length
@@ -40,6 +41,7 @@
 PASS request.result[2].primaryKey is imageData.primaryKey
 PASS request.result[2].width is imageData.width
 PASS request.result[2].height is imageData.height
+PASS request.result[2].colorSpace is imageData.colorSpace
 PASS request.result[3].primaryKey is fileList.primaryKey
 PASS request.result[3].length is fileList.length
 PASS successfullyParsed is true

Modified: trunk/Source/WebCore/CMakeLists.txt (277568 => 277569)


--- trunk/Source/WebCore/CMakeLists.txt	2021-05-16 15:00:51 UTC (rev 277568)
+++ trunk/Source/WebCore/CMakeLists.txt	2021-05-16 15:21:34 UTC (rev 277569)
@@ -1017,6 +1017,7 @@
     html/ImageBitmap.idl
     html/ImageBitmapOptions.idl
     html/ImageData.idl
+    html/ImageDataSettings.idl
     html/MediaController.idl
     html/MediaEncryptedEvent.idl
     html/MediaError.idl

Modified: trunk/Source/WebCore/ChangeLog (277568 => 277569)


--- trunk/Source/WebCore/ChangeLog	2021-05-16 15:00:51 UTC (rev 277568)
+++ trunk/Source/WebCore/ChangeLog	2021-05-16 15:21:34 UTC (rev 277569)
@@ -1,3 +1,142 @@
+2021-05-16  Sam Weinig  <wei...@apple.com>
+
+        Add support for creating/accessing/setting non-sRGB ImageData via canvas
+        https://bugs.webkit.org/show_bug.cgi?id=225841
+
+        Reviewed by Darin Adler.
+
+        Test: fast/canvas/canvas-color-space-display-p3-ImageData.html
+
+        Add support for accessing non-sRGB (only DisplayP3 for now due
+        to the specification, but the support is general) pixel data in
+        HTML canvas.
+
+        Updates ImageData constructors and CanvasImageData operations to 
+        take optional ImageDataSettings dictionaries, which contain an 
+        optional color space (otherwise defaulting back to sRGB). 
+
+        * CMakeLists.txt:
+        * DerivedSources-input.xcfilelist:
+        * DerivedSources-output.xcfilelist:
+        * DerivedSources.make:
+        * Sources.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+        * html/ImageDataSettings.h: Added.
+        * html/ImageDataSettings.idl: Added.
+        Add new ImageDataSettings.idl and related files.
+
+        * bindings/js/SerializedScriptValue.cpp:
+        (WebCore::CloneDeserializer::readImageBitmap):
+        Fixes FIXME and uses PixelBuffer directly rather than allocating
+        an unnecessary ImageData. This was done now since the relevent
+        ImageData constructor has gone away.
+
+        * html/ImageData.cpp:
+        (WebCore::computeDataSize):
+        (WebCore::ImageData::computeColorSpace):
+        (WebCore::ImageData::create):
+        (WebCore::ImageData::createUninitialized):
+        (WebCore::ImageData::ImageData):
+        (WebCore::ImageData::pixelBuffer const):
+        (WebCore::ImageData::dataSize): Deleted.
+        (WebCore::ImageData::deepClone const): Deleted.
+        * html/ImageData.h:
+        (WebCore::ImageData::size const):
+        (WebCore::ImageData::width const):
+        (WebCore::ImageData::height const):
+        (WebCore::ImageData::data const):
+        (WebCore::ImageData::colorSpace const):
+        (WebCore::ImageData::pixelBuffer const): Deleted.
+
+        - Reworked ImageData to no longer store a PixelBuffer, which has
+          extraneous information in it, but rather to store just what it
+          needs IntSize, Ref<JSC::Uint8ClampedArray>, and now PredefinedColorSpace.
+        - Updates create functions for new optional ImageDataSettings.
+        - Adds createUninitialized which follows spec language for ImageData creation
+          and is used by CanvasRenderingContext2D to create ImageData objects of with
+          the right color spaces, allowing for fallback to the canvas' own color space
+          when no ImageDataSettings color space is provided. It is uninitialized and
+          therefore requires the client to initialize the data to allow for support for
+          no alpha support in the future, which requires a non-zero initialization pattern.
+
+        * html/ImageData.idl:
+        Add optional ImageDataSettings parameters and the new colorSpace attribute.
+
+        * html/canvas/CanvasImageData.idl:
+        Add optional ImageDataSettings parameters.
+
+        * html/canvas/CanvasRenderingContext2DBase.h:
+        * html/canvas/CanvasRenderingContext2DBase.cpp:
+        (WebCore::initializeEmptyImageData):
+        Add helper to initialize the ImageData buffer. Right now it always calls
+        zeroFill(), but in the future it will need to do more.
+        
+        (WebCore::CanvasRenderingContext2DBase::createImageData const):
+        Update to account for this function being able to throw an exception (when 
+        out of memory) and use the new createUninitialized/initializeEmptyImageData
+        to create a correctly color spaced ImageData.
+
+        (WebCore::CanvasRenderingContext2DBase::createImageData const):
+        Update for new optional ImageDataSettings and use the new createUninitialized
+        initializeEmptyImageData to create a correctly color spaced ImageData.
+
+        (WebCore::CanvasRenderingContext2DBase::getImageData const):
+        Moves parameter checks to the begining to match the spec, and uses new 
+        createUninitialized/initializeEmptyImageData to create a correctly color 
+        spaced ImageData. Also, use the ImageData's color space when getting
+        the pixel buffer to actually return the right data!
+
+        * html/canvas/PredefinedColorSpace.cpp:
+        (WebCore::toPredefinedColorSpace):
+        * html/canvas/PredefinedColorSpace.h:
+        Add conversion function from DestinationColorSpace to PredefinedColorSpace.
+        Since DestinationColorSpace is a superset of PredefinedColorSpace, this can
+        fail, so this conversion returns an Optional.
+
+        * inspector/InspectorCanvas.cpp:
+        * inspector/InspectorCanvasCallTracer.cpp:
+        * inspector/InspectorCanvasCallTracer.h:
+        Stub out inspector support for ImageDataSettings.
+
+        * platform/graphics/ImageBufferBackend.cpp:
+        (WebCore::ImageBufferBackend::getPixelBuffer const):
+        Use the ImageBuffer's actual color space as the source color space
+        rather than hard coding sRGB. This allows the color space conversion
+        to take place. Also remove some unnecessary temporary variables.
+
+        (WebCore::ImageBufferBackend::putPixelBuffer):
+        Use the ImageBuffer's actual color space as the destination color space
+        rather than hard coding sRGB. This allows the color space conversion
+        to take place. Also remove some unnecessary temporary variables.
+
+        * platform/graphics/PixelBuffer.cpp:
+        (WebCore::PixelBuffer::tryCreate):
+        (WebCore::PixelBuffer::PixelBuffer):
+        * platform/graphics/PixelBuffer.h:
+        (WebCore::PixelBuffer::takeData):
+        Add a few helpers to allow creationg to/from PixelBuffer
+        a bit easier.
+
+        * platform/graphics/PixelBufferConversion.cpp:
+        (WebCore::convertImagePixelsAccelerated):
+        Fix incorrect assertion. We want to assert that there is no error, not that
+        there is one.
+
+        * platform/graphics/filters/FilterEffect.cpp:
+        (WebCore::FilterEffect::convertImageBufferToColorSpace):
+        (WebCore::FilterEffect::copyUnmultipliedResult):
+        (WebCore::FilterEffect::copyPremultipliedResult):
+        (WebCore::FilterEffect::createUnmultipliedImageResult):
+        (WebCore::FilterEffect::createPremultipliedImageResult):
+        Stop hard coding SRGB for PixelBuffer color spaces and use the appropriate
+        color space for the task. We still do color space conversion through ImageBuffer
+        so we should come back and simplify code here to not always require that.
+
+        * testing/Internals.cpp:
+        (WebCore::Internals::videoSampleAvailable):
+        (WebCore::Internals::loadArtworkImage):
+        Update to specify a color space to maintain existing behavior.
+
 2021-05-16  Alan Bujtas  <za...@apple.com>
 
         [LFC] Cleanup margin collapsing class

Modified: trunk/Source/WebCore/DerivedSources-input.xcfilelist (277568 => 277569)


--- trunk/Source/WebCore/DerivedSources-input.xcfilelist	2021-05-16 15:00:51 UTC (rev 277568)
+++ trunk/Source/WebCore/DerivedSources-input.xcfilelist	2021-05-16 15:21:34 UTC (rev 277569)
@@ -1036,6 +1036,7 @@
 $(PROJECT_DIR)/html/ImageBitmap.idl
 $(PROJECT_DIR)/html/ImageBitmapOptions.idl
 $(PROJECT_DIR)/html/ImageData.idl
+$(PROJECT_DIR)/html/ImageDataSettings.idl
 $(PROJECT_DIR)/html/MediaController.idl
 $(PROJECT_DIR)/html/MediaEncryptedEvent.idl
 $(PROJECT_DIR)/html/MediaError.idl

Modified: trunk/Source/WebCore/DerivedSources-output.xcfilelist (277568 => 277569)


--- trunk/Source/WebCore/DerivedSources-output.xcfilelist	2021-05-16 15:00:51 UTC (rev 277568)
+++ trunk/Source/WebCore/DerivedSources-output.xcfilelist	2021-05-16 15:21:34 UTC (rev 277569)
@@ -1180,6 +1180,8 @@
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSImageBitmapRenderingContextSettings.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSImageData.cpp
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSImageData.h
+$(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSImageDataSettings.cpp
+$(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSImageDataSettings.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSImageSmoothingQuality.cpp
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSImageSmoothingQuality.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSInnerHTML.cpp

Modified: trunk/Source/WebCore/DerivedSources.make (277568 => 277569)


--- trunk/Source/WebCore/DerivedSources.make	2021-05-16 15:00:51 UTC (rev 277568)
+++ trunk/Source/WebCore/DerivedSources.make	2021-05-16 15:21:34 UTC (rev 277569)
@@ -890,6 +890,7 @@
     $(WebCore)/html/ImageBitmap.idl \
     $(WebCore)/html/ImageBitmapOptions.idl \
     $(WebCore)/html/ImageData.idl \
+    $(WebCore)/html/ImageDataSettings.idl \
     $(WebCore)/html/MediaController.idl \
     $(WebCore)/html/MediaEncryptedEvent.idl \
     $(WebCore)/html/MediaError.idl \

Modified: trunk/Source/WebCore/Sources.txt (277568 => 277569)


--- trunk/Source/WebCore/Sources.txt	2021-05-16 15:00:51 UTC (rev 277568)
+++ trunk/Source/WebCore/Sources.txt	2021-05-16 15:21:34 UTC (rev 277569)
@@ -3207,6 +3207,7 @@
 JSImageBitmapRenderingContext.cpp
 JSImageBitmapRenderingContextSettings.cpp
 JSImageData.cpp
+JSImageDataSettings.cpp
 JSImageSmoothingQuality.cpp
 JSInputEvent.cpp
 JSInspectorAuditAccessibilityObject.cpp

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (277568 => 277569)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2021-05-16 15:00:51 UTC (rev 277568)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2021-05-16 15:21:34 UTC (rev 277569)
@@ -4103,6 +4103,7 @@
 		BC96DB430F3A880E00573CB3 /* RenderBoxModelObject.h in Headers */ = {isa = PBXBuildFile; fileRef = BC96DB420F3A880E00573CB3 /* RenderBoxModelObject.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		BC97E23A109144950010D361 /* HTMLAllCollection.h in Headers */ = {isa = PBXBuildFile; fileRef = BC97E238109144950010D361 /* HTMLAllCollection.h */; };
 		BC97E413109154FA0010D361 /* JSHTMLAllCollection.h in Headers */ = {isa = PBXBuildFile; fileRef = BC97E411109154FA0010D361 /* JSHTMLAllCollection.h */; };
+		BCA088F5264E1C08003E2A6C /* ImageDataSettings.h in Headers */ = {isa = PBXBuildFile; fileRef = BCA088F2264E1BF9003E2A6C /* ImageDataSettings.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		BCA169A30BFD55B40019CA76 /* JSHTMLTableCaptionElement.h in Headers */ = {isa = PBXBuildFile; fileRef = BCA169A10BFD55B40019CA76 /* JSHTMLTableCaptionElement.h */; };
 		BCA257151293C010007A263D /* VerticalPositionCache.h in Headers */ = {isa = PBXBuildFile; fileRef = BCA257141293C010007A263D /* VerticalPositionCache.h */; };
 		BCA2B061105047600043BD1C /* UserScript.h in Headers */ = {isa = PBXBuildFile; fileRef = BCA2B0601050475F0043BD1C /* UserScript.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -14331,6 +14332,8 @@
 		BC9A6142146859D9006057FD /* EventNames.in */ = {isa = PBXFileReference; lastKnownFileType = text; path = EventNames.in; sourceTree = "<group>"; };
 		BC9A6145146859D9006057FD /* make_event_factory.pl */ = {isa = PBXFileReference; lastKnownFileType = text.script.perl; path = make_event_factory.pl; sourceTree = "<group>"; };
 		BC9A6146146859D9006057FD /* make_names.pl */ = {isa = PBXFileReference; lastKnownFileType = text.script.perl; path = make_names.pl; sourceTree = "<group>"; };
+		BCA088F2264E1BF9003E2A6C /* ImageDataSettings.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ImageDataSettings.h; sourceTree = "<group>"; };
+		BCA088F4264E1BF9003E2A6C /* ImageDataSettings.idl */ = {isa = PBXFileReference; lastKnownFileType = text; path = ImageDataSettings.idl; sourceTree = "<group>"; };
 		BCA169A00BFD55B40019CA76 /* JSHTMLTableCaptionElement.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = JSHTMLTableCaptionElement.cpp; sourceTree = "<group>"; };
 		BCA169A10BFD55B40019CA76 /* JSHTMLTableCaptionElement.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = JSHTMLTableCaptionElement.h; sourceTree = "<group>"; };
 		BCA257141293C010007A263D /* VerticalPositionCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VerticalPositionCache.h; sourceTree = "<group>"; };
@@ -23950,6 +23953,8 @@
 				A77979130D6B9D0C003851B9 /* ImageData.cpp */,
 				A77979140D6B9D0C003851B9 /* ImageData.h */,
 				A77979150D6B9D0C003851B9 /* ImageData.idl */,
+				BCA088F2264E1BF9003E2A6C /* ImageDataSettings.h */,
+				BCA088F4264E1BF9003E2A6C /* ImageDataSettings.idl */,
 				97205AB11239291000B17380 /* ImageDocument.cpp */,
 				97205AB21239291000B17380 /* ImageDocument.h */,
 				F55B3D8D1251F12D003EF269 /* ImageInputType.cpp */,
@@ -32915,6 +32920,7 @@
 				B2A10D910B3818BD00099AA4 /* ImageBufferPipe.h in Headers */,
 				CD3E21DD2183444A00E66F55 /* ImageBufferUtilitiesCG.h in Headers */,
 				A779791A0D6B9D0C003851B9 /* ImageData.h in Headers */,
+				BCA088F5264E1C08003E2A6C /* ImageDataSettings.h in Headers */,
 				CD19FEA81F573972000C42FB /* ImageDecoder.h in Headers */,
 				CD19FEAE1F574B6D000C42FB /* ImageDecoderAVFObjC.h in Headers */,
 				555B87ED1CAAF0AB00349425 /* ImageDecoderCG.h in Headers */,

Modified: trunk/Source/WebCore/bindings/js/SerializedScriptValue.cpp (277568 => 277569)


--- trunk/Source/WebCore/bindings/js/SerializedScriptValue.cpp	2021-05-16 15:00:51 UTC (rev 277568)
+++ trunk/Source/WebCore/bindings/js/SerializedScriptValue.cpp	2021-05-16 15:21:34 UTC (rev 277569)
@@ -3141,30 +3141,24 @@
             return JSValue();
         }
 
-        auto array = Uint8ClampedArray::tryCreate(WTFMove(arrayBuffer), 0, arrayBuffer->byteLength());
-        if (!array) {
-            fail();
-            return JSValue();
-        }
-
         IntSize logicalSize = IntSize(logicalWidth, logicalHeight);
         IntSize imageDataSize = logicalSize;
         imageDataSize.scale(resolutionScale);
 
-        // FIXME: Creating this ImageData is not necessary. We should skip right to creating a PixelBuffer directly.
-        auto imageData = ImageData::create(imageDataSize, array.releaseNonNull());
-        if (!imageData) {
+        auto buffer = ImageBitmap::createImageBuffer(*scriptExecutionContextFromExecState(m_lexicalGlobalObject), logicalSize, RenderingMode::Unaccelerated, resolutionScale);
+        if (!buffer) {
             fail();
             return JSValue();
         }
 
-        auto buffer = ImageBitmap::createImageBuffer(*scriptExecutionContextFromExecState(m_lexicalGlobalObject), logicalSize, RenderingMode::Unaccelerated, resolutionScale);
-        if (!buffer) {
+        PixelBufferFormat format { AlphaPremultiplication::Premultiplied, PixelFormat::RGBA8, DestinationColorSpace::SRGB };
+        auto pixelBuffer = PixelBuffer::tryCreate(format, imageDataSize, arrayBuffer.releaseNonNull());
+        if (!pixelBuffer) {
             fail();
             return JSValue();
         }
 
-        buffer->putPixelBuffer(imageData->pixelBuffer(), { IntPoint::zero(), logicalSize });
+        buffer->putPixelBuffer(WTFMove(*pixelBuffer), { IntPoint::zero(), logicalSize });
 
         auto bitmap = ImageBitmap::create(ImageBitmapBacking(WTFMove(buffer), OptionSet<SerializationState>::fromRaw(serializationState)));
         return getJSValue(bitmap);

Modified: trunk/Source/WebCore/html/ImageData.cpp (277568 => 277569)


--- trunk/Source/WebCore/html/ImageData.cpp	2021-05-16 15:00:51 UTC (rev 277568)
+++ trunk/Source/WebCore/html/ImageData.cpp	2021-05-16 15:21:34 UTC (rev 277569)
@@ -35,7 +35,7 @@
 
 namespace WebCore {
 
-Checked<unsigned, RecordOverflow> ImageData::dataSize(const IntSize& size)
+static Checked<unsigned, RecordOverflow> computeDataSize(const IntSize& size)
 {
     Checked<unsigned, RecordOverflow> checkedDataSize = 4;
     checkedDataSize *= static_cast<unsigned>(size.width());
@@ -43,9 +43,17 @@
     return checkedDataSize;
 }
 
+PredefinedColorSpace ImageData::computeColorSpace(Optional<ImageDataSettings> settings, PredefinedColorSpace defaultColorSpace)
+{
+    if (settings && settings->colorSpace)
+        return *settings->colorSpace;
+    return defaultColorSpace;
+}
+
 Ref<ImageData> ImageData::create(PixelBuffer&& pixelBuffer)
 {
-    return adoptRef(*new ImageData(WTFMove(pixelBuffer)));
+    auto colorSpace = toPredefinedColorSpace(pixelBuffer.format().colorSpace);
+    return adoptRef(*new ImageData(pixelBuffer.size(), pixelBuffer.takeData(), *colorSpace));
 }
 
 RefPtr<ImageData> ImageData::create(Optional<PixelBuffer>&& pixelBuffer)
@@ -52,38 +60,56 @@
 {
     if (!pixelBuffer)
         return nullptr;
-    return ImageData::create(WTFMove(*pixelBuffer));
+    return create(WTFMove(*pixelBuffer));
 }
 
 RefPtr<ImageData> ImageData::create(const IntSize& size)
 {
-    auto dataSize = ImageData::dataSize(size);
+    auto dataSize = computeDataSize(size);
     if (dataSize.hasOverflowed())
         return nullptr;
     auto byteArray = Uint8ClampedArray::tryCreateUninitialized(dataSize.unsafeGet());
     if (!byteArray)
         return nullptr;
-    
-    return adoptRef(*new ImageData({ { AlphaPremultiplication::Unpremultiplied, PixelFormat::RGBA8, DestinationColorSpace::SRGB }, size, byteArray.releaseNonNull() }));
+    return adoptRef(*new ImageData(size, byteArray.releaseNonNull(), PredefinedColorSpace::SRGB));
 }
 
-RefPtr<ImageData> ImageData::create(const IntSize& size, Ref<Uint8ClampedArray>&& byteArray)
+RefPtr<ImageData> ImageData::create(const IntSize& size, Ref<Uint8ClampedArray>&& byteArray, PredefinedColorSpace colorSpace)
 {
-    auto dataSize = ImageData::dataSize(size);
-    if (dataSize.hasOverflowed() || dataSize.unsafeGet() > byteArray->length())
+    auto dataSize = computeDataSize(size);
+    if (dataSize.hasOverflowed() || dataSize.unsafeGet() != byteArray->length())
         return nullptr;
 
-    return adoptRef(*new ImageData({ { AlphaPremultiplication::Unpremultiplied, PixelFormat::RGBA8, DestinationColorSpace::SRGB }, size, WTFMove(byteArray) }));
+    return adoptRef(*new ImageData(size, WTFMove(byteArray), colorSpace));
 }
 
-ExceptionOr<Ref<ImageData>> ImageData::create(unsigned sw, unsigned sh)
+ExceptionOr<Ref<ImageData>> ImageData::createUninitialized(unsigned rows, unsigned pixelsPerRow, PredefinedColorSpace defaultColorSpace, Optional<ImageDataSettings> settings)
 {
+    IntSize size(rows, pixelsPerRow);
+    auto dataSize = computeDataSize(size);
+    if (dataSize.hasOverflowed())
+        return Exception { RangeError, "Cannot allocate a buffer of this size"_s };
+
+    auto byteArray = Uint8ClampedArray::tryCreateUninitialized(dataSize.unsafeGet());
+    if (!byteArray) {
+        // FIXME: Does this need to be a "real" out of memory error with setOutOfMemoryError called on it?
+        return Exception { RangeError, "Out of memory"_s };
+    }
+
+    auto colorSpace = computeColorSpace(settings, defaultColorSpace);
+    return adoptRef(*new ImageData(size, byteArray.releaseNonNull(), colorSpace));
+}
+
+ExceptionOr<Ref<ImageData>> ImageData::create(unsigned sw, unsigned sh, Optional<ImageDataSettings> settings)
+{
     if (!sw || !sh)
         return Exception { IndexSizeError };
+
     IntSize size(sw, sh);
-    auto dataSize = ImageData::dataSize(size);
+    auto dataSize = computeDataSize(size);
     if (dataSize.hasOverflowed())
         return Exception { RangeError, "Cannot allocate a buffer of this size"_s };
+
     auto byteArray = Uint8ClampedArray::tryCreateUninitialized(dataSize.unsafeGet());
     if (!byteArray) {
         // FIXME: Does this need to be a "real" out of memory error with setOutOfMemoryError called on it?
@@ -90,10 +116,12 @@
         return Exception { RangeError, "Out of memory"_s };
     }
     byteArray->zeroFill();
-    return adoptRef(*new ImageData({ { AlphaPremultiplication::Unpremultiplied, PixelFormat::RGBA8, DestinationColorSpace::SRGB }, size, byteArray.releaseNonNull() }));
+
+    auto colorSpace = computeColorSpace(settings);
+    return adoptRef(*new ImageData(size, byteArray.releaseNonNull(), colorSpace));
 }
 
-ExceptionOr<Ref<ImageData>> ImageData::create(Ref<Uint8ClampedArray>&& byteArray, unsigned sw, Optional<unsigned> sh)
+ExceptionOr<Ref<ImageData>> ImageData::create(Ref<Uint8ClampedArray>&& byteArray, unsigned sw, Optional<unsigned> sh, Optional<ImageDataSettings> settings)
 {
     unsigned length = byteArray->length();
     if (!length || length % 4)
@@ -107,22 +135,28 @@
     if (sh && sh.value() != height)
         return Exception { IndexSizeError, "sh value is not equal to height"_s };
 
-    auto result = create(IntSize(sw, height), WTFMove(byteArray));
-    if (!result)
+    IntSize size(sw, height);
+    auto dataSize = computeDataSize(size);
+    if (dataSize.hasOverflowed() || dataSize.unsafeGet() != byteArray->length())
         return Exception { RangeError };
-    return result.releaseNonNull();
+
+    auto colorSpace = computeColorSpace(settings);
+    return adoptRef(*new ImageData(size, WTFMove(byteArray), colorSpace));
 }
 
-ImageData::ImageData(PixelBuffer&& pixelBuffer)
-    : m_pixelBuffer(WTFMove(pixelBuffer))
+ImageData::ImageData(const IntSize& size, Ref<JSC::Uint8ClampedArray>&& data, PredefinedColorSpace colorSpace)
+    : m_size(size)
+    , m_data(WTFMove(data))
+    , m_colorSpace(colorSpace)
 {
 }
 
 ImageData::~ImageData() = default;
 
-Ref<ImageData> ImageData::deepClone() const
+PixelBuffer ImageData::pixelBuffer() const
 {
-    return adoptRef(*new ImageData(m_pixelBuffer.deepClone()));
+    PixelBufferFormat format { AlphaPremultiplication::Unpremultiplied, PixelFormat::RGBA8, toDestinationColorSpace(m_colorSpace) };
+    return { format, m_size, m_data.get() };
 }
 
 TextStream& operator<<(TextStream& ts, const ImageData& imageData)

Modified: trunk/Source/WebCore/html/ImageData.h (277568 => 277569)


--- trunk/Source/WebCore/html/ImageData.h	2021-05-16 15:00:51 UTC (rev 277568)
+++ trunk/Source/WebCore/html/ImageData.h	2021-05-16 15:21:34 UTC (rev 277569)
@@ -29,7 +29,12 @@
 #pragma once
 
 #include "ExceptionOr.h"
+#include "ImageDataSettings.h"
+#include "IntSize.h"
 #include "PixelBuffer.h"
+#include "PredefinedColorSpace.h"
+#include <_javascript_Core/Uint8ClampedArray.h>
+#include <wtf/Forward.h>
 
 namespace WebCore {
 
@@ -38,29 +43,32 @@
     WEBCORE_EXPORT static Ref<ImageData> create(PixelBuffer&&);
     WEBCORE_EXPORT static RefPtr<ImageData> create(Optional<PixelBuffer>&&);
     WEBCORE_EXPORT static RefPtr<ImageData> create(const IntSize&);
-    WEBCORE_EXPORT static RefPtr<ImageData> create(const IntSize&, Ref<Uint8ClampedArray>&&);
-    WEBCORE_EXPORT static ExceptionOr<Ref<ImageData>> create(unsigned sw, unsigned sh);
-    WEBCORE_EXPORT static ExceptionOr<Ref<ImageData>> create(Ref<Uint8ClampedArray>&&, unsigned sw, Optional<unsigned> sh);
+    WEBCORE_EXPORT static RefPtr<ImageData> create(const IntSize&, Ref<Uint8ClampedArray>&&, PredefinedColorSpace);
+    WEBCORE_EXPORT static ExceptionOr<Ref<ImageData>> createUninitialized(unsigned rows, unsigned pixelsPerRow, PredefinedColorSpace defaultColorSpace, Optional<ImageDataSettings> = WTF::nullopt);
+    WEBCORE_EXPORT static ExceptionOr<Ref<ImageData>> create(unsigned sw, unsigned sh, Optional<ImageDataSettings>);
+    WEBCORE_EXPORT static ExceptionOr<Ref<ImageData>> create(Ref<Uint8ClampedArray>&&, unsigned sw, Optional<unsigned> sh, Optional<ImageDataSettings>);
+
     WEBCORE_EXPORT ~ImageData();
 
-    const IntSize& size() const { return m_pixelBuffer.size(); }
-    int width() const { return m_pixelBuffer.size().width(); }
-    int height() const { return m_pixelBuffer.size().height(); }
+    static PredefinedColorSpace computeColorSpace(Optional<ImageDataSettings>, PredefinedColorSpace defaultColorSpace = PredefinedColorSpace::SRGB);
 
-    Uint8ClampedArray& data() const { return m_pixelBuffer.data(); }
+    const IntSize& size() const { return m_size; }
 
-    Ref<ImageData> deepClone() const;
+    int width() const { return m_size.width(); }
+    int height() const { return m_size.height(); }
+    Uint8ClampedArray& data() const { return m_data.get(); }
+    PredefinedColorSpace colorSpace() const { return m_colorSpace; }
 
-    const PixelBuffer& pixelBuffer() const { return m_pixelBuffer; }
+    PixelBuffer pixelBuffer() const;
 
 private:
-    explicit ImageData(PixelBuffer&&);
+    explicit ImageData(const IntSize&, Ref<JSC::Uint8ClampedArray>&&, PredefinedColorSpace);
 
-    static Checked<unsigned, RecordOverflow> dataSize(const IntSize&);
-
-    PixelBuffer m_pixelBuffer;
+    IntSize m_size;
+    Ref<JSC::Uint8ClampedArray> m_data;
+    PredefinedColorSpace m_colorSpace;
 };
 
-WEBCORE_EXPORT WTF::TextStream& operator<<(WTF::TextStream&, const ImageData&);
+WEBCORE_EXPORT TextStream& operator<<(TextStream&, const ImageData&);
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/html/ImageData.idl (277568 => 277569)


--- trunk/Source/WebCore/html/ImageData.idl	2021-05-16 15:00:51 UTC (rev 277568)
+++ trunk/Source/WebCore/html/ImageData.idl	2021-05-16 15:21:34 UTC (rev 277569)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008-2009, 2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2008-2021 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -32,10 +32,11 @@
     Exposed=(Window,Worker),
     ImplementationLacksVTable
 ] interface ImageData {
-    constructor(unsigned long sw, unsigned long sh);
-    constructor(Uint8ClampedArray data, unsigned long sw, optional unsigned long sh);
+    constructor(unsigned long sw, unsigned long sh, optional ImageDataSettings settings);
+    constructor(Uint8ClampedArray data, unsigned long sw, optional unsigned long sh, optional ImageDataSettings settings);
 
     readonly attribute unsigned long width;
     readonly attribute unsigned long height;
     readonly attribute Uint8ClampedArray data;
+    [EnabledBySetting=CanvasColorSpace] readonly attribute PredefinedColorSpace colorSpace;
 };

Copied: trunk/Source/WebCore/html/ImageDataSettings.h (from rev 277568, trunk/Source/WebCore/html/canvas/PredefinedColorSpace.cpp) (0 => 277569)


--- trunk/Source/WebCore/html/ImageDataSettings.h	                        (rev 0)
+++ trunk/Source/WebCore/html/ImageDataSettings.h	2021-05-16 15:21:34 UTC (rev 277569)
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2021 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "PredefinedColorSpace.h"
+#include <wtf/Optional.h>
+
+namespace WebCore {
+
+struct ImageDataSettings {
+    Optional<PredefinedColorSpace> colorSpace;
+};
+
+} // namespace WebCore

Copied: trunk/Source/WebCore/html/ImageDataSettings.idl (from rev 277568, trunk/Source/WebCore/html/canvas/PredefinedColorSpace.cpp) (0 => 277569)


--- trunk/Source/WebCore/html/ImageDataSettings.idl	                        (rev 0)
+++ trunk/Source/WebCore/html/ImageDataSettings.idl	2021-05-16 15:21:34 UTC (rev 277569)
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2021 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// https://html.spec.whatwg.org/multipage/canvas.html#imagedatasettings
+dictionary ImageDataSettings {
+    [EnabledBySetting=CanvasColorSpace] PredefinedColorSpace colorSpace;
+};

Modified: trunk/Source/WebCore/html/canvas/CanvasImageData.idl (277568 => 277569)


--- trunk/Source/WebCore/html/canvas/CanvasImageData.idl	2021-05-16 15:00:51 UTC (rev 277568)
+++ trunk/Source/WebCore/html/canvas/CanvasImageData.idl	2021-05-16 15:21:34 UTC (rev 277569)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2017-2021 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -26,9 +26,9 @@
 // https://html.spec.whatwg.org/multipage/canvas.html#canvasimagedata
 interface mixin CanvasImageData {
     // pixel manipulation
-    ImageData createImageData([EnforceRange] long sw, [EnforceRange] long sh);
+    ImageData createImageData([EnforceRange] long sw, [EnforceRange] long sh, optional ImageDataSettings settings);
     ImageData createImageData(ImageData imagedata);
-    ImageData getImageData([EnforceRange] long sx, [EnforceRange] long sy, [EnforceRange] long sw, [EnforceRange] long sh);
+    ImageData getImageData([EnforceRange] long sx, [EnforceRange] long sy, [EnforceRange] long sw, [EnforceRange] long sh, optional ImageDataSettings settings);
     undefined putImageData(ImageData imagedata, [EnforceRange] long dx, [EnforceRange] long dy);
     undefined putImageData(ImageData imagedata, [EnforceRange] long dx, [EnforceRange] long dy, [EnforceRange] long dirtyX, [EnforceRange] long dirtyY, [EnforceRange] long dirtyWidth, [EnforceRange] long dirtyHeight);
 };

Modified: trunk/Source/WebCore/html/canvas/CanvasRenderingContext2DBase.cpp (277568 => 277569)


--- trunk/Source/WebCore/html/canvas/CanvasRenderingContext2DBase.cpp	2021-05-16 15:00:51 UTC (rev 277568)
+++ trunk/Source/WebCore/html/canvas/CanvasRenderingContext2DBase.cpp	2021-05-16 15:21:34 UTC (rev 277569)
@@ -2160,30 +2160,35 @@
     return false;
 }
 
-static RefPtr<ImageData> createEmptyImageData(const IntSize& size)
+static void initializeEmptyImageData(const ImageData& imageData)
 {
-    auto data = ""
-    if (data)
-        data->data().zeroFill();
-    return data;
+    imageData.data().zeroFill();
 }
 
-RefPtr<ImageData> CanvasRenderingContext2DBase::createImageData(ImageData& imageData) const
+ExceptionOr<Ref<ImageData>> CanvasRenderingContext2DBase::createImageData(ImageData& existingImageData) const
 {
-    return createEmptyImageData(imageData.size());
+    auto newImageData = ImageData::createUninitialized(existingImageData.width(), existingImageData.height(), existingImageData.colorSpace());
+    if (!newImageData.hasException())
+        initializeEmptyImageData(newImageData.returnValue());
+    return newImageData;
 }
 
-ExceptionOr<RefPtr<ImageData>> CanvasRenderingContext2DBase::createImageData(int sw, int sh) const
+ExceptionOr<Ref<ImageData>> CanvasRenderingContext2DBase::createImageData(int sw, int sh, Optional<ImageDataSettings> settings) const
 {
     if (!sw || !sh)
         return Exception { IndexSizeError };
 
-    IntSize size { std::abs(sw), std::abs(sh) };
-    return createEmptyImageData(size);
+    auto imageData = ImageData::createUninitialized(std::abs(sw), std::abs(sh), m_settings.colorSpace, settings);
+    if (!imageData.hasException())
+        initializeEmptyImageData(imageData.returnValue());
+    return imageData;
 }
 
-ExceptionOr<RefPtr<ImageData>> CanvasRenderingContext2DBase::getImageData(int sx, int sy, int sw, int sh) const
+ExceptionOr<Ref<ImageData>> CanvasRenderingContext2DBase::getImageData(int sx, int sy, int sw, int sh, Optional<ImageDataSettings> settings) const
 {
+    if (!sw || !sh)
+        return Exception { IndexSizeError };
+
     if (!canvasBase().originClean()) {
         static NeverDestroyed<String> consoleMessage(MAKE_STATIC_STRING_IMPL("Unable to get image data from canvas because the canvas has been tainted by cross-origin data."));
         canvasBase().scriptExecutionContext()->addConsoleMessage(MessageSource::Security, MessageLevel::Error, consoleMessage);
@@ -2190,9 +2195,6 @@
         return Exception { SecurityError };
     }
 
-    if (!sw || !sh)
-        return Exception { IndexSizeError };
-
     if (sw < 0) {
         sx += sw;
         sw = -sw;
@@ -2205,10 +2207,16 @@
     IntRect imageDataRect { sx, sy, sw, sh };
 
     ImageBuffer* buffer = canvasBase().buffer();
-    if (!buffer)
-        return createEmptyImageData(imageDataRect.size());
+    if (!buffer) {
+        auto imageData = ImageData::createUninitialized(imageDataRect.width(), imageDataRect.height(), m_settings.colorSpace, settings);
+        if (!imageData.hasException())
+            initializeEmptyImageData(imageData.returnValue());
+        return imageData;
+    }
 
-    PixelBufferFormat format { AlphaPremultiplication::Unpremultiplied, PixelFormat::RGBA8, DestinationColorSpace::SRGB };
+    auto computedColorSpace = ImageData::computeColorSpace(settings, m_settings.colorSpace);
+
+    PixelBufferFormat format { AlphaPremultiplication::Unpremultiplied, PixelFormat::RGBA8, toDestinationColorSpace(computedColorSpace) };
     auto pixelBuffer = buffer->getPixelBuffer(format, imageDataRect);
     if (!pixelBuffer) {
         canvasBase().scriptExecutionContext()->addConsoleMessage(MessageSource::Rendering, MessageLevel::Error,
@@ -2216,6 +2224,8 @@
         return Exception { InvalidStateError };
     }
 
+    ASSERT(pixelBuffer->format().colorSpace == toDestinationColorSpace(computedColorSpace));
+
     return { { ImageData::create(WTFMove(*pixelBuffer)) } };
 }
 

Modified: trunk/Source/WebCore/html/canvas/CanvasRenderingContext2DBase.h (277568 => 277569)


--- trunk/Source/WebCore/html/canvas/CanvasRenderingContext2DBase.h	2021-05-16 15:00:51 UTC (rev 277568)
+++ trunk/Source/WebCore/html/canvas/CanvasRenderingContext2DBase.h	2021-05-16 15:21:34 UTC (rev 277569)
@@ -43,6 +43,7 @@
 #include "GraphicsContext.h"
 #include "GraphicsTypes.h"
 #include "ImageBuffer.h"
+#include "ImageDataSettings.h"
 #include "ImageSmoothingQuality.h"
 #include "Path.h"
 #include "PlatformLayer.h"
@@ -192,9 +193,9 @@
     ExceptionOr<Ref<CanvasGradient>> createConicGradient(float angleInRadians, float x, float y);
     ExceptionOr<RefPtr<CanvasPattern>> createPattern(CanvasImageSource&&, const String& repetition);
 
-    RefPtr<ImageData> createImageData(ImageData&) const;
-    ExceptionOr<RefPtr<ImageData>> createImageData(int width, int height) const;
-    ExceptionOr<RefPtr<ImageData>> getImageData(int sx, int sy, int sw, int sh) const;
+    ExceptionOr<Ref<ImageData>> createImageData(ImageData&) const;
+    ExceptionOr<Ref<ImageData>> createImageData(int width, int height, Optional<ImageDataSettings>) const;
+    ExceptionOr<Ref<ImageData>> getImageData(int sx, int sy, int sw, int sh, Optional<ImageDataSettings>) const;
     void putImageData(ImageData&, int dx, int dy);
     void putImageData(ImageData&, int dx, int dy, int dirtyX, int dirtyY, int dirtyWidth, int dirtyHeight);
 

Modified: trunk/Source/WebCore/html/canvas/PredefinedColorSpace.cpp (277568 => 277569)


--- trunk/Source/WebCore/html/canvas/PredefinedColorSpace.cpp	2021-05-16 15:00:51 UTC (rev 277568)
+++ trunk/Source/WebCore/html/canvas/PredefinedColorSpace.cpp	2021-05-16 15:21:34 UTC (rev 277569)
@@ -27,6 +27,7 @@
 #include "PredefinedColorSpace.h"
 
 #include "ColorSpace.h"
+#include <wtf/Optional.h>
 
 namespace WebCore {
 
@@ -45,4 +46,23 @@
     return DestinationColorSpace::SRGB;
 }
 
+Optional<PredefinedColorSpace> toPredefinedColorSpace(DestinationColorSpace colorSpace)
+{
+    switch (colorSpace) {
+    case DestinationColorSpace::SRGB:
+        return PredefinedColorSpace::SRGB;
+#if ENABLE(DESTINATION_COLOR_SPACE_LINEAR_SRGB)
+    case DestinationColorSpace::LinearSRGB:
+        return WTF::nullopt;
+#endif
+#if ENABLE(DESTINATION_COLOR_SPACE_DISPLAY_P3)
+    case DestinationColorSpace::DisplayP3:
+        return PredefinedColorSpace::DisplayP3;
+#endif
+    }
+
+    ASSERT_NOT_REACHED();
+    return WTF::nullopt;
 }
+
+}

Modified: trunk/Source/WebCore/html/canvas/PredefinedColorSpace.h (277568 => 277569)


--- trunk/Source/WebCore/html/canvas/PredefinedColorSpace.h	2021-05-16 15:00:51 UTC (rev 277568)
+++ trunk/Source/WebCore/html/canvas/PredefinedColorSpace.h	2021-05-16 15:21:34 UTC (rev 277569)
@@ -26,6 +26,7 @@
 #pragma once
 
 #include <wtf/EnumTraits.h>
+#include <wtf/Forward.h>
 
 namespace WebCore {
 
@@ -39,6 +40,7 @@
 };
 
 DestinationColorSpace toDestinationColorSpace(PredefinedColorSpace);
+Optional<PredefinedColorSpace> toPredefinedColorSpace(DestinationColorSpace);
 
 }
 

Modified: trunk/Source/WebCore/inspector/InspectorCanvas.cpp (277568 => 277569)


--- trunk/Source/WebCore/inspector/InspectorCanvas.cpp	2021-05-16 15:00:51 UTC (rev 277568)
+++ trunk/Source/WebCore/inspector/InspectorCanvas.cpp	2021-05-16 15:21:34 UTC (rev 277569)
@@ -428,6 +428,12 @@
     return {{ valueIndexForData(argument), RecordingSwizzleType::ImageData }};
 }
 
+Optional<InspectorCanvasCallTracer::ProcessedArgument> InspectorCanvas::processArgument(ImageDataSettings&)
+{
+    // FIXME: Implement.
+    return WTF::nullopt;
+}
+
 Optional<InspectorCanvasCallTracer::ProcessedArgument> InspectorCanvas::processArgument(ImageSmoothingQuality argument)
 {
     return {{ valueIndexForData(convertEnumerationToString(argument)), RecordingSwizzleType::String }};

Modified: trunk/Source/WebCore/inspector/InspectorCanvasCallTracer.cpp (277568 => 277569)


--- trunk/Source/WebCore/inspector/InspectorCanvasCallTracer.cpp	2021-05-16 15:00:51 UTC (rev 277568)
+++ trunk/Source/WebCore/inspector/InspectorCanvasCallTracer.cpp	2021-05-16 15:21:34 UTC (rev 277569)
@@ -37,6 +37,7 @@
 #include "HTMLImageElement.h"
 #include "HTMLVideoElement.h"
 #include "ImageData.h"
+#include "ImageDataSettings.h"
 #include "InspectorCanvasAgent.h"
 #include "InspectorInstrumentation.h"
 #include "InstrumentingAgents.h"

Modified: trunk/Source/WebCore/inspector/InspectorCanvasCallTracer.h (277568 => 277569)


--- trunk/Source/WebCore/inspector/InspectorCanvasCallTracer.h	2021-05-16 15:00:51 UTC (rev 277568)
+++ trunk/Source/WebCore/inspector/InspectorCanvasCallTracer.h	2021-05-16 15:21:34 UTC (rev 277569)
@@ -70,6 +70,7 @@
 class WebGLUniformLocation;
 class WebGLVertexArrayObject;
 struct DOMMatrix2DInit;
+struct ImageDataSettings;
 enum class RecordingSwizzleType : int;
 enum class CanvasDirection;
 enum class CanvasFillRule;
@@ -150,6 +151,7 @@
     macro(HTMLImageElement*) \
     macro(ImageBitmap*) \
     macro(ImageData*) \
+    macro(ImageDataSettings&) \
     macro(ImageSmoothingQuality) \
     macro(Optional<float>&) \
     macro(Path2D*) \

Modified: trunk/Source/WebCore/platform/graphics/ImageBufferBackend.cpp (277568 => 277569)


--- trunk/Source/WebCore/platform/graphics/ImageBufferBackend.cpp	2021-05-16 15:00:51 UTC (rev 277568)
+++ trunk/Source/WebCore/platform/graphics/ImageBufferBackend.cpp	2021-05-16 15:21:34 UTC (rev 277569)
@@ -116,6 +116,8 @@
 
 Optional<PixelBuffer> ImageBufferBackend::getPixelBuffer(const PixelBufferFormat& destinationFormat, const IntRect& sourceRect, void* data) const
 {
+    ASSERT(PixelBuffer::supportedPixelFormat(destinationFormat.pixelFormat));
+
     auto sourceRectScaled = toBackendCoordinates(sourceRect);
 
     auto pixelBuffer = PixelBuffer::tryCreate(destinationFormat, sourceRectScaled.size());
@@ -122,8 +124,8 @@
     if (!pixelBuffer)
         return WTF::nullopt;
 
-    IntRect sourceRectClipped = intersection(backendRect(), sourceRectScaled);
-    IntRect destinationRect = { IntPoint::zero(), sourceRectClipped.size() };
+    auto sourceRectClipped = intersection(backendRect(), sourceRectScaled);
+    IntRect destinationRect { IntPoint::zero(), sourceRectClipped.size() };
 
     if (sourceRectScaled.x() < 0)
         destinationRect.setX(-sourceRectScaled.x());
@@ -134,23 +136,15 @@
     if (destinationRect.size() != sourceRectScaled.size())
         pixelBuffer->data().zeroFill();
 
-    unsigned sourceBytesPerRow = bytesPerRow();
-    const uint8_t* sourceRows = reinterpret_cast<uint8_t*>(data) + sourceRectClipped.y() * sourceBytesPerRow + sourceRectClipped.x() * 4;
-
-    unsigned destinationBytesPerRow = 4 * sourceRectScaled.width();
-    uint8_t* destinationRows = pixelBuffer->data().data() + destinationRect.y() * destinationBytesPerRow + destinationRect.x() * 4;
-
-    PixelBufferFormat sourceFormat { AlphaPremultiplication::Premultiplied, pixelFormat(), DestinationColorSpace::SRGB };
-
     ConstPixelBufferConversionView source;
-    source.format = sourceFormat;
-    source.bytesPerRow = sourceBytesPerRow;
-    source.rows = sourceRows;
+    source.format = { AlphaPremultiplication::Premultiplied, pixelFormat(), colorSpace() };
+    source.bytesPerRow = bytesPerRow();
+    source.rows = reinterpret_cast<uint8_t*>(data) + sourceRectClipped.y() * source.bytesPerRow + sourceRectClipped.x() * 4;
     
     PixelBufferConversionView destination;
     destination.format = destinationFormat;
-    destination.bytesPerRow = destinationBytesPerRow;
-    destination.rows = destinationRows;
+    destination.bytesPerRow = 4 * sourceRectScaled.width();
+    destination.rows = pixelBuffer->data().data() + destinationRect.y() * destination.bytesPerRow + destinationRect.x() * 4;
 
     convertImagePixels(source, destination, destinationRect.size());
 
@@ -159,14 +153,11 @@
 
 void ImageBufferBackend::putPixelBuffer(const PixelBuffer& sourcePixelBuffer, const IntRect& sourceRect, const IntPoint& destinationPoint, AlphaPremultiplication destinationAlphaFormat, void* data)
 {
-    // FIXME: Add support for non-RGBA8 pixel formats.
-    ASSERT(sourcePixelBuffer.format().pixelFormat == PixelFormat::RGBA8);
-
     auto sourceRectScaled = toBackendCoordinates(sourceRect);
     auto destinationPointScaled = toBackendCoordinates(destinationPoint);
 
-    IntRect sourceRectClipped = intersection({ IntPoint::zero(), sourcePixelBuffer.size() }, sourceRectScaled);
-    IntRect destinationRect = sourceRectClipped;
+    auto sourceRectClipped = intersection({ IntPoint::zero(), sourcePixelBuffer.size() }, sourceRectScaled);
+    auto destinationRect = sourceRectClipped;
     destinationRect.moveBy(destinationPointScaled);
 
     if (sourceRectScaled.x() < 0)
@@ -178,24 +169,15 @@
     destinationRect.intersect(backendRect());
     sourceRectClipped.setSize(destinationRect.size());
 
-    unsigned sourceBytesPerRow = 4 * sourcePixelBuffer.size().width();
-    const uint8_t* sourceRows = sourcePixelBuffer.data().data() + sourceRectClipped.y() * sourceBytesPerRow + sourceRectClipped.x() * 4;
+    ConstPixelBufferConversionView source;
+    source.format = sourcePixelBuffer.format();
+    source.bytesPerRow = 4 * sourcePixelBuffer.size().width();
+    source.rows = sourcePixelBuffer.data().data() + sourceRectClipped.y() * source.bytesPerRow + sourceRectClipped.x() * 4;
 
-    unsigned destinationBytesPerRow = bytesPerRow();
-    uint8_t* destinationRows = reinterpret_cast<uint8_t*>(data) + destinationRect.y() * destinationBytesPerRow + destinationRect.x() * 4;
-
-    PixelBufferFormat sourceFormat = sourcePixelBuffer.format();
-    PixelBufferFormat destinationFormat { destinationAlphaFormat, pixelFormat(), DestinationColorSpace::SRGB };
-
-    ConstPixelBufferConversionView source;
-    source.format = sourceFormat;
-    source.bytesPerRow = sourceBytesPerRow;
-    source.rows = sourceRows;
-    
     PixelBufferConversionView destination;
-    destination.format = destinationFormat;
-    destination.bytesPerRow = destinationBytesPerRow;
-    destination.rows = destinationRows;
+    destination.format = { destinationAlphaFormat, pixelFormat(), colorSpace() };
+    destination.bytesPerRow = bytesPerRow();
+    destination.rows = reinterpret_cast<uint8_t*>(data) + destinationRect.y() * destination.bytesPerRow + destinationRect.x() * 4;
 
     convertImagePixels(source, destination, destinationRect.size());
 }

Modified: trunk/Source/WebCore/platform/graphics/PixelBuffer.cpp (277568 => 277569)


--- trunk/Source/WebCore/platform/graphics/PixelBuffer.cpp	2021-05-16 15:00:51 UTC (rev 277568)
+++ trunk/Source/WebCore/platform/graphics/PixelBuffer.cpp	2021-05-16 15:21:34 UTC (rev 277569)
@@ -31,10 +31,22 @@
 
 namespace WebCore {
 
+bool PixelBuffer::supportedPixelFormat(PixelFormat pixelFormat)
+{
+    switch (pixelFormat) {
+    case PixelFormat::RGBA8:
+    case PixelFormat::BGRA8:
+        return true;
+
+    case PixelFormat::RGB10:
+    case PixelFormat::RGB10A8:
+        return false;
+    }
+}
+
 Checked<unsigned, RecordOverflow> PixelBuffer::computeBufferSize(const PixelBufferFormat& format, const IntSize& size)
 {
-    // NOTE: Only 8-bit formats are currently supported.
-    ASSERT_UNUSED(format, format.pixelFormat == PixelFormat::RGBA8 || format.pixelFormat == PixelFormat::BGRA8);
+    ASSERT_UNUSED(format, supportedPixelFormat(format.pixelFormat));
 
     constexpr unsigned bytesPerPixel = 4;
 
@@ -43,7 +55,7 @@
 
 Optional<PixelBuffer> PixelBuffer::tryCreateForDecoding(const PixelBufferFormat& format, const IntSize& size, unsigned dataByteLength)
 {
-    ASSERT(format.pixelFormat == PixelFormat::RGBA8 || format.pixelFormat == PixelFormat::BGRA8);
+    ASSERT(supportedPixelFormat(format.pixelFormat));
     ASSERT(computeBufferSize(format, size).unsafeGet() == dataByteLength);
 
     auto pixelArray = Uint8ClampedArray::tryCreateUninitialized(dataByteLength);
@@ -54,8 +66,7 @@
 
 Optional<PixelBuffer> PixelBuffer::tryCreate(const PixelBufferFormat& format, const IntSize& size)
 {
-    // NOTE: Only 8-bit formats are currently supported.
-    ASSERT(format.pixelFormat == PixelFormat::RGBA8 || format.pixelFormat == PixelFormat::BGRA8);
+    ASSERT(supportedPixelFormat(format.pixelFormat));
 
     auto bufferSize = computeBufferSize(format, size);
     if (bufferSize.hasOverflowed())
@@ -66,6 +77,21 @@
     return { { format, size, pixelArray.releaseNonNull() } };
 }
 
+Optional<PixelBuffer> PixelBuffer::tryCreate(const PixelBufferFormat& format, const IntSize& size, Ref<JSC::ArrayBuffer>&& arrayBuffer)
+{
+    ASSERT(supportedPixelFormat(format.pixelFormat));
+
+    auto bufferSize = computeBufferSize(format, size);
+    if (bufferSize.hasOverflowed())
+        return WTF::nullopt;
+    if (bufferSize.unsafeGet() != arrayBuffer->byteLength())
+        return WTF::nullopt;
+    auto pixelArray = Uint8ClampedArray::tryCreate(WTFMove(arrayBuffer), 0, bufferSize.unsafeGet());
+    if (!pixelArray)
+        return WTF::nullopt;
+    return { { format, size, pixelArray.releaseNonNull() } };
+}
+
 PixelBuffer::PixelBuffer(const PixelBufferFormat& format, const IntSize& size, Ref<JSC::Uint8ClampedArray>&& data)
     : m_format { format }
     , m_size { size }
@@ -74,6 +100,14 @@
     RELEASE_ASSERT_WITH_SECURITY_IMPLICATION((m_size.area() * 4).unsafeGet() <= m_data->length());
 }
 
+PixelBuffer::PixelBuffer(const PixelBufferFormat& format, const IntSize& size, JSC::Uint8ClampedArray& data)
+    : m_format { format }
+    , m_size { size }
+    , m_data { data }
+{
+    RELEASE_ASSERT_WITH_SECURITY_IMPLICATION((m_size.area() * 4).unsafeGet() <= m_data->length());
+}
+
 PixelBuffer::~PixelBuffer() = default;
 
 PixelBuffer PixelBuffer::deepClone() const

Modified: trunk/Source/WebCore/platform/graphics/PixelBuffer.h (277568 => 277569)


--- trunk/Source/WebCore/platform/graphics/PixelBuffer.h	2021-05-16 15:00:51 UTC (rev 277568)
+++ trunk/Source/WebCore/platform/graphics/PixelBuffer.h	2021-05-16 15:21:34 UTC (rev 277569)
@@ -41,9 +41,13 @@
 class PixelBuffer {
     WTF_MAKE_NONCOPYABLE(PixelBuffer);
 public:
+    static bool supportedPixelFormat(PixelFormat);
+
     WEBCORE_EXPORT static Optional<PixelBuffer> tryCreate(const PixelBufferFormat&, const IntSize&);
+    WEBCORE_EXPORT static Optional<PixelBuffer> tryCreate(const PixelBufferFormat&, const IntSize&, Ref<JSC::ArrayBuffer>&&);
 
     PixelBuffer(const PixelBufferFormat&, const IntSize&, Ref<JSC::Uint8ClampedArray>&&);
+    PixelBuffer(const PixelBufferFormat&, const IntSize&, JSC::Uint8ClampedArray&);
     WEBCORE_EXPORT ~PixelBuffer();
 
     PixelBuffer(PixelBuffer&&) = default;
@@ -53,6 +57,8 @@
     const IntSize& size() const { return m_size; }
     JSC::Uint8ClampedArray& data() const { return m_data.get(); }
 
+    Ref<JSC::Uint8ClampedArray>&& takeData() { return WTFMove(m_data); }
+
     PixelBuffer deepClone() const;
 
     template<class Encoder> void encode(Encoder&) const;

Modified: trunk/Source/WebCore/platform/graphics/PixelBufferConversion.cpp (277568 => 277569)


--- trunk/Source/WebCore/platform/graphics/PixelBufferConversion.cpp	2021-05-16 15:00:51 UTC (rev 277568)
+++ trunk/Source/WebCore/platform/graphics/PixelBufferConversion.cpp	2021-05-16 15:21:34 UTC (rev 277569)
@@ -106,7 +106,7 @@
 
         vImage_Error converterCreateError = kvImageNoError;
         auto converter = adoptCF(vImageConverter_CreateWithCGImageFormat(&sourceCGImageFormat, &destinationCGImageFormat, nullptr, kvImageNoFlags, &converterCreateError));
-        ASSERT_WITH_MESSAGE_UNUSED(converterCreateError, converterCreateError != kvImageNoError, "vImageConverter creation failed with error: %zd", converterCreateError);
+        ASSERT_WITH_MESSAGE_UNUSED(converterCreateError, converterCreateError == kvImageNoError, "vImageConverter creation failed with error: %zd", converterCreateError);
 
         vImage_Error converterConvertError = vImageConvert_AnyToAny(converter.get(), &sourceVImageBuffer, &destinationVImageBuffer, nullptr, kvImageNoFlags);
         ASSERT_WITH_MESSAGE_UNUSED(converterConvertError, converterConvertError == kvImageNoError, "vImageConvert_AnyToAny failed conversion with error: %zd", converterConvertError);

Modified: trunk/Source/WebCore/platform/graphics/filters/FilterEffect.cpp (277568 => 277569)


--- trunk/Source/WebCore/platform/graphics/filters/FilterEffect.cpp	2021-05-16 15:00:51 UTC (rev 277568)
+++ trunk/Source/WebCore/platform/graphics/filters/FilterEffect.cpp	2021-05-16 15:21:34 UTC (rev 277569)
@@ -468,7 +468,7 @@
     // Color space conversion happens internally when drawing from one image buffer to another
     convertedBuffer->context().drawImageBuffer(inputBuffer, rect);
     
-    PixelBufferFormat format { outputAlphaFormat, PixelFormat::RGBA8, DestinationColorSpace::SRGB };
+    PixelBufferFormat format { outputAlphaFormat, PixelFormat::RGBA8, targetColorSpace };
     return convertedBuffer->getPixelBuffer(format, rect);
 }
 
@@ -504,7 +504,9 @@
                 copyConvertedImageBufferToDestination(destination, *colorSpace, AlphaPremultiplication::Unpremultiplied, rect);
                 return;
             }
-            PixelBufferFormat format { AlphaPremultiplication::Unpremultiplied, PixelFormat::RGBA8, DestinationColorSpace::SRGB };
+
+            ASSERT(m_imageBufferResult->colorSpace() == m_resultColorSpace);
+            PixelBufferFormat format { AlphaPremultiplication::Unpremultiplied, PixelFormat::RGBA8, m_resultColorSpace };
             m_unmultipliedImageResult = m_imageBufferResult->getPixelBuffer(format, { IntPoint(), m_absolutePaintRect.size() });
             if (!m_unmultipliedImageResult)
                 return;
@@ -512,7 +514,9 @@
             IntSize inputSize(m_absolutePaintRect.size());
             ASSERT(!ImageBuffer::sizeNeedsClamping(inputSize));
             inputSize.scale(m_filter.filterScale());
-            PixelBufferFormat format { AlphaPremultiplication::Unpremultiplied, PixelFormat::RGBA8, DestinationColorSpace::SRGB };
+            
+            ASSERT(m_premultipliedImageResult->format().colorSpace == m_resultColorSpace);
+            PixelBufferFormat format { AlphaPremultiplication::Unpremultiplied, PixelFormat::RGBA8, m_resultColorSpace };
             m_unmultipliedImageResult = PixelBuffer::tryCreate(format, inputSize);
             if (!m_unmultipliedImageResult)
                 return;
@@ -539,7 +543,9 @@
                 copyConvertedImageBufferToDestination(destination, *colorSpace, AlphaPremultiplication::Premultiplied, rect);
                 return;
             }
-            PixelBufferFormat format { AlphaPremultiplication::Premultiplied, PixelFormat::RGBA8, DestinationColorSpace::SRGB };
+
+            ASSERT(m_imageBufferResult->colorSpace() == m_resultColorSpace);
+            PixelBufferFormat format { AlphaPremultiplication::Premultiplied, PixelFormat::RGBA8, m_resultColorSpace };
             m_premultipliedImageResult = m_imageBufferResult->getPixelBuffer(format, { IntPoint(), m_absolutePaintRect.size() });
             if (!m_premultipliedImageResult)
                 return;
@@ -547,7 +553,9 @@
             IntSize inputSize(m_absolutePaintRect.size());
             ASSERT(!ImageBuffer::sizeNeedsClamping(inputSize));
             inputSize.scale(m_filter.filterScale());
-            PixelBufferFormat format { AlphaPremultiplication::Premultiplied, PixelFormat::RGBA8, DestinationColorSpace::SRGB };
+
+            ASSERT(m_unmultipliedImageResult->format().colorSpace == m_resultColorSpace);
+            PixelBufferFormat format { AlphaPremultiplication::Premultiplied, PixelFormat::RGBA8, m_resultColorSpace };
             m_premultipliedImageResult = PixelBuffer::tryCreate(format, inputSize);
             if (!m_premultipliedImageResult)
                 return;
@@ -590,7 +598,7 @@
     IntSize resultSize(m_absolutePaintRect.size());
     ASSERT(!ImageBuffer::sizeNeedsClamping(resultSize));
     resultSize.scale(m_filter.filterScale());
-    PixelBufferFormat format { AlphaPremultiplication::Unpremultiplied, PixelFormat::RGBA8, DestinationColorSpace::SRGB };
+    PixelBufferFormat format { AlphaPremultiplication::Unpremultiplied, PixelFormat::RGBA8, m_resultColorSpace };
     m_unmultipliedImageResult = PixelBuffer::tryCreate(format, resultSize);
     return m_unmultipliedImageResult;
 }
@@ -609,7 +617,7 @@
     IntSize resultSize(m_absolutePaintRect.size());
     ASSERT(!ImageBuffer::sizeNeedsClamping(resultSize));
     resultSize.scale(m_filter.filterScale());
-    PixelBufferFormat format { AlphaPremultiplication::Premultiplied, PixelFormat::RGBA8, DestinationColorSpace::SRGB };
+    PixelBufferFormat format { AlphaPremultiplication::Premultiplied, PixelFormat::RGBA8, m_resultColorSpace };
     m_premultipliedImageResult = PixelBuffer::tryCreate(format, resultSize);
     return m_premultipliedImageResult;
 }

Modified: trunk/Source/WebCore/testing/Internals.cpp (277568 => 277569)


--- trunk/Source/WebCore/testing/Internals.cpp	2021-05-16 15:00:51 UTC (rev 277568)
+++ trunk/Source/WebCore/testing/Internals.cpp	2021-05-16 15:21:34 UTC (rev 277569)
@@ -5331,7 +5331,7 @@
     if (!rgba)
         return;
     
-    auto imageData = ImageData::create(rgba.releaseNonNull(), videoSettings.width(), videoSettings.height());
+    auto imageData = ImageData::create(rgba.releaseNonNull(), videoSettings.width(), videoSettings.height(), { { PredefinedColorSpace::SRGB } });
     if (!imageData.hasException())
         m_nextTrackFramePromise->resolve(imageData.releaseReturnValue());
     else
@@ -6203,7 +6203,7 @@
     m_artworkImagePromise = makeUnique<ArtworkImagePromise>(WTFMove(promise));
     m_artworkLoader = makeUnique<ArtworkImageLoader>(*contextDocument(), url, [this](Image* image) {
         if (image) {
-            auto imageData = ImageData::create(unsigned(image->width()), unsigned(image->height()));
+            auto imageData = ImageData::create(image->width(), image->height(), { { PredefinedColorSpace::SRGB } });
             if (!imageData.hasException())
                 m_artworkImagePromise->resolve(imageData.releaseReturnValue());
             else

Modified: trunk/Source/WebKitLegacy/win/ChangeLog (277568 => 277569)


--- trunk/Source/WebKitLegacy/win/ChangeLog	2021-05-16 15:00:51 UTC (rev 277568)
+++ trunk/Source/WebKitLegacy/win/ChangeLog	2021-05-16 15:21:34 UTC (rev 277569)
@@ -1,3 +1,18 @@
+2021-05-16  Sam Weinig  <wei...@apple.com>
+
+        Add support for creating/accessing/setting non-sRGB ImageData via canvas
+        https://bugs.webkit.org/show_bug.cgi?id=225841
+
+        Reviewed by Darin Adler.
+
+        Add support for tests enabling the CanvasColorSpaceEnabled preference.
+
+        * WebPreferences.cpp:
+        (WebPreferences::canvasColorSpaceEnabled):
+        * WebPreferences.h:
+        * WebView.cpp:
+        (WebView::notifyPreferencesChanged):
+
 2021-05-15  Ryosuke Niwa  <rn...@webkit.org>
 
         Delete WebSQL code from WebKit2

Modified: trunk/Source/WebKitLegacy/win/WebPreferences.cpp (277568 => 277569)


--- trunk/Source/WebKitLegacy/win/WebPreferences.cpp	2021-05-16 15:00:51 UTC (rev 277568)
+++ trunk/Source/WebKitLegacy/win/WebPreferences.cpp	2021-05-16 15:21:34 UTC (rev 277569)
@@ -2631,3 +2631,9 @@
     }
     return S_OK;
 }
+
+bool WebPreferences::canvasColorSpaceEnabled()
+{
+    return boolValueForKey("WebKitCanvasColorSpaceEnabled");
+}
+

Modified: trunk/Source/WebKitLegacy/win/WebPreferences.h (277568 => 277569)


--- trunk/Source/WebKitLegacy/win/WebPreferences.h	2021-05-16 15:00:51 UTC (rev 277568)
+++ trunk/Source/WebKitLegacy/win/WebPreferences.h	2021-05-16 15:21:34 UTC (rev 277569)
@@ -343,6 +343,10 @@
 
     HRESULT postPreferencesChangesNotification();
 
+    // The following preference accessors are not exposed via IWebPreferences* as they are only
+    // needed for testing purposes and can be toggled via the set*PreferenceForTesting functions.
+    bool canvasColorSpaceEnabled();
+
 private:
     WebPreferences();
     ~WebPreferences();

Modified: trunk/Source/WebKitLegacy/win/WebView.cpp (277568 => 277569)


--- trunk/Source/WebKitLegacy/win/WebView.cpp	2021-05-16 15:00:51 UTC (rev 277568)
+++ trunk/Source/WebKitLegacy/win/WebView.cpp	2021-05-16 15:21:34 UTC (rev 277569)
@@ -5667,6 +5667,8 @@
         return hr;
     settings.setOverscrollBehaviorEnabled(!!enabled);
 
+    settings.setCanvasColorSpaceEnabled(m_preferences->canvasColorSpaceEnabled());
+
     return S_OK;
 }
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to