| 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) <=
|
|
|