Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(14)

Unified Diff: third_party/WebKit/Source/core/html/ImageData.cpp

Issue 2555213002: Implement color management for ImageData (Closed)
Patch Set: Fixing ImageData::validateConstructorArguments Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « third_party/WebKit/Source/core/html/ImageData.h ('k') | third_party/WebKit/Source/core/html/ImageData.idl » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/WebKit/Source/core/html/ImageData.cpp
diff --git a/third_party/WebKit/Source/core/html/ImageData.cpp b/third_party/WebKit/Source/core/html/ImageData.cpp
index 355814b2c3249bd4e0b6bd2f15439569c83edec4..3cca1f6759ee7e67df9f50bd7d5853ef9427b76e 100644
--- a/third_party/WebKit/Source/core/html/ImageData.cpp
+++ b/third_party/WebKit/Source/core/html/ImageData.cpp
@@ -34,11 +34,163 @@
#include "core/frame/ImageBitmap.h"
#include "core/imagebitmap/ImageBitmapOptions.h"
#include "platform/RuntimeEnabledFeatures.h"
-#include "wtf/CheckedNumeric.h"
namespace blink {
+bool ImageData::validateConstructorArguments(const unsigned& paramFlags,
+ const IntSize* size,
+ const unsigned& width,
+ const unsigned& height,
+ const DOMArrayBufferView* data,
+ const String* colorSpace,
+ ExceptionState* exceptionState,
+ ImageDataType imageDataType) {
+ if (paramFlags & kParamData) {
+ if (data->type() != DOMArrayBufferView::ViewType::TypeUint8Clamped &&
+ data->type() != DOMArrayBufferView::ViewType::TypeFloat32)
+ return false;
+ if (data->type() == DOMArrayBufferView::ViewType::TypeUint8Clamped &&
+ imageDataType != kUint8ClampedImageData)
+ imageDataType = kFloat32ImageData;
+ }
+
+ // ImageData::create parameters without ExceptionState
+ if (paramFlags & kParamSize) {
+ if (!size->width() || !size->height())
+ return false;
+ CheckedNumeric<unsigned> dataSize = 4;
+ dataSize *= size->width();
+ dataSize *= size->height();
+ if (!dataSize.IsValid())
+ return false;
+ if (paramFlags & kParamData) {
+ DCHECK(data);
+ unsigned length =
+ data->type() == DOMArrayBufferView::ViewType::TypeUint8Clamped
+ ? (const_cast<DOMUint8ClampedArray*>(
+ static_cast<const DOMUint8ClampedArray*>(data)))
+ ->length()
+ : (const_cast<DOMFloat32Array*>(
+ static_cast<const DOMFloat32Array*>(data)))
+ ->length();
+ if (dataSize.ValueOrDie() > length)
+ return false;
+ }
+ return true;
+ }
+
+ // ImageData::create parameters with ExceptionState
+ if ((paramFlags & kParamWidth) && !width) {
+ exceptionState->throwDOMException(
+ IndexSizeError, "The source width is zero or not a number.");
+ return false;
+ }
+ if ((paramFlags & kParamHeight) && !height) {
+ exceptionState->throwDOMException(
+ IndexSizeError, "The source height is zero or not a number.");
+ return false;
+ }
+ if (paramFlags & (kParamWidth | kParamHeight)) {
+ CheckedNumeric<unsigned> dataSize = 4;
+ dataSize *= width;
+ dataSize *= height;
+ if (!dataSize.IsValid()) {
+ exceptionState->throwDOMException(
+ IndexSizeError,
+ "The requested image size exceeds the supported range.");
+ return false;
+ }
+ }
+ if (paramFlags & kParamData) {
+ DCHECK(data);
+ unsigned length =
+ data->type() == DOMArrayBufferView::ViewType::TypeUint8Clamped
+ ? (const_cast<DOMUint8ClampedArray*>(
+ static_cast<const DOMUint8ClampedArray*>(data)))
+ ->length()
+ : (const_cast<DOMFloat32Array*>(
+ static_cast<const DOMFloat32Array*>(data)))
+ ->length();
+ if (!length) {
+ exceptionState->throwDOMException(IndexSizeError,
+ "The input data has zero elements.");
+ return false;
+ }
+ if (length % 4) {
+ exceptionState->throwDOMException(
+ IndexSizeError, "The input data length is not a multiple of 4.");
+ return false;
+ }
+ length /= 4;
+ if (length % width) {
+ exceptionState->throwDOMException(
+ IndexSizeError,
+ "The input data length is not a multiple of (4 * width).");
+ return false;
+ }
+ if ((paramFlags & kParamHeight) && height != length / width) {
+ exceptionState->throwDOMException(
+ IndexSizeError,
+ "The input data length is not equal to (4 * width * height).");
+ return false;
+ }
+ }
+ if (paramFlags & kParamColorSpace) {
+ if (!colorSpace || colorSpace->length() == 0) {
+ exceptionState->throwDOMException(
+ NotSupportedError, "The source color space is not defined.");
+ return false;
+ }
+ if (imageDataType == kUint8ClampedImageData &&
+ *colorSpace != kLegacyImageDataColorSpaceName &&
+ *colorSpace != kSRGBImageDataColorSpaceName) {
+ exceptionState->throwDOMException(NotSupportedError,
+ "The input color space is not "
+ "supported in "
+ "Uint8ClampedArray-backed ImageData.");
+ return false;
+ }
+ if (imageDataType == kFloat32ImageData &&
+ *colorSpace != kLinearRGBImageDataColorSpaceName) {
+ exceptionState->throwDOMException(NotSupportedError,
+ "The input color space is not "
+ "supported in "
+ "Float32Array-backed ImageData.");
+ return false;
+ }
+ }
+ return true;
+}
+
+DOMUint8ClampedArray* ImageData::allocateAndValidateUint8ClampedArray(
+ const unsigned& length,
+ ExceptionState* exceptionState) {
+ if (!length)
+ return nullptr;
+ DOMUint8ClampedArray* dataArray = DOMUint8ClampedArray::createOrNull(length);
+ if (!dataArray || length != dataArray->length()) {
+ if (exceptionState) {
+ exceptionState->throwDOMException(V8RangeError,
+ "Out of memory at ImageData creation");
+ }
+ return nullptr;
+ }
+ return dataArray;
+}
+
ImageData* ImageData::create(const IntSize& size) {
+ if (!ImageData::validateConstructorArguments(kParamSize, &size))
+ return nullptr;
+ DOMUint8ClampedArray* byteArray =
+ ImageData::allocateAndValidateUint8ClampedArray(4 * size.width() *
+ size.height());
+ if (!byteArray)
+ return nullptr;
+ return new ImageData(size, byteArray);
+}
+
+// This function accepts size (0, 0).
+ImageData* ImageData::createForTest(const IntSize& size) {
CheckedNumeric<unsigned> dataSize = 4;
dataSize *= size.width();
dataSize *= size.height();
@@ -55,94 +207,33 @@ ImageData* ImageData::create(const IntSize& size) {
ImageData* ImageData::create(const IntSize& size,
DOMUint8ClampedArray* byteArray) {
- CheckedNumeric<unsigned> dataSize = 4;
- dataSize *= size.width();
- dataSize *= size.height();
- if (!dataSize.IsValid())
- return nullptr;
-
- if (!dataSize.IsValid() || dataSize.ValueOrDie() > byteArray->length())
+ if (!ImageData::validateConstructorArguments(kParamSize | kParamData, &size,
+ 0, 0, byteArray))
return nullptr;
-
return new ImageData(size, byteArray);
}
ImageData* ImageData::create(unsigned width,
unsigned height,
ExceptionState& exceptionState) {
- if (!width || !height) {
- exceptionState.throwDOMException(
- IndexSizeError, String::format("The source %s is zero or not a number.",
- width ? "height" : "width"));
- return nullptr;
- }
-
- CheckedNumeric<unsigned> dataSize = 4;
- dataSize *= width;
- dataSize *= height;
- if (!dataSize.IsValid() || static_cast<int>(width) < 0 ||
- static_cast<int>(height) < 0) {
- exceptionState.throwDOMException(
- IndexSizeError,
- "The requested image size exceeds the supported range.");
+ if (!ImageData::validateConstructorArguments(kParamWidth | kParamHeight,
+ nullptr, width, height, nullptr,
+ nullptr, &exceptionState))
return nullptr;
- }
-
DOMUint8ClampedArray* byteArray =
- DOMUint8ClampedArray::createOrNull(dataSize.ValueOrDie());
- if (!byteArray) {
- exceptionState.throwDOMException(V8Error,
- "Out of memory at ImageData creation");
- return nullptr;
- }
-
- return new ImageData(IntSize(width, height), byteArray);
-}
-
-bool ImageData::validateConstructorArguments(DOMUint8ClampedArray* data,
- unsigned width,
- unsigned& lengthInPixels,
- ExceptionState& exceptionState) {
- if (!width) {
- exceptionState.throwDOMException(
- IndexSizeError, "The source width is zero or not a number.");
- return false;
- }
- DCHECK(data);
- unsigned length = data->length();
- if (!length) {
- exceptionState.throwDOMException(IndexSizeError,
- "The input data has a zero byte length.");
- return false;
- }
- if (length % 4) {
- exceptionState.throwDOMException(
- IndexSizeError, "The input data byte length is not a multiple of 4.");
- return false;
- }
- length /= 4;
- if (length % width) {
- exceptionState.throwDOMException(
- IndexSizeError,
- "The input data byte length is not a multiple of (4 * width).");
- return false;
- }
- lengthInPixels = length;
- return true;
+ ImageData::allocateAndValidateUint8ClampedArray(4 * width * height,
+ &exceptionState);
+ return byteArray ? new ImageData(IntSize(width, height), byteArray) : nullptr;
}
ImageData* ImageData::create(DOMUint8ClampedArray* data,
unsigned width,
ExceptionState& exceptionState) {
- unsigned lengthInPixels = 0;
- if (!validateConstructorArguments(data, width, lengthInPixels,
- exceptionState)) {
- DCHECK(exceptionState.hadException());
+ if (!ImageData::validateConstructorArguments(kParamData | kParamWidth,
+ nullptr, width, 0, data, nullptr,
+ &exceptionState))
return nullptr;
- }
- DCHECK_GT(lengthInPixels, 0u);
- DCHECK_GT(width, 0u);
- unsigned height = lengthInPixels / width;
+ unsigned height = data->length() / (width * 4);
return new ImageData(IntSize(width, height), data);
}
@@ -150,23 +241,81 @@ ImageData* ImageData::create(DOMUint8ClampedArray* data,
unsigned width,
unsigned height,
ExceptionState& exceptionState) {
- unsigned lengthInPixels = 0;
- if (!validateConstructorArguments(data, width, lengthInPixels,
- exceptionState)) {
- DCHECK(exceptionState.hadException());
+ if (!ImageData::validateConstructorArguments(
+ kParamData | kParamWidth | kParamHeight, nullptr, width, height, data,
+ nullptr, &exceptionState))
return nullptr;
+ return new ImageData(IntSize(width, height), data);
+}
+
+ImageDataColorSpace ImageData::getImageDataColorSpace(String colorSpaceName) {
+ if (colorSpaceName == kLegacyImageDataColorSpaceName)
+ return kLegacyImageDataColorSpace;
+ if (colorSpaceName == kSRGBImageDataColorSpaceName)
+ return kSRGBImageDataColorSpace;
+ if (colorSpaceName == kLinearRGBImageDataColorSpaceName)
+ return kLinearRGBImageDataColorSpace;
+ NOTREACHED();
+ return kLegacyImageDataColorSpace;
+}
+
+String ImageData::getImageDataColorSpaceName(ImageDataColorSpace colorSpace) {
+ switch (colorSpace) {
+ case kLegacyImageDataColorSpace:
+ return kLegacyImageDataColorSpaceName;
+ case kSRGBImageDataColorSpace:
+ return kSRGBImageDataColorSpaceName;
+ case kLinearRGBImageDataColorSpace:
+ return kLinearRGBImageDataColorSpaceName;
}
- DCHECK_GT(lengthInPixels, 0u);
- DCHECK_GT(width, 0u);
- if (height != lengthInPixels / width) {
- exceptionState.throwDOMException(
- IndexSizeError,
- "The input data byte length is not equal to (4 * width * height).");
+ NOTREACHED();
+ return String();
+}
+
+ImageData* ImageData::createImageData(unsigned width,
+ unsigned height,
+ String colorSpace,
+ ExceptionState& exceptionState) {
+ if (!ImageData::validateConstructorArguments(
+ kParamWidth | kParamHeight | kParamColorSpace, nullptr, width, height,
+ nullptr, &colorSpace, &exceptionState))
return nullptr;
- }
- return new ImageData(IntSize(width, height), data);
+
+ DOMUint8ClampedArray* byteArray =
+ ImageData::allocateAndValidateUint8ClampedArray(4 * width * height,
+ &exceptionState);
+ return byteArray
+ ? new ImageData(IntSize(width, height), byteArray, colorSpace)
+ : nullptr;
+}
+
+ImageData* ImageData::createImageData(DOMUint8ClampedArray* data,
+ unsigned width,
+ String colorSpace,
+ ExceptionState& exceptionState) {
+ if (!ImageData::validateConstructorArguments(
+ kParamData | kParamWidth | kParamColorSpace, nullptr, width, 0, data,
+ &colorSpace, &exceptionState))
+ return nullptr;
+ unsigned height = data->length() / (width * 4);
+ return new ImageData(IntSize(width, height), data, colorSpace);
+}
+
+ImageData* ImageData::createImageData(DOMUint8ClampedArray* data,
+ unsigned width,
+ unsigned height,
+ String colorSpace,
+ ExceptionState& exceptionState) {
+ if (!ImageData::validateConstructorArguments(
+ kParamData | kParamWidth | kParamHeight | kParamColorSpace, nullptr,
+ width, height, data, &colorSpace, &exceptionState))
+ return nullptr;
+ return new ImageData(IntSize(width, height), data, colorSpace);
}
+// TODO(zakerinasab): Fix this when ImageBitmap color correction code is landed.
+// Tip: If the source Image Data has a color space, createImageBitmap must
+// respect this color space even when no color space tag is passed to it.
ScriptPromise ImageData::createImageBitmap(ScriptState* scriptState,
EventTarget& eventTarget,
Optional<IntRect> cropRect,
@@ -211,8 +360,12 @@ v8::Local<v8::Object> ImageData::associateWithWrapper(
return wrapper;
}
-ImageData::ImageData(const IntSize& size, DOMUint8ClampedArray* byteArray)
- : m_size(size), m_data(byteArray) {
+ImageData::ImageData(const IntSize& size,
+ DOMUint8ClampedArray* byteArray,
+ String colorSpaceName)
+ : m_size(size),
+ m_colorSpace(getImageDataColorSpace(colorSpaceName)),
+ m_data(byteArray) {
DCHECK_GE(size.width(), 0);
DCHECK_GE(size.height(), 0);
SECURITY_CHECK(static_cast<unsigned>(size.width() * size.height() * 4) <=
« no previous file with comments | « third_party/WebKit/Source/core/html/ImageData.h ('k') | third_party/WebKit/Source/core/html/ImageData.idl » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698