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

Side by Side Diff: third_party/WebKit/Source/core/html/ImageData.cpp

Issue 2771813003: Prepare ImageData for color managed BaseRenderingContext2D::create/put/get-ImageData (Closed)
Patch Set: Addressing comments Created 3 years, 8 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 unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2008 Apple Inc. All rights reserved. 2 * Copyright (C) 2008 Apple Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions 5 * modification, are permitted provided that the following conditions
6 * are met: 6 * are met:
7 * 7 *
8 * 1. Redistributions of source code must retain the above copyright 8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright 10 * 2. Redistributions in binary form must reproduce the above copyright
(...skipping 17 matching lines...) Expand all
28 28
29 #include "core/html/ImageData.h" 29 #include "core/html/ImageData.h"
30 30
31 #include "bindings/core/v8/ExceptionState.h" 31 #include "bindings/core/v8/ExceptionState.h"
32 #include "bindings/core/v8/V8Uint8ClampedArray.h" 32 #include "bindings/core/v8/V8Uint8ClampedArray.h"
33 #include "core/dom/ExceptionCode.h" 33 #include "core/dom/ExceptionCode.h"
34 #include "core/frame/ImageBitmap.h" 34 #include "core/frame/ImageBitmap.h"
35 #include "core/imagebitmap/ImageBitmapOptions.h" 35 #include "core/imagebitmap/ImageBitmapOptions.h"
36 #include "platform/RuntimeEnabledFeatures.h" 36 #include "platform/RuntimeEnabledFeatures.h"
37 #include "platform/graphics/ColorBehavior.h" 37 #include "platform/graphics/ColorBehavior.h"
38 #include "third_party/skia/include/core/SkColorSpaceXform.h"
38 39
39 namespace blink { 40 namespace blink {
40 41
41 bool RaiseDOMExceptionAndReturnFalse(ExceptionState* exceptionState, 42 bool RaiseDOMExceptionAndReturnFalse(ExceptionState* exceptionState,
42 ExceptionCode exceptionCode, 43 ExceptionCode exceptionCode,
43 const char* message) { 44 const char* message) {
44 if (exceptionState) 45 if (exceptionState)
45 exceptionState->throwDOMException(exceptionCode, message); 46 exceptionState->throwDOMException(exceptionCode, message);
46 return false; 47 return false;
47 } 48 }
48 49
49 bool ImageData::validateConstructorArguments(const unsigned& paramFlags, 50 bool ImageData::validateConstructorArguments(
50 const IntSize* size, 51 const unsigned& paramFlags,
51 const unsigned& width, 52 const IntSize* size,
52 const unsigned& height, 53 const unsigned& width,
53 const DOMArrayBufferView* data, 54 const unsigned& height,
54 ExceptionState* exceptionState) { 55 const DOMArrayBufferView* data,
56 const ImageDataColorSettings* colorSettings,
57 ExceptionState* exceptionState) {
55 // We accept all the combinations of colorSpace and storageFormat in an 58 // We accept all the combinations of colorSpace and storageFormat in an
56 // ImageDataColorSettings to be stored in an ImageData. Therefore, we don't 59 // ImageDataColorSettings to be stored in an ImageData. Therefore, we don't
57 // check the color settings in this function. 60 // check the color settings in this function.
58 61
59 if ((paramFlags & kParamWidth) && !width) { 62 if ((paramFlags & kParamWidth) && !width) {
60 return RaiseDOMExceptionAndReturnFalse( 63 return RaiseDOMExceptionAndReturnFalse(
61 exceptionState, IndexSizeError, 64 exceptionState, IndexSizeError,
62 "The source width is zero or not a number."); 65 "The source width is zero or not a number.");
63 } 66 }
64 67
65 if ((paramFlags & kParamHeight) && !height) { 68 if ((paramFlags & kParamHeight) && !height) {
66 return RaiseDOMExceptionAndReturnFalse( 69 return RaiseDOMExceptionAndReturnFalse(
67 exceptionState, IndexSizeError, 70 exceptionState, IndexSizeError,
68 "The source height is zero or not a number."); 71 "The source height is zero or not a number.");
69 } 72 }
70 73
71 if (paramFlags & (kParamWidth | kParamHeight)) { 74 if (paramFlags & (kParamWidth | kParamHeight)) {
72 CheckedNumeric<unsigned> dataSize = 4; 75 CheckedNumeric<unsigned> dataSize = 4;
76 if (colorSettings) {
77 dataSize *=
78 ImageData::storageFormatDataSize(colorSettings->storageFormat());
79 }
73 dataSize *= width; 80 dataSize *= width;
74 dataSize *= height; 81 dataSize *= height;
75 if (!dataSize.IsValid()) 82 if (!dataSize.IsValid())
76 return RaiseDOMExceptionAndReturnFalse( 83 return RaiseDOMExceptionAndReturnFalse(
77 exceptionState, IndexSizeError, 84 exceptionState, IndexSizeError,
78 "The requested image size exceeds the supported range."); 85 "The requested image size exceeds the supported range.");
79 } 86 }
80 87
81 unsigned dataLength = 0; 88 unsigned dataLength = 0;
82 if (paramFlags & kParamData) { 89 if (paramFlags & kParamData) {
83 DCHECK(data); 90 DCHECK(data);
84 switch (data->type()) { 91 if (data->type() != DOMArrayBufferView::ViewType::TypeUint8Clamped &&
85 case DOMArrayBufferView::ViewType::TypeUint8Clamped: 92 data->type() != DOMArrayBufferView::ViewType::TypeUint16 &&
86 dataLength = data->view()->byteLength(); 93 data->type() != DOMArrayBufferView::ViewType::TypeFloat32) {
87 break; 94 return RaiseDOMExceptionAndReturnFalse(
88 case DOMArrayBufferView::ViewType::TypeUint16: 95 exceptionState, NotSupportedError,
89 dataLength = data->view()->byteLength() / 2; 96 "The input data type is not supported.");
90 break;
91 case DOMArrayBufferView::ViewType::TypeFloat32:
92 dataLength = data->view()->byteLength() / 4;
93 break;
94 default:
95 return RaiseDOMExceptionAndReturnFalse(
96 exceptionState, NotSupportedError,
97 "The input data type is not supported.");
98 } 97 }
99 98
100 if (!dataLength) { 99 if (!data->byteLength()) {
101 return RaiseDOMExceptionAndReturnFalse( 100 return RaiseDOMExceptionAndReturnFalse(
102 exceptionState, IndexSizeError, "The input data has zero elements."); 101 exceptionState, IndexSizeError, "The input data has zero elements.");
103 } 102 }
104 103
104 dataLength = data->byteLength() / data->typeSize();
105 if (dataLength % 4) { 105 if (dataLength % 4) {
106 return RaiseDOMExceptionAndReturnFalse( 106 return RaiseDOMExceptionAndReturnFalse(
107 exceptionState, IndexSizeError, 107 exceptionState, IndexSizeError,
108 "The input data length is not a multiple of 4."); 108 "The input data length is not a multiple of 4.");
109 } 109 }
110 110
111 if ((paramFlags & kParamWidth) && (dataLength / 4) % width) { 111 if ((paramFlags & kParamWidth) && (dataLength / 4) % width) {
112 return RaiseDOMExceptionAndReturnFalse( 112 return RaiseDOMExceptionAndReturnFalse(
113 exceptionState, IndexSizeError, 113 exceptionState, IndexSizeError,
114 "The input data length is not a multiple of (4 * width)."); 114 "The input data length is not a multiple of (4 * width).");
(...skipping 24 matching lines...) Expand all
139 } 139 }
140 140
141 DOMArrayBufferView* ImageData::allocateAndValidateDataArray( 141 DOMArrayBufferView* ImageData::allocateAndValidateDataArray(
142 const unsigned& length, 142 const unsigned& length,
143 ImageDataStorageFormat storageFormat, 143 ImageDataStorageFormat storageFormat,
144 ExceptionState* exceptionState) { 144 ExceptionState* exceptionState) {
145 if (!length) 145 if (!length)
146 return nullptr; 146 return nullptr;
147 147
148 DOMArrayBufferView* dataArray = nullptr; 148 DOMArrayBufferView* dataArray = nullptr;
149 unsigned dataLength = 0;
150 unsigned dataItemLength = 1;
151 switch (storageFormat) { 149 switch (storageFormat) {
152 case kUint8ClampedArrayStorageFormat: 150 case kUint8ClampedArrayStorageFormat:
153 dataArray = DOMUint8ClampedArray::createOrNull(length); 151 dataArray = DOMUint8ClampedArray::createOrNull(length);
154 break; 152 break;
155 case kUint16ArrayStorageFormat: 153 case kUint16ArrayStorageFormat:
156 dataArray = DOMUint16Array::createOrNull(length); 154 dataArray = DOMUint16Array::createOrNull(length);
157 dataItemLength = 2;
158 break; 155 break;
159 case kFloat32ArrayStorageFormat: 156 case kFloat32ArrayStorageFormat:
160 dataArray = DOMFloat32Array::createOrNull(length); 157 dataArray = DOMFloat32Array::createOrNull(length);
161 dataItemLength = 4;
162 break; 158 break;
163 default: 159 default:
164 NOTREACHED(); 160 NOTREACHED();
165 } 161 }
166 162
167 if (dataArray) 163 if (!dataArray || length != dataArray->byteLength() / dataArray->typeSize()) {
168 dataLength = dataArray->view()->byteLength() / dataItemLength;
169
170 if (!dataArray || length != dataLength) {
171 if (exceptionState) 164 if (exceptionState)
172 exceptionState->throwDOMException(V8RangeError, 165 exceptionState->throwDOMException(V8RangeError,
173 "Out of memory at ImageData creation"); 166 "Out of memory at ImageData creation");
174 return nullptr; 167 return nullptr;
175 } 168 }
176 169
177 return dataArray; 170 return dataArray;
178 } 171 }
179 172
180 ImageData* ImageData::create(const IntSize& size) { 173 DOMUint8ClampedArray* ImageData::allocateAndValidateUint8ClampedArray(
181 if (!ImageData::validateConstructorArguments(kParamSize, &size)) 174 const unsigned& length,
175 ExceptionState* exceptionState) {
176 DOMArrayBufferView* bufferView = allocateAndValidateDataArray(
177 length, kUint8ClampedArrayStorageFormat, exceptionState);
178 if (!bufferView)
182 return nullptr; 179 return nullptr;
183 DOMArrayBufferView* byteArray = 180 DOMUint8ClampedArray* u8Array = const_cast<DOMUint8ClampedArray*>(
184 allocateAndValidateDataArray(4 * static_cast<unsigned>(size.width()) * 181 static_cast<const DOMUint8ClampedArray*>(bufferView));
185 static_cast<unsigned>(size.height()), 182 DCHECK(u8Array);
186 kUint8ClampedArrayStorageFormat); 183 return u8Array;
187 return byteArray ? new ImageData(size, byteArray) : nullptr;
188 } 184 }
189 185
190 // This function accepts size (0, 0) and always returns the ImageData in 186 DOMUint16Array* ImageData::allocateAndValidateUint16Array(
191 // "srgb" color space and "uint8" storage format. 187 const unsigned& length,
192 ImageData* ImageData::createForTest(const IntSize& size) { 188 ExceptionState* exceptionState) {
193 CheckedNumeric<unsigned> dataSize = 4; 189 DOMArrayBufferView* bufferView = allocateAndValidateDataArray(
194 dataSize *= size.width(); 190 length, kUint16ArrayStorageFormat, exceptionState);
195 dataSize *= size.height(); 191 if (!bufferView)
196 if (!dataSize.IsValid())
197 return nullptr; 192 return nullptr;
193 DOMUint16Array* u16Array = const_cast<DOMUint16Array*>(
194 static_cast<const DOMUint16Array*>(bufferView));
195 DCHECK(u16Array);
196 return u16Array;
197 }
198 198
199 DOMUint8ClampedArray* byteArray = 199 DOMFloat32Array* ImageData::allocateAndValidateFloat32Array(
200 DOMUint8ClampedArray::createOrNull(dataSize.ValueOrDie()); 200 const unsigned& length,
201 if (!byteArray) 201 ExceptionState* exceptionState) {
202 DOMArrayBufferView* bufferView = allocateAndValidateDataArray(
203 length, kFloat32ArrayStorageFormat, exceptionState);
204 if (!bufferView)
202 return nullptr; 205 return nullptr;
203 206 DOMFloat32Array* f32Array = const_cast<DOMFloat32Array*>(
204 return new ImageData(size, byteArray); 207 static_cast<const DOMFloat32Array*>(bufferView));
208 DCHECK(f32Array);
209 return f32Array;
205 } 210 }
206 211
207 ImageData* ImageData::create(const IntSize& size, 212 ImageData* ImageData::create(const IntSize& size,
208 DOMUint8ClampedArray* byteArray) { 213 const ImageDataColorSettings* colorSettings) {
214 if (!ImageData::validateConstructorArguments(kParamSize, &size, 0, 0, nullptr,
215 colorSettings))
216 return nullptr;
217 ImageDataStorageFormat storageFormat = kUint8ClampedArrayStorageFormat;
218 if (colorSettings) {
219 storageFormat =
220 ImageData::imageDataStorageFormat(colorSettings->storageFormat());
221 }
222 DOMArrayBufferView* dataArray =
223 allocateAndValidateDataArray(4 * static_cast<unsigned>(size.width()) *
224 static_cast<unsigned>(size.height()),
225 storageFormat);
226 return dataArray ? new ImageData(size, dataArray, colorSettings) : nullptr;
227 }
228
229 ImageData* ImageData::create(const IntSize& size,
230 DOMArrayBufferView* dataArray,
231 const ImageDataColorSettings* colorSettings) {
209 if (!ImageData::validateConstructorArguments(kParamSize | kParamData, &size, 232 if (!ImageData::validateConstructorArguments(kParamSize | kParamData, &size,
210 0, 0, byteArray)) 233 0, 0, dataArray, colorSettings))
211 return nullptr; 234 return nullptr;
212 235 return new ImageData(size, dataArray, colorSettings);
213 return new ImageData(size, byteArray);
214 } 236 }
215 237
216 ImageData* ImageData::create(unsigned width, 238 ImageData* ImageData::create(unsigned width,
217 unsigned height, 239 unsigned height,
218 ExceptionState& exceptionState) { 240 ExceptionState& exceptionState) {
219 if (!ImageData::validateConstructorArguments(kParamWidth | kParamHeight, 241 if (!ImageData::validateConstructorArguments(kParamWidth | kParamHeight,
220 nullptr, width, height, nullptr, 242 nullptr, width, height, nullptr,
221 &exceptionState)) 243 nullptr, &exceptionState))
222 return nullptr; 244 return nullptr;
223 245
224 DOMArrayBufferView* byteArray = allocateAndValidateDataArray( 246 DOMArrayBufferView* byteArray = allocateAndValidateDataArray(
225 4 * width * height, kUint8ClampedArrayStorageFormat, &exceptionState); 247 4 * width * height, kUint8ClampedArrayStorageFormat, &exceptionState);
226 return byteArray ? new ImageData(IntSize(width, height), byteArray) : nullptr; 248 return byteArray ? new ImageData(IntSize(width, height), byteArray) : nullptr;
227 } 249 }
228 250
229 ImageData* ImageData::create(DOMUint8ClampedArray* data, 251 ImageData* ImageData::create(DOMUint8ClampedArray* data,
230 unsigned width, 252 unsigned width,
231 ExceptionState& exceptionState) { 253 ExceptionState& exceptionState) {
232 if (!ImageData::validateConstructorArguments( 254 if (!ImageData::validateConstructorArguments(kParamData | kParamWidth,
233 kParamData | kParamWidth, nullptr, width, 0, data, &exceptionState)) 255 nullptr, width, 0, data, nullptr,
256 &exceptionState))
234 return nullptr; 257 return nullptr;
235 258
236 unsigned height = data->length() / (width * 4); 259 unsigned height = data->length() / (width * 4);
237 return new ImageData(IntSize(width, height), data); 260 return new ImageData(IntSize(width, height), data);
238 } 261 }
239 262
240 ImageData* ImageData::create(DOMUint8ClampedArray* data, 263 ImageData* ImageData::create(DOMUint8ClampedArray* data,
241 unsigned width, 264 unsigned width,
242 unsigned height, 265 unsigned height,
243 ExceptionState& exceptionState) { 266 ExceptionState& exceptionState) {
244 if (!ImageData::validateConstructorArguments( 267 if (!ImageData::validateConstructorArguments(
245 kParamData | kParamWidth | kParamHeight, nullptr, width, height, data, 268 kParamData | kParamWidth | kParamHeight, nullptr, width, height, data,
246 &exceptionState)) 269 nullptr, &exceptionState))
247 return nullptr; 270 return nullptr;
248 271
249 return new ImageData(IntSize(width, height), data); 272 return new ImageData(IntSize(width, height), data);
250 } 273 }
251 274
252 ImageData* ImageData::createImageData( 275 ImageData* ImageData::createImageData(
253 unsigned width, 276 unsigned width,
254 unsigned height, 277 unsigned height,
255 const ImageDataColorSettings& colorSettings, 278 const ImageDataColorSettings& colorSettings,
256 ExceptionState& exceptionState) { 279 ExceptionState& exceptionState) {
257 if (!ImageData::validateConstructorArguments(kParamWidth | kParamHeight, 280 if (!ImageData::validateConstructorArguments(kParamWidth | kParamHeight,
258 nullptr, width, height, nullptr, 281 nullptr, width, height, nullptr,
259 &exceptionState)) 282 &colorSettings, &exceptionState))
260 return nullptr; 283 return nullptr;
261 284
262 ImageDataStorageFormat storageFormat = 285 ImageDataStorageFormat storageFormat =
263 ImageData::getImageDataStorageFormat(colorSettings.storageFormat()); 286 ImageData::imageDataStorageFormat(colorSettings.storageFormat());
264 DOMArrayBufferView* bufferView = allocateAndValidateDataArray( 287 DOMArrayBufferView* bufferView = allocateAndValidateDataArray(
265 4 * width * height, storageFormat, &exceptionState); 288 4 * width * height, storageFormat, &exceptionState);
266 289
267 if (!bufferView) 290 if (!bufferView)
268 return nullptr; 291 return nullptr;
269 292
270 return new ImageData(IntSize(width, height), bufferView, &colorSettings); 293 return new ImageData(IntSize(width, height), bufferView, &colorSettings);
271 } 294 }
272 295
273 ImageData* ImageData::createImageData( 296 ImageData* ImageData::createImageData(ImageDataArray& data,
274 ImageDataArray& data, 297 unsigned width,
275 unsigned width, 298 unsigned height,
276 unsigned height, 299 ImageDataColorSettings& colorSettings,
277 const ImageDataColorSettings& colorSettings, 300 ExceptionState& exceptionState) {
278 ExceptionState& exceptionState) {
279 DOMArrayBufferView* bufferView = nullptr; 301 DOMArrayBufferView* bufferView = nullptr;
280 if (data.isUint8ClampedArray()) 302 // When pixels data is provided, we need to override the storage format of
303 // ImageDataColorSettings with the one that matches the data type of the
304 // pixels.
305 String storageFormatName;
306
307 if (data.isUint8ClampedArray()) {
281 bufferView = data.getAsUint8ClampedArray(); 308 bufferView = data.getAsUint8ClampedArray();
282 else if (data.isUint16Array()) 309 storageFormatName = kUint8ClampedArrayStorageFormatName;
310 } else if (data.isUint16Array()) {
283 bufferView = data.getAsUint16Array(); 311 bufferView = data.getAsUint16Array();
284 else if (data.isFloat32Array()) 312 storageFormatName = kUint16ArrayStorageFormatName;
313 } else if (data.isFloat32Array()) {
285 bufferView = data.getAsFloat32Array(); 314 bufferView = data.getAsFloat32Array();
286 else 315 storageFormatName = kFloat32ArrayStorageFormatName;
316 } else {
287 NOTREACHED(); 317 NOTREACHED();
318 }
319
320 if (storageFormatName != colorSettings.storageFormat())
321 colorSettings.setStorageFormat(storageFormatName);
288 322
289 if (!ImageData::validateConstructorArguments( 323 if (!ImageData::validateConstructorArguments(
290 kParamData | kParamWidth | kParamHeight, nullptr, width, height, 324 kParamData | kParamWidth | kParamHeight, nullptr, width, height,
291 bufferView, &exceptionState)) 325 bufferView, &colorSettings, &exceptionState))
292 return nullptr; 326 return nullptr;
293 327
294 return new ImageData(IntSize(width, height), bufferView, &colorSettings, 328 return new ImageData(IntSize(width, height), bufferView, &colorSettings);
295 kStorageFormatFromBufferType); 329 }
330
331 // This function accepts size (0, 0) and always returns the ImageData in
332 // "srgb" color space and "uint8" storage format.
333 ImageData* ImageData::createForTest(const IntSize& size) {
334 CheckedNumeric<unsigned> dataSize = 4;
335 dataSize *= size.width();
336 dataSize *= size.height();
337 if (!dataSize.IsValid())
338 return nullptr;
339
340 DOMUint8ClampedArray* byteArray =
341 DOMUint8ClampedArray::createOrNull(dataSize.ValueOrDie());
342 if (!byteArray)
343 return nullptr;
344
345 return new ImageData(size, byteArray);
346 }
347
348 // This function is called from unit tests, and all the parameters are supposed
349 // to be validated on the call site.
350 ImageData* ImageData::createForTest(
351 const IntSize& size,
352 DOMArrayBufferView* bufferView,
353 const ImageDataColorSettings* colorSettings) {
354 return new ImageData(size, bufferView, colorSettings);
296 } 355 }
297 356
298 ScriptPromise ImageData::createImageBitmap(ScriptState* scriptState, 357 ScriptPromise ImageData::createImageBitmap(ScriptState* scriptState,
299 EventTarget& eventTarget, 358 EventTarget& eventTarget,
300 Optional<IntRect> cropRect, 359 Optional<IntRect> cropRect,
301 const ImageBitmapOptions& options, 360 const ImageBitmapOptions& options,
302 ExceptionState& exceptionState) { 361 ExceptionState& exceptionState) {
303 if ((cropRect && 362 if ((cropRect &&
304 !ImageBitmap::isSourceSizeValid(cropRect->width(), cropRect->height(), 363 !ImageBitmap::isSourceSizeValid(cropRect->width(), cropRect->height(),
305 exceptionState)) || 364 exceptionState)) ||
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
344 return m_data.get(); 403 return m_data.get();
345 return nullptr; 404 return nullptr;
346 } 405 }
347 406
348 DOMUint8ClampedArray* ImageData::data() { 407 DOMUint8ClampedArray* ImageData::data() {
349 if (m_colorSettings.storageFormat() == kUint8ClampedArrayStorageFormatName) 408 if (m_colorSettings.storageFormat() == kUint8ClampedArrayStorageFormatName)
350 return m_data.get(); 409 return m_data.get();
351 return nullptr; 410 return nullptr;
352 } 411 }
353 412
354 ImageDataStorageFormat ImageData::getImageDataStorageFormat( 413 CanvasColorSpace ImageData::canvasColorSpace(const String& colorSpaceName) {
414 if (colorSpaceName == kLegacyCanvasColorSpaceName)
415 return kLegacyCanvasColorSpace;
416 if (colorSpaceName == kSRGBCanvasColorSpaceName)
417 return kSRGBCanvasColorSpace;
418 if (colorSpaceName == kRec2020CanvasColorSpaceName)
419 return kRec2020CanvasColorSpace;
420 if (colorSpaceName == kP3CanvasColorSpaceName)
421 return kP3CanvasColorSpace;
422 NOTREACHED();
423 return kSRGBCanvasColorSpace;
424 }
425
426 String ImageData::canvasColorSpaceName(const CanvasColorSpace& colorSpace) {
427 switch (colorSpace) {
428 case kSRGBCanvasColorSpace:
429 return kSRGBCanvasColorSpaceName;
430 case kRec2020CanvasColorSpace:
431 return kRec2020CanvasColorSpaceName;
432 case kP3CanvasColorSpace:
433 return kP3CanvasColorSpaceName;
434 default:
435 NOTREACHED();
436 }
437 return kSRGBCanvasColorSpaceName;
438 }
439
440 ImageDataStorageFormat ImageData::imageDataStorageFormat(
355 const String& storageFormatName) { 441 const String& storageFormatName) {
356 if (storageFormatName == kUint8ClampedArrayStorageFormatName) 442 if (storageFormatName == kUint8ClampedArrayStorageFormatName)
357 return kUint8ClampedArrayStorageFormat; 443 return kUint8ClampedArrayStorageFormat;
358 if (storageFormatName == kUint16ArrayStorageFormatName) 444 if (storageFormatName == kUint16ArrayStorageFormatName)
359 return kUint16ArrayStorageFormat; 445 return kUint16ArrayStorageFormat;
360 if (storageFormatName == kFloat32ArrayStorageFormatName) 446 if (storageFormatName == kFloat32ArrayStorageFormatName)
361 return kFloat32ArrayStorageFormat; 447 return kFloat32ArrayStorageFormat;
362 NOTREACHED(); 448 NOTREACHED();
363 return kUint8ClampedArrayStorageFormat; 449 return kUint8ClampedArrayStorageFormat;
364 } 450 }
365 451
452 unsigned ImageData::storageFormatDataSize(const String& storageFormatName) {
453 if (storageFormatName == kUint8ClampedArrayStorageFormatName)
454 return 1;
455 if (storageFormatName == kUint16ArrayStorageFormatName)
456 return 2;
457 if (storageFormatName == kFloat32ArrayStorageFormatName)
458 return 4;
459 NOTREACHED();
460 return 1;
461 }
462
463 DOMFloat32Array* ImageData::convertFloat16ArrayToFloat32Array(
464 const uint16_t* f16Array,
465 unsigned arrayLength) {
466 if (!f16Array || arrayLength <= 0)
467 return nullptr;
468
469 DOMFloat32Array* f32Array = allocateAndValidateFloat32Array(arrayLength);
470 if (!f32Array)
471 return nullptr;
472
473 std::unique_ptr<SkColorSpaceXform> xform =
474 SkColorSpaceXform::New(SkColorSpace::MakeSRGBLinear().get(),
475 SkColorSpace::MakeSRGBLinear().get());
476 xform->apply(SkColorSpaceXform::ColorFormat::kRGBA_F32_ColorFormat,
477 f32Array->data(),
478 SkColorSpaceXform::ColorFormat::kRGBA_F16_ColorFormat, f16Array,
479 arrayLength, SkAlphaType::kUnpremul_SkAlphaType);
480 return f32Array;
481 }
482
483 DOMArrayBufferView*
484 ImageData::convertPixelsFromCanvasPixelFormatToImageDataStorageFormat(
485 WTF::ArrayBufferContents& content,
486 CanvasPixelFormat pixelFormat,
487 ImageDataStorageFormat storageFormat) {
488 if (!content.sizeInBytes())
489 return nullptr;
490
491 // Uint16 is not supported as the storage format for ImageData created from a
492 // canvas
493 if (storageFormat == kUint16ArrayStorageFormat)
494 return nullptr;
495
496 unsigned numPixels = 0;
497 DOMArrayBuffer* arrayBuffer = nullptr;
498 DOMUint8ClampedArray* u8Array = nullptr;
499 DOMFloat32Array* f32Array = nullptr;
500
501 SkColorSpaceXform::ColorFormat srcColorFormat =
502 SkColorSpaceXform::ColorFormat::kRGBA_8888_ColorFormat;
503 SkColorSpaceXform::ColorFormat dstColorFormat =
504 SkColorSpaceXform::ColorFormat::kRGBA_F32_ColorFormat;
505 std::unique_ptr<SkColorSpaceXform> xform =
506 SkColorSpaceXform::New(SkColorSpace::MakeSRGBLinear().get(),
507 SkColorSpace::MakeSRGBLinear().get());
508
509 // To speed up the conversion process, we use SkColorSpaceXform::apply()
510 // wherever appropriate.
511 switch (pixelFormat) {
512 case kRGBA8CanvasPixelFormat:
513 numPixels = content.sizeInBytes();
tasak 2017/04/04 06:30:15 I think, number of pixels = content.sizeInBytes()
zakerinasab 2017/04/04 16:24:47 Good catch. Thanks.
514 switch (storageFormat) {
515 case kUint8ClampedArrayStorageFormat:
516 arrayBuffer = DOMArrayBuffer::create(content);
517 return DOMUint8ClampedArray::create(arrayBuffer, 0,
518 arrayBuffer->byteLength());
519 break;
520 case kFloat32ArrayStorageFormat:
521 f32Array = allocateAndValidateFloat32Array(numPixels);
tasak 2017/04/04 06:30:15 I think, we need [R(float), G(float), B(float), A(
zakerinasab 2017/04/04 16:24:47 Done.
522 if (!f32Array)
523 return nullptr;
524 xform->apply(dstColorFormat, f32Array->data(), srcColorFormat,
525 content.data(), numPixels,
526 SkAlphaType::kUnpremul_SkAlphaType);
527 return f32Array;
528 break;
529 default:
530 NOTREACHED();
531 }
532 break;
533
534 case kF16CanvasPixelFormat:
535 numPixels = content.sizeInBytes() / 2;
536 srcColorFormat = SkColorSpaceXform::ColorFormat::kRGBA_F16_ColorFormat;
537
538 switch (storageFormat) {
539 case kUint8ClampedArrayStorageFormat:
540 u8Array = allocateAndValidateUint8ClampedArray(numPixels);
541 if (!u8Array)
542 return nullptr;
543 dstColorFormat =
544 SkColorSpaceXform::ColorFormat::kRGBA_8888_ColorFormat;
545 xform->apply(dstColorFormat, u8Array->data(), srcColorFormat,
546 content.data(), numPixels,
547 SkAlphaType::kUnpremul_SkAlphaType);
548 return u8Array;
549 break;
550 case kFloat32ArrayStorageFormat:
551 f32Array = allocateAndValidateFloat32Array(numPixels);
552 if (!f32Array)
553 return nullptr;
554 dstColorFormat =
555 SkColorSpaceXform::ColorFormat::kRGBA_F32_ColorFormat;
556 xform->apply(dstColorFormat, f32Array->data(), srcColorFormat,
557 content.data(), numPixels,
558 SkAlphaType::kUnpremul_SkAlphaType);
559 return f32Array;
560 break;
561 default:
562 NOTREACHED();
563 }
564 break;
565
566 default:
567 NOTREACHED();
568 }
569 return nullptr;
570 }
571
366 // For ImageData, the color space is only specified by color settings. 572 // For ImageData, the color space is only specified by color settings.
367 // It cannot have a SkColorSpace. This doesn't mean anything. Fix this. 573 // It cannot have a SkColorSpace. This doesn't mean anything. Fix this.
368 sk_sp<SkColorSpace> ImageData::getSkColorSpace() { 574 sk_sp<SkColorSpace> ImageData::skColorSpace() {
369 if (!RuntimeEnabledFeatures::experimentalCanvasFeaturesEnabled() || 575 if (!RuntimeEnabledFeatures::experimentalCanvasFeaturesEnabled() ||
370 !RuntimeEnabledFeatures::colorCorrectRenderingEnabled()) 576 !RuntimeEnabledFeatures::colorCorrectRenderingEnabled())
371 return nullptr; 577 return nullptr;
372 578
373 return SkColorSpace::MakeSRGB(); 579 return SkColorSpace::MakeSRGB();
374 } 580 }
375 581
582 // This function returns the proper SkColorSpace to color correct the pixels
583 // stored in ImageData before copying to the canvas. For now, it assumes that
584 // both ImageData and canvas use a linear gamma curve.
585 sk_sp<SkColorSpace> ImageData::getSkColorSpace(
586 const CanvasColorSpace& colorSpace,
587 const CanvasPixelFormat& pixelFormat) {
588 switch (colorSpace) {
589 case kLegacyCanvasColorSpace:
590 return (gfx::ColorSpace::CreateSRGB()).ToSkColorSpace();
591 case kSRGBCanvasColorSpace:
592 if (pixelFormat == kF16CanvasPixelFormat)
593 return (gfx::ColorSpace::CreateSCRGBLinear()).ToSkColorSpace();
594 return (gfx::ColorSpace::CreateSRGB()).ToSkColorSpace();
595 case kRec2020CanvasColorSpace:
596 return (gfx::ColorSpace(gfx::ColorSpace::PrimaryID::BT2020,
597 gfx::ColorSpace::TransferID::LINEAR))
598 .ToSkColorSpace();
599 case kP3CanvasColorSpace:
600 return (gfx::ColorSpace(gfx::ColorSpace::PrimaryID::SMPTEST432_1,
601 gfx::ColorSpace::TransferID::LINEAR))
602 .ToSkColorSpace();
603 }
604 NOTREACHED();
605 return nullptr;
606 }
607
608 sk_sp<SkColorSpace> ImageData::getSkColorSpaceForTest(
609 const CanvasColorSpace& colorSpace,
610 const CanvasPixelFormat& pixelFormat) {
611 return getSkColorSpace(colorSpace, pixelFormat);
612 }
613
614 bool ImageData::imageDataInCanvasColorSettings(
615 const CanvasColorSpace& canvasColorSpace,
616 const CanvasPixelFormat& canvasPixelFormat,
617 std::unique_ptr<uint8_t[]>& convertedPixels) {
618 if (!m_data && !m_dataU16 && !m_dataF32)
619 return false;
620
621 // If canvas and image data are both in the same color space and pixel format
622 // is 8-8-8-8, just return the embedded data.
623 CanvasColorSpace imageDataColorSpace =
624 ImageData::canvasColorSpace(m_colorSettings.colorSpace());
625 if (canvasPixelFormat == kRGBA8CanvasPixelFormat &&
626 m_colorSettings.storageFormat() == kUint8ClampedArrayStorageFormatName) {
627 if ((canvasColorSpace == kLegacyCanvasColorSpace ||
628 canvasColorSpace == kSRGBCanvasColorSpace) &&
629 (imageDataColorSpace == kLegacyCanvasColorSpace ||
630 imageDataColorSpace == kSRGBCanvasColorSpace)) {
631 memcpy(convertedPixels.get(), m_data->data(), m_data->length());
632 return true;
633 }
634 }
635
636 // Otherwise, color convert the pixels.
637 unsigned numPixels = m_size.width() * m_size.height();
638 unsigned dataLength = numPixels * 4;
639 void* srcData = nullptr;
640 std::unique_ptr<uint16_t[]> leData;
641 SkColorSpaceXform::ColorFormat srcColorFormat =
642 SkColorSpaceXform::ColorFormat::kRGBA_8888_ColorFormat;
643 if (m_data) {
644 srcData = static_cast<void*>(m_data->data());
645 DCHECK(srcData);
646 } else if (m_dataU16) {
647 srcData = static_cast<void*>(m_dataU16->data());
648 DCHECK(srcData);
649 // SkColorSpaceXform::apply expects U16 data to be in Big Endian byte
650 // order, while srcData is always Little Endian. As we cannot consume
651 // ImageData here, we change the byte order in a copy.
652 leData.reset(new uint16_t[dataLength]());
653 memcpy(leData.get(), srcData, dataLength * 2);
654 uint16_t swapValue = 0;
655 for (unsigned i = 0; i < dataLength; i++) {
656 swapValue = leData[i];
657 leData[i] = swapValue >> 8 | swapValue << 8;
658 }
659 srcData = static_cast<void*>(leData.get());
660 DCHECK(srcData);
661 srcColorFormat = SkColorSpaceXform::ColorFormat::kRGBA_U16_BE_ColorFormat;
662 } else if (m_dataF32) {
663 srcData = static_cast<void*>(m_dataF32->data());
664 DCHECK(srcData);
665 srcColorFormat = SkColorSpaceXform::ColorFormat::kRGBA_F32_ColorFormat;
666 } else {
667 NOTREACHED();
668 }
669
670 sk_sp<SkColorSpace> srcColorSpace = nullptr;
671 if (m_data) {
672 srcColorSpace = ImageData::getSkColorSpace(imageDataColorSpace,
673 kRGBA8CanvasPixelFormat);
674 } else {
675 srcColorSpace =
676 ImageData::getSkColorSpace(imageDataColorSpace, kF16CanvasPixelFormat);
677 }
678
679 sk_sp<SkColorSpace> dstColorSpace =
680 ImageData::getSkColorSpace(canvasColorSpace, canvasPixelFormat);
681
682 SkColorSpaceXform::ColorFormat dstColorFormat =
683 SkColorSpaceXform::ColorFormat::kRGBA_8888_ColorFormat;
684 if (canvasPixelFormat == kF16CanvasPixelFormat)
685 dstColorFormat = SkColorSpaceXform::ColorFormat::kRGBA_F16_ColorFormat;
686
687 if (SkColorSpace::Equals(srcColorSpace.get(), dstColorSpace.get()) &&
688 srcColorFormat == dstColorFormat)
689 return static_cast<unsigned char*>(srcData);
690
691 std::unique_ptr<SkColorSpaceXform> xform =
692 SkColorSpaceXform::New(srcColorSpace.get(), dstColorSpace.get());
693
694 if (!xform->apply(dstColorFormat, convertedPixels.get(), srcColorFormat,
695 srcData, numPixels, SkAlphaType::kUnpremul_SkAlphaType))
696 return false;
697 return true;
698 }
699
376 void ImageData::trace(Visitor* visitor) { 700 void ImageData::trace(Visitor* visitor) {
377 visitor->trace(m_data); 701 visitor->trace(m_data);
378 visitor->trace(m_dataU16); 702 visitor->trace(m_dataU16);
379 visitor->trace(m_dataF32); 703 visitor->trace(m_dataF32);
380 visitor->trace(m_dataUnion); 704 visitor->trace(m_dataUnion);
381 } 705 }
382 706
383 ImageData::ImageData(const IntSize& size, 707 ImageData::ImageData(const IntSize& size,
384 DOMArrayBufferView* data, 708 DOMArrayBufferView* data,
385 const ImageDataColorSettings* colorSettings, 709 const ImageDataColorSettings* colorSettings)
386 StorageFormatSource storageFormatSource)
387 : m_size(size) { 710 : m_size(size) {
388 DCHECK_GE(size.width(), 0); 711 DCHECK_GE(size.width(), 0);
389 DCHECK_GE(size.height(), 0); 712 DCHECK_GE(size.height(), 0);
390 DCHECK(data); 713 DCHECK(data);
391 714
392 m_data = nullptr; 715 m_data = nullptr;
393 m_dataU16 = nullptr; 716 m_dataU16 = nullptr;
394 m_dataF32 = nullptr; 717 m_dataF32 = nullptr;
395 718
396 if (colorSettings) { 719 if (colorSettings) {
397 m_colorSettings.setColorSpace(colorSettings->colorSpace()); 720 m_colorSettings.setColorSpace(colorSettings->colorSpace());
398 m_colorSettings.setStorageFormat(colorSettings->storageFormat()); 721 m_colorSettings.setStorageFormat(colorSettings->storageFormat());
399 } 722 }
400 723
401 // if data is provided through the JS call, override the storage format.
402 if (storageFormatSource == kStorageFormatFromBufferType) {
403 switch (data->type()) {
404 case DOMArrayBufferView::ViewType::TypeUint8Clamped:
405 m_colorSettings.setStorageFormat(kUint8ClampedArrayStorageFormatName);
406 break;
407 case DOMArrayBufferView::ViewType::TypeUint16:
408 m_colorSettings.setStorageFormat(kUint16ArrayStorageFormatName);
409 break;
410 case DOMArrayBufferView::ViewType::TypeFloat32:
411 m_colorSettings.setStorageFormat(kFloat32ArrayStorageFormatName);
412 break;
413 default:
414 NOTREACHED();
415 }
416 }
417
418 ImageDataStorageFormat storageFormat = 724 ImageDataStorageFormat storageFormat =
419 getImageDataStorageFormat(m_colorSettings.storageFormat()); 725 imageDataStorageFormat(m_colorSettings.storageFormat());
420 726
421 switch (storageFormat) { 727 switch (storageFormat) {
422 case kUint8ClampedArrayStorageFormat: 728 case kUint8ClampedArrayStorageFormat:
423 DCHECK(data->type() == DOMArrayBufferView::ViewType::TypeUint8Clamped); 729 DCHECK(data->type() == DOMArrayBufferView::ViewType::TypeUint8Clamped);
424 m_data = const_cast<DOMUint8ClampedArray*>( 730 m_data = const_cast<DOMUint8ClampedArray*>(
425 static_cast<const DOMUint8ClampedArray*>(data)); 731 static_cast<const DOMUint8ClampedArray*>(data));
426 DCHECK(m_data); 732 DCHECK(m_data);
427 m_dataUnion.setUint8ClampedArray(m_data); 733 m_dataUnion.setUint8ClampedArray(m_data);
428 SECURITY_CHECK(static_cast<unsigned>(size.width() * size.height() * 4) <= 734 SECURITY_CHECK(static_cast<unsigned>(size.width() * size.height() * 4) <=
429 m_data->length()); 735 m_data->length());
(...skipping 18 matching lines...) Expand all
448 SECURITY_CHECK(static_cast<unsigned>(size.width() * size.height() * 4) <= 754 SECURITY_CHECK(static_cast<unsigned>(size.width() * size.height() * 4) <=
449 m_dataF32->length()); 755 m_dataF32->length());
450 break; 756 break;
451 757
452 default: 758 default:
453 NOTREACHED(); 759 NOTREACHED();
454 } 760 }
455 } 761 }
456 762
457 } // namespace blink 763 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/html/ImageData.h ('k') | third_party/WebKit/Source/core/html/ImageDataTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698