summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/core/html/canvas/image_data.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/blink/renderer/core/html/canvas/image_data.cc')
-rw-r--r--chromium/third_party/blink/renderer/core/html/canvas/image_data.cc835
1 files changed, 158 insertions, 677 deletions
diff --git a/chromium/third_party/blink/renderer/core/html/canvas/image_data.cc b/chromium/third_party/blink/renderer/core/html/canvas/image_data.cc
index 5e8683287c1..d2bbbae8bf8 100644
--- a/chromium/third_party/blink/renderer/core/html/canvas/image_data.cc
+++ b/chromium/third_party/blink/renderer/core/html/canvas/image_data.cc
@@ -34,137 +34,154 @@
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/core/imagebitmap/image_bitmap.h"
#include "third_party/blink/renderer/platform/graphics/color_behavior.h"
-#include "third_party/skia/include/third_party/skcms/skcms.h"
#include "v8/include/v8.h"
namespace blink {
-// Please note that all the number "4" in the file means number of channels
-// required to describe a pixel, namely, red, green, blue and alpha.
-namespace {
-
-bool RaiseDOMExceptionAndReturnFalse(ExceptionState* exception_state,
- DOMExceptionCode exception_code,
- const char* message) {
- if (exception_state)
- exception_state->ThrowDOMException(exception_code, message);
- return false;
-}
-
-} // namespace
-
-bool ImageData::ValidateConstructorArguments(
- const unsigned& param_flags,
- const IntSize* size,
- const unsigned& width,
- const unsigned& height,
- const NotShared<DOMArrayBufferView> data,
- const ImageDataColorSettings* color_settings,
- ExceptionState* exception_state) {
- // We accept all the combinations of colorSpace and storageFormat in an
- // ImageDataColorSettings to be stored in an ImageData. Therefore, we don't
- // check the color settings in this function.
+ImageData* ImageData::ValidateAndCreate(
+ unsigned width,
+ base::Optional<unsigned> height,
+ base::Optional<NotShared<DOMArrayBufferView>> data,
+ const ImageDataSettings* input_settings,
+ ExceptionState& exception_state,
+ uint32_t flags) {
+ IntSize size;
+ if ((flags & RequireCanvasColorManagement &&
+ !RuntimeEnabledFeatures::CanvasColorManagementEnabled())) {
+ exception_state.ThrowTypeError("Overload resolution failed.");
+ return nullptr;
+ }
- if ((param_flags & kParamWidth) && !width) {
- return RaiseDOMExceptionAndReturnFalse(
- exception_state, DOMExceptionCode::kIndexSizeError,
+ if (!width) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kIndexSizeError,
"The source width is zero or not a number.");
+ return nullptr;
}
-
- if ((param_flags & kParamHeight) && !height) {
- return RaiseDOMExceptionAndReturnFalse(
- exception_state, DOMExceptionCode::kIndexSizeError,
- "The source height is zero or not a number.");
+ size.SetWidth(width);
+ if (height) {
+ if (!*height) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kIndexSizeError,
+ "The source height is zero or not a number.");
+ return nullptr;
+ }
+ size.SetHeight(*height);
}
- if (param_flags & (kParamWidth | kParamHeight)) {
- base::CheckedNumeric<unsigned> data_size =
- ImageData::StorageFormatBytesPerPixel(
- kUint8ClampedArrayStorageFormatName);
- if (color_settings) {
- data_size = ImageData::StorageFormatBytesPerPixel(
- color_settings->storageFormat());
- }
- data_size *= width;
- data_size *= height;
- if (!data_size.IsValid()) {
- return RaiseDOMExceptionAndReturnFalse(
- exception_state, DOMExceptionCode::kIndexSizeError,
- "The requested image size exceeds the supported range.");
- }
+ // Populate the ImageDataSettings to use based on |input_settings|.
+ ImageDataSettings* settings = ImageDataSettings::Create();
+ if (input_settings) {
+ settings->setColorSpace(input_settings->colorSpace());
+ settings->setStorageFormat(input_settings->storageFormat());
+ }
- if (data_size.ValueOrDie() > v8::TypedArray::kMaxLength) {
- if (exception_state) {
- exception_state->ThrowRangeError(
- "Out of memory at ImageData creation.");
+ // Ensure the size does not overflow.
+ unsigned size_in_elements = 0;
+ {
+ // Please note that the number "4" in the means number of channels required
+ // to describe a pixel, namely, red, green, blue and alpha.
+ base::CheckedNumeric<unsigned> size_in_elements_checked = 4;
+ size_in_elements_checked *= size.Width();
+ size_in_elements_checked *= size.Height();
+ if (!(flags & ValidateAndCreateFlags::Context2DErrorMode)) {
+ if (!size_in_elements_checked.IsValid()) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kIndexSizeError,
+ "The requested image size exceeds the supported range.");
+ return nullptr;
}
- return false;
}
+ if (!size_in_elements_checked.IsValid() ||
+ size_in_elements_checked.ValueOrDie() > v8::TypedArray::kMaxLength) {
+ exception_state.ThrowRangeError("Out of memory at ImageData creation.");
+ return nullptr;
+ }
+ size_in_elements = size_in_elements_checked.ValueOrDie();
}
- unsigned data_length = 0;
- if (param_flags & kParamData) {
+ // If |data| is provided, ensure it is a reasonable format, and that it can
+ // work with |size|. Update |settings| to reflect |data|'s format.
+ if (data) {
DCHECK(data);
- if (data->GetType() != DOMArrayBufferView::ViewType::kTypeUint8Clamped &&
- data->GetType() != DOMArrayBufferView::ViewType::kTypeUint16 &&
- data->GetType() != DOMArrayBufferView::ViewType::kTypeFloat32) {
- return RaiseDOMExceptionAndReturnFalse(
- exception_state, DOMExceptionCode::kNotSupportedError,
- "The input data type is not supported.");
+ switch ((*data)->GetType()) {
+ case DOMArrayBufferView::ViewType::kTypeUint8Clamped:
+ settings->setStorageFormat(kUint8ClampedArrayStorageFormatName);
+ break;
+ case DOMArrayBufferView::ViewType::kTypeUint16:
+ settings->setStorageFormat(kUint16ArrayStorageFormatName);
+ break;
+ case DOMArrayBufferView::ViewType::kTypeFloat32:
+ settings->setStorageFormat(kFloat32ArrayStorageFormatName);
+ break;
+ default:
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kNotSupportedError,
+ "The input data type is not supported.");
+ return nullptr;
}
-
static_assert(
std::numeric_limits<unsigned>::max() >=
std::numeric_limits<uint32_t>::max(),
"We use UINT32_MAX as the upper bound of the input size and expect "
"that the result fits into an `unsigned`.");
- if (!base::CheckedNumeric<uint32_t>(data->byteLength())
- .AssignIfValid(&data_length)) {
- return RaiseDOMExceptionAndReturnFalse(
- exception_state, DOMExceptionCode::kNotSupportedError,
+
+ unsigned data_length_in_bytes = 0;
+ if (!base::CheckedNumeric<uint32_t>((*data)->byteLength())
+ .AssignIfValid(&data_length_in_bytes)) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kNotSupportedError,
"The input data is too large. The maximum size is 4294967295.");
+ return nullptr;
}
- if (!data_length) {
- return RaiseDOMExceptionAndReturnFalse(
- exception_state, DOMExceptionCode::kInvalidStateError,
- "The input data has zero elements.");
+ if (!data_length_in_bytes) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ "The input data has zero elements.");
+ return nullptr;
}
- data_length /= data->TypeSize();
- if (data_length % 4) {
- return RaiseDOMExceptionAndReturnFalse(
- exception_state, DOMExceptionCode::kInvalidStateError,
+
+ const unsigned data_length_in_elements =
+ data_length_in_bytes / (*data)->TypeSize();
+ if (data_length_in_elements % 4) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kInvalidStateError,
"The input data length is not a multiple of 4.");
+ return nullptr;
}
- if ((param_flags & kParamWidth) && (data_length / 4) % width) {
- return RaiseDOMExceptionAndReturnFalse(
- exception_state, DOMExceptionCode::kIndexSizeError,
+ const unsigned data_length_in_pixels = data_length_in_elements / 4;
+ if (data_length_in_pixels % width) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kIndexSizeError,
"The input data length is not a multiple of (4 * width).");
+ return nullptr;
}
- if ((param_flags & kParamWidth) && (param_flags & kParamHeight) &&
- height != data_length / (4 * width))
- return RaiseDOMExceptionAndReturnFalse(
- exception_state, DOMExceptionCode::kIndexSizeError,
- "The input data length is not equal to (4 * width * height).");
+ const unsigned expected_height = data_length_in_pixels / width;
+ if (height) {
+ if (*height != expected_height) {
+ exception_state.ThrowDOMException(
+ DOMExceptionCode::kIndexSizeError,
+ "The input data length is not equal to (4 * width * height).");
+ return nullptr;
+ }
+ } else {
+ size.SetHeight(expected_height);
+ }
}
- if (param_flags & kParamSize) {
- if (size->Width() <= 0 || size->Height() <= 0)
- return false;
- base::CheckedNumeric<unsigned> data_size = 4;
- data_size *= size->Width();
- data_size *= size->Height();
- if (!data_size.IsValid() ||
- data_size.ValueOrDie() > v8::TypedArray::kMaxLength)
- return false;
- if (param_flags & kParamData) {
- if (data_size.ValueOrDie() > data_length)
- return false;
- }
+ NotShared<DOMArrayBufferView> allocated_data;
+ if (!data) {
+ ImageDataStorageFormat storage_format =
+ GetImageDataStorageFormat(settings->storageFormat());
+ allocated_data = AllocateAndValidateDataArray(
+ size_in_elements, storage_format, &exception_state);
+ if (!allocated_data)
+ return nullptr;
}
- return true;
+ return MakeGarbageCollected<ImageData>(size, data ? *data : allocated_data,
+ settings);
}
NotShared<DOMArrayBufferView> ImageData::AllocateAndValidateDataArray(
@@ -204,333 +221,11 @@ NotShared<DOMArrayBufferView> ImageData::AllocateAndValidateDataArray(
return data_array;
}
-NotShared<DOMUint8ClampedArray> ImageData::AllocateAndValidateUint8ClampedArray(
- const unsigned& length,
- ExceptionState* exception_state) {
- NotShared<DOMUint8ClampedArray> buffer_view;
- buffer_view = AllocateAndValidateDataArray(
- length, kUint8ClampedArrayStorageFormat, exception_state);
- return buffer_view;
-}
-
-NotShared<DOMUint16Array> ImageData::AllocateAndValidateUint16Array(
- const unsigned& length,
- ExceptionState* exception_state) {
- NotShared<DOMUint16Array> buffer_view;
- buffer_view = AllocateAndValidateDataArray(length, kUint16ArrayStorageFormat,
- exception_state);
- return buffer_view;
-}
-
-NotShared<DOMFloat32Array> ImageData::AllocateAndValidateFloat32Array(
- const unsigned& length,
- ExceptionState* exception_state) {
- NotShared<DOMFloat32Array> buffer_view;
- buffer_view = AllocateAndValidateDataArray(length, kFloat32ArrayStorageFormat,
- exception_state);
- return buffer_view;
-}
-
-ImageData* ImageData::Create(const IntSize& size,
- const ImageDataColorSettings* color_settings) {
- if (!ValidateConstructorArguments(kParamSize, &size, 0, 0,
- NotShared<DOMArrayBufferView>(),
- color_settings))
- return nullptr;
- ImageDataStorageFormat storage_format = kUint8ClampedArrayStorageFormat;
- if (color_settings) {
- storage_format =
- ImageData::GetImageDataStorageFormat(color_settings->storageFormat());
- }
- NotShared<DOMArrayBufferView> data_array =
- AllocateAndValidateDataArray(4 * static_cast<unsigned>(size.Width()) *
- static_cast<unsigned>(size.Height()),
- storage_format);
- return data_array
- ? MakeGarbageCollected<ImageData>(size, data_array, color_settings)
- : nullptr;
-}
-
-ImageDataColorSettings* CanvasColorParamsToImageDataColorSettings(
- const CanvasColorParams& color_params) {
- ImageDataColorSettings* color_settings = ImageDataColorSettings::Create();
- switch (color_params.ColorSpace()) {
- case CanvasColorSpace::kSRGB:
- color_settings->setColorSpace(kSRGBCanvasColorSpaceName);
- break;
- case CanvasColorSpace::kRec2020:
- color_settings->setColorSpace(kRec2020CanvasColorSpaceName);
- break;
- case CanvasColorSpace::kP3:
- color_settings->setColorSpace(kP3CanvasColorSpaceName);
- break;
- }
- color_settings->setStorageFormat(kUint8ClampedArrayStorageFormatName);
- if (color_params.PixelFormat() == CanvasPixelFormat::kF16)
- color_settings->setStorageFormat(kFloat32ArrayStorageFormatName);
- return color_settings;
-}
-
-ImageData* ImageData::Create(const IntSize& size,
- const CanvasColorParams& color_params) {
- ImageDataColorSettings* color_settings =
- CanvasColorParamsToImageDataColorSettings(color_params);
- return ImageData::Create(size, color_settings);
-}
-
-ImageData* ImageData::Create(const IntSize& size,
- CanvasColorSpace color_space,
- ImageDataStorageFormat storage_format) {
- ImageDataColorSettings* color_settings = ImageDataColorSettings::Create();
- switch (color_space) {
- case CanvasColorSpace::kSRGB:
- color_settings->setColorSpace(kSRGBCanvasColorSpaceName);
- break;
- case CanvasColorSpace::kRec2020:
- color_settings->setColorSpace(kRec2020CanvasColorSpaceName);
- break;
- case CanvasColorSpace::kP3:
- color_settings->setColorSpace(kP3CanvasColorSpaceName);
- break;
- }
-
- switch (storage_format) {
- case kUint8ClampedArrayStorageFormat:
- color_settings->setStorageFormat(kUint8ClampedArrayStorageFormatName);
- break;
- case kUint16ArrayStorageFormat:
- color_settings->setStorageFormat(kUint16ArrayStorageFormatName);
- break;
- case kFloat32ArrayStorageFormat:
- color_settings->setStorageFormat(kFloat32ArrayStorageFormatName);
- break;
- }
-
- return ImageData::Create(size, color_settings);
-}
-
-ImageData* ImageData::Create(const IntSize& size,
- NotShared<DOMArrayBufferView> data_array,
- const ImageDataColorSettings* color_settings) {
- if (!ImageData::ValidateConstructorArguments(
- kParamSize | kParamData, &size, 0, 0, data_array, color_settings))
- return nullptr;
- return MakeGarbageCollected<ImageData>(size, data_array, color_settings);
-}
-
-ImageData* ImageData::Create(scoped_refptr<StaticBitmapImage> image,
- AlphaDisposition alpha_disposition) {
- PaintImage paint_image = image->PaintImageForCurrentFrame();
- DCHECK(paint_image);
- SkImageInfo image_info = image->PaintImageForCurrentFrame().GetSkImageInfo();
- CanvasColorParams color_params(image_info);
- if (image_info.alphaType() != kOpaque_SkAlphaType) {
- if (alpha_disposition == kPremultiplyAlpha) {
- image_info = image_info.makeAlphaType(kPremul_SkAlphaType);
- } else if (alpha_disposition == kUnpremultiplyAlpha) {
- image_info = image_info.makeAlphaType(kUnpremul_SkAlphaType);
- }
- }
-
- ImageData* image_data = Create(image->Size(), color_params);
- if (!image_data)
- return nullptr;
-
- ImageDataArray data = image_data->data();
- SkColorType color_type = image_info.colorType();
- bool create_f32_image_data = (color_type == kRGBA_1010102_SkColorType ||
- color_type == kRGB_101010x_SkColorType ||
- color_type == kRGBA_F16_SkColorType ||
- color_type == kRGBA_F32_SkColorType);
-
- if (!create_f32_image_data) {
- if (color_type == kR16G16B16A16_unorm_SkColorType) {
- image_info = image_info.makeColorType(kR16G16B16A16_unorm_SkColorType);
- paint_image.readPixels(image_info, data.GetAsUint16Array()->Data(),
- image_info.minRowBytes(), 0, 0);
- } else {
- image_info = image_info.makeColorType(kRGBA_8888_SkColorType);
- paint_image.readPixels(image_info, data.GetAsUint8ClampedArray()->Data(),
- image_info.minRowBytes(), 0, 0);
- }
- } else {
- image_info = image_info.makeColorType(kRGBA_F32_SkColorType);
- paint_image.readPixels(image_info, data.GetAsFloat32Array()->Data(),
- image_info.minRowBytes(), 0, 0);
- }
- return image_data;
-}
-
-ImageData* ImageData::Create(unsigned width,
- unsigned height,
- ExceptionState& exception_state) {
- if (!ImageData::ValidateConstructorArguments(
- kParamWidth | kParamHeight, nullptr, width, height,
- NotShared<DOMArrayBufferView>(), nullptr, &exception_state))
- return nullptr;
-
- NotShared<DOMUint8ClampedArray> byte_array =
- AllocateAndValidateUint8ClampedArray(
- ImageData::StorageFormatBytesPerPixel(
- kUint8ClampedArrayStorageFormat) *
- width * height,
- &exception_state);
- return byte_array ? MakeGarbageCollected<ImageData>(IntSize(width, height),
- byte_array)
- : nullptr;
-}
-
-ImageData* ImageData::Create(NotShared<DOMUint8ClampedArray> data,
- unsigned width,
- ExceptionState& exception_state) {
- if (!ImageData::ValidateConstructorArguments(kParamData | kParamWidth,
- nullptr, width, 0, data, nullptr,
- &exception_state))
- return nullptr;
-
- unsigned height = base::checked_cast<unsigned>(data->length()) / (width * 4);
- return MakeGarbageCollected<ImageData>(IntSize(width, height), data);
-}
-
-ImageData* ImageData::Create(NotShared<DOMUint8ClampedArray> data,
- unsigned width,
- unsigned height,
- ExceptionState& exception_state) {
- if (!ImageData::ValidateConstructorArguments(
- kParamData | kParamWidth | kParamHeight, nullptr, width, height, data,
- nullptr, &exception_state))
- return nullptr;
-
- return MakeGarbageCollected<ImageData>(IntSize(width, height), data);
-}
-
-ImageData* ImageData::Create(NotShared<DOMUint16Array> data,
- unsigned width,
- ExceptionState& exception_state) {
- if (!ImageData::ValidateConstructorArguments(kParamData | kParamWidth,
- nullptr, width, 0, data, nullptr,
- &exception_state))
- return nullptr;
- unsigned height = base::checked_cast<unsigned>(data->length()) /
- (width * ImageData::StorageFormatBytesPerPixel(
- kUint16ArrayStorageFormatName));
- ImageDataColorSettings* image_setting = ImageDataColorSettings::Create();
- image_setting->setStorageFormat(kUint16ArrayStorageFormatName);
- return MakeGarbageCollected<ImageData>(IntSize(width, height), data,
- image_setting);
-}
-
-ImageData* ImageData::Create(NotShared<DOMUint16Array> data,
- unsigned width,
- unsigned height,
- ExceptionState& exception_state) {
- if (!ImageData::ValidateConstructorArguments(
- kParamData | kParamWidth | kParamHeight, nullptr, width, height, data,
- nullptr, &exception_state))
- return nullptr;
-
- ImageDataColorSettings* image_setting = ImageDataColorSettings::Create();
- image_setting->setStorageFormat(kUint16ArrayStorageFormatName);
- return MakeGarbageCollected<ImageData>(IntSize(width, height), data,
- image_setting);
-}
-
-ImageData* ImageData::Create(NotShared<DOMFloat32Array> data,
- unsigned width,
- ExceptionState& exception_state) {
- if (!ImageData::ValidateConstructorArguments(kParamData | kParamWidth,
- nullptr, width, 0, data, nullptr,
- &exception_state))
- return nullptr;
-
- unsigned height = base::checked_cast<unsigned>(data->length()) /
- (width * ImageData::StorageFormatBytesPerPixel(
- kFloat32ArrayStorageFormatName));
- ImageDataColorSettings* image_setting = ImageDataColorSettings::Create();
- image_setting->setStorageFormat(kFloat32ArrayStorageFormatName);
- return MakeGarbageCollected<ImageData>(IntSize(width, height), data,
- image_setting);
-}
-
-ImageData* ImageData::Create(NotShared<DOMFloat32Array> data,
- unsigned width,
- unsigned height,
- ExceptionState& exception_state) {
- if (!ImageData::ValidateConstructorArguments(
- kParamData | kParamWidth | kParamHeight, nullptr, width, height, data,
- nullptr, &exception_state))
- return nullptr;
-
- ImageDataColorSettings* image_setting = ImageDataColorSettings::Create();
- image_setting->setStorageFormat(kFloat32ArrayStorageFormatName);
- return MakeGarbageCollected<ImageData>(IntSize(width, height), data,
- image_setting);
-}
-
-ImageData* ImageData::CreateImageData(
- unsigned width,
- unsigned height,
- const ImageDataColorSettings* color_settings,
- ExceptionState& exception_state) {
- if (!ImageData::ValidateConstructorArguments(
- kParamWidth | kParamHeight, nullptr, width, height,
- NotShared<DOMArrayBufferView>(), color_settings, &exception_state))
- return nullptr;
-
- ImageDataStorageFormat storage_format =
- ImageData::GetImageDataStorageFormat(color_settings->storageFormat());
- NotShared<DOMArrayBufferView> buffer_view = AllocateAndValidateDataArray(
- 4 * width * height, storage_format, &exception_state);
-
- if (!buffer_view)
- return nullptr;
-
- return MakeGarbageCollected<ImageData>(IntSize(width, height), buffer_view,
- color_settings);
-}
-
-ImageData* ImageData::CreateImageData(ImageDataArray& data,
- unsigned width,
- unsigned height,
- ImageDataColorSettings* color_settings,
- ExceptionState& exception_state) {
- NotShared<DOMArrayBufferView> buffer_view;
-
- // When pixels data is provided, we need to override the storage format of
- // ImageDataColorSettings with the one that matches the data type of the
- // pixels.
- String storage_format_name;
-
- if (data.IsUint8ClampedArray()) {
- buffer_view = data.GetAsUint8ClampedArray();
- storage_format_name = kUint8ClampedArrayStorageFormatName;
- } else if (data.IsUint16Array()) {
- buffer_view = data.GetAsUint16Array();
- storage_format_name = kUint16ArrayStorageFormatName;
- } else if (data.IsFloat32Array()) {
- buffer_view = data.GetAsFloat32Array();
- storage_format_name = kFloat32ArrayStorageFormatName;
- } else {
- NOTREACHED();
- }
-
- if (color_settings->storageFormat() != storage_format_name)
- color_settings->setStorageFormat(storage_format_name);
-
- if (!ImageData::ValidateConstructorArguments(
- kParamData | kParamWidth | kParamHeight, nullptr, width, height,
- buffer_view, color_settings, &exception_state))
- return nullptr;
-
- return MakeGarbageCollected<ImageData>(IntSize(width, height), buffer_view,
- color_settings);
-}
-
// This function accepts size (0, 0) and always returns the ImageData in
// "srgb" color space and "uint8" storage format.
ImageData* ImageData::CreateForTest(const IntSize& size) {
base::CheckedNumeric<unsigned> data_size =
- ImageData::StorageFormatBytesPerPixel(kUint8ClampedArrayStorageFormat);
+ StorageFormatBytesPerPixel(kUint8ClampedArrayStorageFormat);
data_size *= size.Width();
data_size *= size.Height();
if (!data_size.IsValid() ||
@@ -547,65 +242,17 @@ ImageData* ImageData::CreateForTest(const IntSize& size) {
// This function is called from unit tests, and all the parameters are supposed
// to be validated on the call site.
-ImageData* ImageData::CreateForTest(
- const IntSize& size,
- NotShared<DOMArrayBufferView> buffer_view,
- const ImageDataColorSettings* color_settings) {
- return MakeGarbageCollected<ImageData>(size, buffer_view, color_settings);
-}
-
-// Crops ImageData to the intersect of its size and the given rectangle. If the
-// intersection is empty or it cannot create the cropped ImageData it returns
-// nullptr. This function leaves the source ImageData intact. When crop_rect
-// covers all the ImageData, a copy of the ImageData is returned.
-// TODO (zakerinasab): crbug.com/774484: As a rule of thumb ImageData belongs to
-// the user and its state should not change unless directly modified by the
-// user. Therefore, we should be able to remove the extra copy and return a
-// "cropped view" on the source ImageData object.
-ImageData* ImageData::CropRect(const IntRect& crop_rect, bool flip_y) {
- IntRect src_rect(IntPoint(), size_);
- const IntRect dst_rect = Intersection(src_rect, crop_rect);
- if (dst_rect.IsEmpty())
- return nullptr;
-
- unsigned data_size = 4 * dst_rect.Width() * dst_rect.Height();
- NotShared<DOMArrayBufferView> buffer_view = AllocateAndValidateDataArray(
- data_size,
- ImageData::GetImageDataStorageFormat(color_settings_->storageFormat()));
- if (!buffer_view)
- return nullptr;
-
- if (src_rect == dst_rect && !flip_y) {
- std::memcpy(buffer_view->BufferBase()->Data(), BufferBase()->Data(),
- data_size * buffer_view->TypeSize());
- } else {
- unsigned data_type_size =
- ImageData::StorageFormatBytesPerPixel(color_settings_->storageFormat());
- int src_index = (dst_rect.X() + dst_rect.Y() * src_rect.Width()) * 4;
- int dst_index = 0;
- if (flip_y)
- dst_index = (dst_rect.Height() - 1) * dst_rect.Width() * 4;
- int src_row_stride = src_rect.Width() * 4;
- int dst_row_stride = flip_y ? -dst_rect.Width() * 4 : dst_rect.Width() * 4;
- for (int i = 0; i < dst_rect.Height(); i++) {
- std::memcpy(static_cast<char*>(buffer_view->BufferBase()->Data()) +
- dst_index / 4 * data_type_size,
- static_cast<char*>(BufferBase()->Data()) +
- src_index / 4 * data_type_size,
- dst_rect.Width() * data_type_size);
- src_index += src_row_stride;
- dst_index += dst_row_stride;
- }
- }
- return MakeGarbageCollected<ImageData>(dst_rect.Size(), buffer_view,
- color_settings_);
+ImageData* ImageData::CreateForTest(const IntSize& size,
+ NotShared<DOMArrayBufferView> buffer_view,
+ const ImageDataSettings* settings) {
+ return MakeGarbageCollected<ImageData>(size, buffer_view, settings);
}
ScriptPromise ImageData::CreateImageBitmap(ScriptState* script_state,
base::Optional<IntRect> crop_rect,
const ImageBitmapOptions* options,
ExceptionState& exception_state) {
- if (BufferBase()->IsDetached()) {
+ if (IsBufferBaseDetached()) {
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
"The source data has been detached.");
return ScriptPromise();
@@ -641,18 +288,6 @@ v8::Local<v8::Object> ImageData::AssociateWithWrapper(
return wrapper;
}
-CanvasColorSpace ImageData::GetCanvasColorSpace(
- const String& color_space_name) {
- if (color_space_name == kSRGBCanvasColorSpaceName)
- return CanvasColorSpace::kSRGB;
- if (color_space_name == kRec2020CanvasColorSpaceName)
- return CanvasColorSpace::kRec2020;
- if (color_space_name == kP3CanvasColorSpaceName)
- return CanvasColorSpace::kP3;
- NOTREACHED();
- return CanvasColorSpace::kSRGB;
-}
-
String ImageData::CanvasColorSpaceName(CanvasColorSpace color_space) {
switch (color_space) {
case CanvasColorSpace::kSRGB:
@@ -679,7 +314,13 @@ ImageDataStorageFormat ImageData::GetImageDataStorageFormat(
return kUint8ClampedArrayStorageFormat;
}
-ImageDataStorageFormat ImageData::GetImageDataStorageFormat() {
+CanvasColorSpace ImageData::GetCanvasColorSpace() const {
+ if (!RuntimeEnabledFeatures::CanvasColorManagementEnabled())
+ return CanvasColorSpace::kSRGB;
+ return CanvasColorSpaceFromName(settings_->colorSpace());
+}
+
+ImageDataStorageFormat ImageData::GetImageDataStorageFormat() const {
if (data_u16_)
return kUint16ArrayStorageFormat;
if (data_f32_)
@@ -713,192 +354,38 @@ unsigned ImageData::StorageFormatBytesPerPixel(
return 1;
}
-NotShared<DOMArrayBufferView>
-ImageData::ConvertPixelsFromCanvasPixelFormatToImageDataStorageFormat(
- ArrayBufferContents& content,
- CanvasPixelFormat pixel_format,
- ImageDataStorageFormat storage_format) {
- if (!content.DataLength())
- return NotShared<DOMArrayBufferView>();
-
- if (pixel_format == CanvasColorParams::GetNativeCanvasPixelFormat() &&
- storage_format == kUint8ClampedArrayStorageFormat) {
- DOMArrayBuffer* array_buffer = DOMArrayBuffer::Create(content);
- return NotShared<DOMArrayBufferView>(DOMUint8ClampedArray::Create(
- array_buffer, 0, array_buffer->ByteLength()));
- }
-
- skcms_PixelFormat src_format = skcms_PixelFormat_RGBA_8888;
- unsigned num_pixels = content.DataLength() / 4;
- if (pixel_format == CanvasPixelFormat::kF16) {
- src_format = skcms_PixelFormat_RGBA_hhhh;
- num_pixels /= 2;
- }
- skcms_AlphaFormat alpha_format = skcms_AlphaFormat_Unpremul;
-
- if (storage_format == kUint8ClampedArrayStorageFormat) {
- NotShared<DOMUint8ClampedArray> u8_array =
- AllocateAndValidateUint8ClampedArray(num_pixels * 4);
- if (!u8_array)
- return NotShared<DOMArrayBufferView>();
- bool data_transform_successful = skcms_Transform(
- content.Data(), src_format, alpha_format, nullptr, u8_array->Data(),
- skcms_PixelFormat_RGBA_8888, alpha_format, nullptr, num_pixels);
- DCHECK(data_transform_successful);
- return u8_array;
- }
-
- if (storage_format == kUint16ArrayStorageFormat) {
- NotShared<DOMUint16Array> u16_array =
- AllocateAndValidateUint16Array(num_pixels * 4);
- if (!u16_array)
- return NotShared<DOMArrayBufferView>();
- bool data_transform_successful = skcms_Transform(
- content.Data(), src_format, alpha_format, nullptr, u16_array->Data(),
- skcms_PixelFormat_RGBA_16161616LE, alpha_format, nullptr, num_pixels);
- DCHECK(data_transform_successful);
- return u16_array;
- }
-
- NotShared<DOMFloat32Array> f32_array =
- AllocateAndValidateFloat32Array(num_pixels * 4);
- if (!f32_array)
- return NotShared<DOMArrayBufferView>();
- bool data_transform_successful = skcms_Transform(
- content.Data(), src_format, alpha_format, nullptr, f32_array->Data(),
- skcms_PixelFormat_RGBA_ffff, alpha_format, nullptr, num_pixels);
- DCHECK(data_transform_successful);
- return f32_array;
-}
-
-DOMArrayBufferBase* ImageData::BufferBase() const {
+bool ImageData::IsBufferBaseDetached() const {
if (data_.IsUint8ClampedArray())
- return data_.GetAsUint8ClampedArray()->BufferBase();
+ return data_.GetAsUint8ClampedArray()->BufferBase()->IsDetached();
if (data_.IsUint16Array())
- return data_.GetAsUint16Array()->BufferBase();
+ return data_.GetAsUint16Array()->BufferBase()->IsDetached();
if (data_.IsFloat32Array())
- return data_.GetAsFloat32Array()->BufferBase();
- return nullptr;
-}
-
-CanvasColorParams ImageData::GetCanvasColorParams() {
- if (!RuntimeEnabledFeatures::CanvasColorManagementEnabled())
- return CanvasColorParams();
- CanvasColorSpace color_space =
- ImageData::GetCanvasColorSpace(color_settings_->colorSpace());
- return CanvasColorParams(
- color_space,
- color_settings_->storageFormat() != kUint8ClampedArrayStorageFormatName
- ? CanvasPixelFormat::kF16
- : CanvasColorParams::GetNativeCanvasPixelFormat(),
- kNonOpaque);
+ return data_.GetAsFloat32Array()->BufferBase()->IsDetached();
+ return false;
}
-SkImageInfo ImageData::GetSkImageInfo() {
- SkColorType color_type = kN32_SkColorType;
- if (data_u16_) {
+SkPixmap ImageData::GetSkPixmap() const {
+ CHECK(!IsBufferBaseDetached());
+ SkColorType color_type = kRGBA_8888_SkColorType;
+ const void* data = nullptr;
+ if (data_.IsUint8ClampedArray()) {
+ color_type = kRGBA_8888_SkColorType;
+ data = data_.GetAsUint8ClampedArray()->Data();
+ } else if (data_.IsUint16Array()) {
color_type = kR16G16B16A16_unorm_SkColorType;
- } else if (data_f32_) {
+ data = data_.GetAsUint16Array()->Data();
+ } else if (data_.IsFloat32Array()) {
color_type = kRGBA_F32_SkColorType;
+ data = data_.GetAsFloat32Array()->Data();
}
- return SkImageInfo::Make(width(), height(), color_type,
- kUnpremul_SkAlphaType);
-}
-
-bool ImageData::ImageDataInCanvasColorSettings(
- CanvasColorSpace canvas_color_space,
- CanvasPixelFormat canvas_pixel_format,
- unsigned char* converted_pixels,
- DataU8ColorType u8_color_type,
- const IntRect* src_rect,
- const AlphaDisposition alpha_disposition) {
- if (data_.IsNull())
- return false;
-
- CanvasColorParams canvas_color_params =
- CanvasColorParams(canvas_color_space, canvas_pixel_format, kNonOpaque);
-
- unsigned char* src_data = static_cast<unsigned char*>(BufferBase()->Data());
-
- ImageDataStorageFormat storage_format = GetImageDataStorageFormat();
-
- skcms_PixelFormat src_pixel_format = skcms_PixelFormat_RGBA_8888;
- if (data_u16_)
- src_pixel_format = skcms_PixelFormat_RGBA_16161616LE;
- else if (data_f32_)
- src_pixel_format = skcms_PixelFormat_RGBA_ffff;
-
- skcms_PixelFormat dst_pixel_format = skcms_PixelFormat_RGBA_8888;
- if (canvas_pixel_format == CanvasPixelFormat::kF16) {
- dst_pixel_format = skcms_PixelFormat_RGBA_hhhh;
- }
-#if SK_PMCOLOR_BYTE_ORDER(B, G, R, A)
- else if (canvas_pixel_format ==
- CanvasColorParams::GetNativeCanvasPixelFormat() &&
- u8_color_type == kN32ColorType) {
- dst_pixel_format = skcms_PixelFormat_BGRA_8888;
- }
-#endif
-
- skcms_AlphaFormat src_alpha_format = skcms_AlphaFormat_Unpremul;
- skcms_AlphaFormat dst_alpha_format = skcms_AlphaFormat_Unpremul;
- if (alpha_disposition == kPremultiplyAlpha)
- dst_alpha_format = skcms_AlphaFormat_PremulAsEncoded;
-
- skcms_ICCProfile* src_profile_ptr = nullptr;
- skcms_ICCProfile* dst_profile_ptr = nullptr;
- skcms_ICCProfile src_profile, dst_profile;
- GetCanvasColorParams().GetSkColorSpace()->toProfile(&src_profile);
- canvas_color_params.GetSkColorSpace()->toProfile(&dst_profile);
- // If the profiles are similar, we better leave them as nullptr, since
- // skcms_Transform() only checks for profile pointer equality for the fast
- // path.
- if (!skcms_ApproximatelyEqualProfiles(&src_profile, &dst_profile)) {
- src_profile_ptr = &src_profile;
- dst_profile_ptr = &dst_profile;
- }
-
- const IntRect* crop_rect = nullptr;
- if (src_rect && *src_rect != IntRect(IntPoint(), Size()))
- crop_rect = src_rect;
-
- // If only a portion of ImageData is required for canvas, we run the transform
- // for every line.
- if (crop_rect) {
- unsigned bytes_per_pixel =
- ImageData::StorageFormatBytesPerPixel(storage_format);
- unsigned src_index =
- (crop_rect->X() + crop_rect->Y() * width()) * bytes_per_pixel;
- unsigned dst_index = 0;
- unsigned src_row_stride = width() * bytes_per_pixel;
- unsigned dst_row_stride =
- crop_rect->Width() * canvas_color_params.BytesPerPixel();
- bool data_transform_successful = true;
-
- for (int i = 0; data_transform_successful && i < crop_rect->Height(); i++) {
- data_transform_successful = skcms_Transform(
- src_data + src_index, src_pixel_format, src_alpha_format,
- src_profile_ptr, converted_pixels + dst_index, dst_pixel_format,
- dst_alpha_format, dst_profile_ptr, crop_rect->Width());
- DCHECK(data_transform_successful);
- src_index += src_row_stride;
- dst_index += dst_row_stride;
- }
- return data_transform_successful;
- }
-
- base::CheckedNumeric<uint32_t> area = size_.Area();
- if (!area.IsValid())
- return false;
- bool data_transform_successful =
- skcms_Transform(src_data, src_pixel_format, src_alpha_format,
- src_profile_ptr, converted_pixels, dst_pixel_format,
- dst_alpha_format, dst_profile_ptr, area.ValueOrDie());
- return data_transform_successful;
+ SkImageInfo info =
+ SkImageInfo::Make(width(), height(), color_type, kUnpremul_SkAlphaType,
+ CanvasColorSpaceToSkColorSpace(GetCanvasColorSpace()));
+ return SkPixmap(info, data, info.minRowBytes());
}
void ImageData::Trace(Visitor* visitor) const {
- visitor->Trace(color_settings_);
+ visitor->Trace(settings_);
visitor->Trace(data_);
visitor->Trace(data_u8_);
visitor->Trace(data_u16_);
@@ -908,8 +395,8 @@ void ImageData::Trace(Visitor* visitor) const {
ImageData::ImageData(const IntSize& size,
NotShared<DOMArrayBufferView> data,
- const ImageDataColorSettings* color_settings)
- : size_(size), color_settings_(ImageDataColorSettings::Create()) {
+ const ImageDataSettings* settings)
+ : size_(size), settings_(ImageDataSettings::Create()) {
DCHECK_GE(size.Width(), 0);
DCHECK_GE(size.Height(), 0);
DCHECK(data);
@@ -918,23 +405,17 @@ ImageData::ImageData(const IntSize& size,
data_u16_.Clear();
data_f32_.Clear();
- if (color_settings) {
- color_settings_->setColorSpace(color_settings->colorSpace());
- color_settings_->setStorageFormat(color_settings->storageFormat());
+ if (settings) {
+ settings_->setColorSpace(settings->colorSpace());
+ settings_->setStorageFormat(settings->storageFormat());
}
ImageDataStorageFormat storage_format =
- GetImageDataStorageFormat(color_settings_->storageFormat());
-
- // TODO (zakerinasab): crbug.com/779570
- // The default color space for ImageData with U16/F32 data should be
- // extended-srgb color space. It is temporarily set to linear-rgb, which is
- // not correct, but fixes crbug.com/779419.
-
+ GetImageDataStorageFormat(settings_->storageFormat());
switch (storage_format) {
case kUint8ClampedArrayStorageFormat:
- DCHECK(data->GetType() ==
- DOMArrayBufferView::ViewType::kTypeUint8Clamped);
+ DCHECK_EQ(data->GetType(),
+ DOMArrayBufferView::ViewType::kTypeUint8Clamped);
data_u8_ = data;
DCHECK(data_u8_);
data_.SetUint8ClampedArray(data_u8_);
@@ -944,7 +425,7 @@ ImageData::ImageData(const IntSize& size,
break;
case kUint16ArrayStorageFormat:
- DCHECK(data->GetType() == DOMArrayBufferView::ViewType::kTypeUint16);
+ DCHECK_EQ(data->GetType(), DOMArrayBufferView::ViewType::kTypeUint16);
data_u16_ = data;
DCHECK(data_u16_);
data_.SetUint16Array(data_u16_);
@@ -954,7 +435,7 @@ ImageData::ImageData(const IntSize& size,
break;
case kFloat32ArrayStorageFormat:
- DCHECK(data->GetType() == DOMArrayBufferView::ViewType::kTypeFloat32);
+ DCHECK_EQ(data->GetType(), DOMArrayBufferView::ViewType::kTypeFloat32);
data_f32_ = data;
DCHECK(data_f32_);
data_.SetFloat32Array(data_f32_);