Index: third_party/WebKit/Source/modules/canvas2d/BaseRenderingContext2D.cpp |
diff --git a/third_party/WebKit/Source/modules/canvas2d/BaseRenderingContext2D.cpp b/third_party/WebKit/Source/modules/canvas2d/BaseRenderingContext2D.cpp |
index e7f9f3bfe590b13529a01cfe7c89a7f8c9b4eff0..a125cc96892163f884919ecaa22cf3635ae6e514 100644 |
--- a/third_party/WebKit/Source/modules/canvas2d/BaseRenderingContext2D.cpp |
+++ b/third_party/WebKit/Source/modules/canvas2d/BaseRenderingContext2D.cpp |
@@ -35,8 +35,11 @@ |
namespace blink { |
BaseRenderingContext2D::BaseRenderingContext2D() |
- : m_clipAntialiasing(NotAntiAliased) { |
+ : m_clipAntialiasing(NotAntiAliased), m_isColorManaged(false) { |
m_stateStack.push_back(CanvasRenderingContext2DState::create()); |
+ m_isColorManaged = |
+ RuntimeEnabledFeatures::experimentalCanvasFeaturesEnabled() && |
+ RuntimeEnabledFeatures::colorCorrectRenderingEnabled(); |
} |
BaseRenderingContext2D::~BaseRenderingContext2D() {} |
@@ -1496,10 +1499,38 @@ bool BaseRenderingContext2D::computeDirtyRect( |
return true; |
} |
+bool BaseRenderingContext2D::colorSettingsAsImageDataColorSettings( |
+ ImageDataColorSettings& colorSettings) const { |
+ if (!m_isColorManaged) |
+ return false; |
+ colorSettings.setColorSpace(renderingContext()->colorSpaceAsString()); |
+ switch (renderingContext()->pixelFormat()) { |
+ case kRGBA8CanvasPixelFormat: |
+ colorSettings.setStorageFormat(kUint8ClampedArrayStorageFormatName); |
+ break; |
+ case kF16CanvasPixelFormat: |
+ colorSettings.setStorageFormat(kFloat32ArrayStorageFormatName); |
+ break; |
+ case kRGB10A2CanvasPixelFormat: |
+ case kRGBA12CanvasPixelFormat: |
+ default: |
+ NOTREACHED(); |
+ return false; |
+ } |
+ return true; |
+} |
+ |
ImageData* BaseRenderingContext2D::createImageData( |
ImageData* imageData, |
ExceptionState& exceptionState) const { |
- ImageData* result = ImageData::create(imageData->size()); |
+ ImageData* result = nullptr; |
+ if (m_isColorManaged) { |
+ ImageDataColorSettings colorSettings; |
+ if (colorSettingsAsImageDataColorSettings(colorSettings)) |
+ result = ImageData::create(imageData->size(), &colorSettings); |
+ } else { |
+ result = ImageData::create(imageData->size()); |
+ } |
if (!result) |
exceptionState.throwRangeError("Out of memory at ImageData creation"); |
return result; |
@@ -1517,8 +1548,14 @@ ImageData* BaseRenderingContext2D::createImageData( |
} |
IntSize size(abs(sw), abs(sh)); |
- |
- ImageData* result = ImageData::create(size); |
+ ImageData* result = nullptr; |
+ if (m_isColorManaged) { |
+ ImageDataColorSettings colorSettings; |
+ if (colorSettingsAsImageDataColorSettings(colorSettings)) |
+ result = ImageData::create(size, &colorSettings); |
+ } else { |
+ result = ImageData::create(size); |
+ } |
if (!result) |
exceptionState.throwRangeError("Out of memory at ImageData creation"); |
return result; |
@@ -1573,11 +1610,19 @@ ImageData* BaseRenderingContext2D::getImageData( |
timer.emplace(scopedUsCounterCPU); |
} |
+ ImageDataColorSettings colorSettings; |
+ bool validColorSettings = false; |
+ if (m_isColorManaged) |
+ validColorSettings = colorSettingsAsImageDataColorSettings(colorSettings); |
IntRect imageDataRect(sx, sy, sw, sh); |
DVLOG(1) << sx << ", " << sy << ", " << sw << ", " << sh; |
ImageBuffer* buffer = imageBuffer(); |
if (!buffer || isContextLost()) { |
- ImageData* result = ImageData::create(imageDataRect.size()); |
+ ImageData* result = nullptr; |
+ if (validColorSettings) |
+ result = ImageData::create(imageDataRect.size(), &colorSettings); |
+ else |
+ result = ImageData::create(imageDataRect.size()); |
if (!result) |
exceptionState.throwRangeError("Out of memory at ImageData creation"); |
return result; |
@@ -1589,7 +1634,39 @@ ImageData* BaseRenderingContext2D::getImageData( |
return nullptr; |
} |
- DOMArrayBuffer* arrayBuffer = DOMArrayBuffer::create(contents); |
+ DOMArrayBuffer* arrayBuffer = nullptr; |
+ DOMArrayBufferView* arrayBufferView = nullptr; |
+ DOMFloat32Array* dataArray = nullptr; |
+ |
+ if (m_isColorManaged) { |
+ ImageDataStorageFormat storageFormat = |
+ ImageData::imageDataStorageFormat(colorSettings.storageFormat()); |
+ switch (storageFormat) { |
+ case kUint8ClampedArrayStorageFormat: |
+ arrayBuffer = DOMArrayBuffer::create(contents); |
+ return ImageData::create( |
+ imageDataRect.size(), |
+ DOMUint8ClampedArray::create(arrayBuffer, 0, |
+ arrayBuffer->byteLength())); |
+ break; |
+ case kUint16ArrayStorageFormat: |
+ NOTREACHED(); |
+ break; |
+ case kFloat32ArrayStorageFormat: |
+ arrayBufferView = ImageData:: |
+ convertPixelsFromCanvasPixelFormatToImageDataStorageFormat( |
+ contents, renderingContext()->pixelFormat(), storageFormat); |
+ dataArray = const_cast<DOMFloat32Array*>( |
+ static_cast<const DOMFloat32Array*>(arrayBufferView)); |
+ return ImageData::create(imageDataRect.size(), arrayBufferView, |
+ &colorSettings); |
+ default: |
+ NOTREACHED(); |
+ } |
+ return nullptr; |
+ } |
+ |
+ arrayBuffer = DOMArrayBuffer::create(contents); |
return ImageData::create( |
imageDataRect.size(), |
DOMUint8ClampedArray::create(arrayBuffer, 0, arrayBuffer->byteLength())); |
@@ -1613,11 +1690,28 @@ void BaseRenderingContext2D::putImageData(ImageData* data, |
ExceptionState& exceptionState) { |
m_usageCounters.numPutImageDataCalls++; |
m_usageCounters.areaPutImageDataCalls += dirtyWidth * dirtyHeight; |
- if (data->data()->bufferBase()->isNeutered()) { |
+ |
+ bool dataIsNeutered = false; |
+ if (m_isColorManaged) { |
+ dataIsNeutered = |
+ (data->dataUnion().isUint8ClampedArray() && |
+ data->dataUnion() |
+ .getAsUint8ClampedArray() |
+ ->bufferBase() |
+ ->isNeutered()) || |
+ (data->dataUnion().isUint16Array() && |
+ data->dataUnion().getAsUint16Array()->bufferBase()->isNeutered()) || |
+ (data->dataUnion().isFloat32Array() && |
+ data->dataUnion().getAsFloat32Array()->bufferBase()->isNeutered()); |
+ } else { |
+ dataIsNeutered = data->data()->bufferBase()->isNeutered(); |
+ } |
+ if (dataIsNeutered) { |
exceptionState.throwDOMException(InvalidStateError, |
"The source data has been neutered."); |
return; |
} |
+ |
ImageBuffer* buffer = imageBuffer(); |
if (!buffer) |
return; |
@@ -1667,10 +1761,22 @@ void BaseRenderingContext2D::putImageData(ImageData* data, |
checkOverdraw(destRect, 0, CanvasRenderingContext2DState::NoImage, |
UntransformedUnclippedFill); |
- buffer->putByteArray(Unmultiplied, data->data()->data(), |
- IntSize(data->width(), data->height()), sourceRect, |
- IntPoint(destOffset)); |
- |
+ if (m_isColorManaged) { |
+ unsigned dataLength = data->width() * data->height(); |
+ if (renderingContext()->pixelFormat() == kF16CanvasPixelFormat) |
+ dataLength *= 2; |
+ std::unique_ptr<uint8_t[]> convertedPixels(new uint8_t[4 * dataLength]); |
+ data->imageDataInCanvasColorSettings(renderingContext()->colorSpace(), |
+ renderingContext()->pixelFormat(), |
+ convertedPixels); |
+ buffer->putByteArray(Unmultiplied, convertedPixels.get(), |
+ IntSize(data->width(), data->height()), sourceRect, |
+ IntPoint(destOffset)); |
+ } else { |
+ buffer->putByteArray(Unmultiplied, data->data()->data(), |
+ IntSize(data->width(), data->height()), sourceRect, |
+ IntPoint(destOffset)); |
+ } |
didDraw(destRect); |
} |