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

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

Issue 2798523002: Revert of Prepare ImageData for color managed BaseRenderingContext2D::create/put/get-ImageData (Closed)
Patch Set: 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"
39 38
40 namespace blink { 39 namespace blink {
41 40
42 bool RaiseDOMExceptionAndReturnFalse(ExceptionState* exceptionState, 41 bool RaiseDOMExceptionAndReturnFalse(ExceptionState* exceptionState,
43 ExceptionCode exceptionCode, 42 ExceptionCode exceptionCode,
44 const char* message) { 43 const char* message) {
45 if (exceptionState) 44 if (exceptionState)
46 exceptionState->throwDOMException(exceptionCode, message); 45 exceptionState->throwDOMException(exceptionCode, message);
47 return false; 46 return false;
48 } 47 }
49 48
50 bool ImageData::validateConstructorArguments( 49 bool ImageData::validateConstructorArguments(const unsigned& paramFlags,
51 const unsigned& paramFlags, 50 const IntSize* size,
52 const IntSize* size, 51 const unsigned& width,
53 const unsigned& width, 52 const unsigned& height,
54 const unsigned& height, 53 const DOMArrayBufferView* data,
55 const DOMArrayBufferView* data, 54 ExceptionState* exceptionState) {
56 const ImageDataColorSettings* colorSettings,
57 ExceptionState* exceptionState) {
58 // We accept all the combinations of colorSpace and storageFormat in an 55 // We accept all the combinations of colorSpace and storageFormat in an
59 // ImageDataColorSettings to be stored in an ImageData. Therefore, we don't 56 // ImageDataColorSettings to be stored in an ImageData. Therefore, we don't
60 // check the color settings in this function. 57 // check the color settings in this function.
61 58
62 if ((paramFlags & kParamWidth) && !width) { 59 if ((paramFlags & kParamWidth) && !width) {
63 return RaiseDOMExceptionAndReturnFalse( 60 return RaiseDOMExceptionAndReturnFalse(
64 exceptionState, IndexSizeError, 61 exceptionState, IndexSizeError,
65 "The source width is zero or not a number."); 62 "The source width is zero or not a number.");
66 } 63 }
67 64
68 if ((paramFlags & kParamHeight) && !height) { 65 if ((paramFlags & kParamHeight) && !height) {
69 return RaiseDOMExceptionAndReturnFalse( 66 return RaiseDOMExceptionAndReturnFalse(
70 exceptionState, IndexSizeError, 67 exceptionState, IndexSizeError,
71 "The source height is zero or not a number."); 68 "The source height is zero or not a number.");
72 } 69 }
73 70
74 if (paramFlags & (kParamWidth | kParamHeight)) { 71 if (paramFlags & (kParamWidth | kParamHeight)) {
75 CheckedNumeric<unsigned> dataSize = 4; 72 CheckedNumeric<unsigned> dataSize = 4;
76 if (colorSettings) {
77 dataSize *=
78 ImageData::storageFormatDataSize(colorSettings->storageFormat());
79 }
80 dataSize *= width; 73 dataSize *= width;
81 dataSize *= height; 74 dataSize *= height;
82 if (!dataSize.IsValid()) 75 if (!dataSize.IsValid())
83 return RaiseDOMExceptionAndReturnFalse( 76 return RaiseDOMExceptionAndReturnFalse(
84 exceptionState, IndexSizeError, 77 exceptionState, IndexSizeError,
85 "The requested image size exceeds the supported range."); 78 "The requested image size exceeds the supported range.");
86 } 79 }
87 80
88 unsigned dataLength = 0; 81 unsigned dataLength = 0;
89 if (paramFlags & kParamData) { 82 if (paramFlags & kParamData) {
90 DCHECK(data); 83 DCHECK(data);
91 if (data->type() != DOMArrayBufferView::ViewType::TypeUint8Clamped && 84 switch (data->type()) {
92 data->type() != DOMArrayBufferView::ViewType::TypeUint16 && 85 case DOMArrayBufferView::ViewType::TypeUint8Clamped:
93 data->type() != DOMArrayBufferView::ViewType::TypeFloat32) { 86 dataLength = data->view()->byteLength();
94 return RaiseDOMExceptionAndReturnFalse( 87 break;
95 exceptionState, NotSupportedError, 88 case DOMArrayBufferView::ViewType::TypeUint16:
96 "The input data type is not supported."); 89 dataLength = data->view()->byteLength() / 2;
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.");
97 } 98 }
98 99
99 if (!data->byteLength()) { 100 if (!dataLength) {
100 return RaiseDOMExceptionAndReturnFalse( 101 return RaiseDOMExceptionAndReturnFalse(
101 exceptionState, IndexSizeError, "The input data has zero elements."); 102 exceptionState, IndexSizeError, "The input data has zero elements.");
102 } 103 }
103 104
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;
149 switch (storageFormat) { 151 switch (storageFormat) {
150 case kUint8ClampedArrayStorageFormat: 152 case kUint8ClampedArrayStorageFormat:
151 dataArray = DOMUint8ClampedArray::createOrNull(length); 153 dataArray = DOMUint8ClampedArray::createOrNull(length);
152 break; 154 break;
153 case kUint16ArrayStorageFormat: 155 case kUint16ArrayStorageFormat:
154 dataArray = DOMUint16Array::createOrNull(length); 156 dataArray = DOMUint16Array::createOrNull(length);
157 dataItemLength = 2;
155 break; 158 break;
156 case kFloat32ArrayStorageFormat: 159 case kFloat32ArrayStorageFormat:
157 dataArray = DOMFloat32Array::createOrNull(length); 160 dataArray = DOMFloat32Array::createOrNull(length);
161 dataItemLength = 4;
158 break; 162 break;
159 default: 163 default:
160 NOTREACHED(); 164 NOTREACHED();
161 } 165 }
162 166
163 if (!dataArray || length != dataArray->byteLength() / dataArray->typeSize()) { 167 if (dataArray)
168 dataLength = dataArray->view()->byteLength() / dataItemLength;
169
170 if (!dataArray || length != dataLength) {
164 if (exceptionState) 171 if (exceptionState)
165 exceptionState->throwDOMException(V8RangeError, 172 exceptionState->throwDOMException(V8RangeError,
166 "Out of memory at ImageData creation"); 173 "Out of memory at ImageData creation");
167 return nullptr; 174 return nullptr;
168 } 175 }
169 176
170 return dataArray; 177 return dataArray;
171 } 178 }
172 179
173 DOMUint8ClampedArray* ImageData::allocateAndValidateUint8ClampedArray( 180 ImageData* ImageData::create(const IntSize& size) {
174 const unsigned& length, 181 if (!ImageData::validateConstructorArguments(kParamSize, &size))
175 ExceptionState* exceptionState) {
176 DOMArrayBufferView* bufferView = allocateAndValidateDataArray(
177 length, kUint8ClampedArrayStorageFormat, exceptionState);
178 if (!bufferView)
179 return nullptr; 182 return nullptr;
180 DOMUint8ClampedArray* u8Array = const_cast<DOMUint8ClampedArray*>( 183 DOMArrayBufferView* byteArray =
181 static_cast<const DOMUint8ClampedArray*>(bufferView)); 184 allocateAndValidateDataArray(4 * static_cast<unsigned>(size.width()) *
182 DCHECK(u8Array); 185 static_cast<unsigned>(size.height()),
183 return u8Array; 186 kUint8ClampedArrayStorageFormat);
187 return byteArray ? new ImageData(size, byteArray) : nullptr;
184 } 188 }
185 189
186 DOMUint16Array* ImageData::allocateAndValidateUint16Array( 190 // This function accepts size (0, 0) and always returns the ImageData in
187 const unsigned& length, 191 // "srgb" color space and "uint8" storage format.
188 ExceptionState* exceptionState) { 192 ImageData* ImageData::createForTest(const IntSize& size) {
189 DOMArrayBufferView* bufferView = allocateAndValidateDataArray( 193 CheckedNumeric<unsigned> dataSize = 4;
190 length, kUint16ArrayStorageFormat, exceptionState); 194 dataSize *= size.width();
191 if (!bufferView) 195 dataSize *= size.height();
196 if (!dataSize.IsValid())
192 return nullptr; 197 return nullptr;
193 DOMUint16Array* u16Array = const_cast<DOMUint16Array*>(
194 static_cast<const DOMUint16Array*>(bufferView));
195 DCHECK(u16Array);
196 return u16Array;
197 }
198 198
199 DOMFloat32Array* ImageData::allocateAndValidateFloat32Array( 199 DOMUint8ClampedArray* byteArray =
200 const unsigned& length, 200 DOMUint8ClampedArray::createOrNull(dataSize.ValueOrDie());
201 ExceptionState* exceptionState) { 201 if (!byteArray)
202 DOMArrayBufferView* bufferView = allocateAndValidateDataArray(
203 length, kFloat32ArrayStorageFormat, exceptionState);
204 if (!bufferView)
205 return nullptr; 202 return nullptr;
206 DOMFloat32Array* f32Array = const_cast<DOMFloat32Array*>( 203
207 static_cast<const DOMFloat32Array*>(bufferView)); 204 return new ImageData(size, byteArray);
208 DCHECK(f32Array);
209 return f32Array;
210 } 205 }
211 206
212 ImageData* ImageData::create(const IntSize& size, 207 ImageData* ImageData::create(const IntSize& size,
213 const ImageDataColorSettings* colorSettings) { 208 DOMUint8ClampedArray* byteArray) {
214 if (!ImageData::validateConstructorArguments(kParamSize, &size, 0, 0, nullptr, 209 if (!ImageData::validateConstructorArguments(kParamSize | kParamData, &size,
215 colorSettings)) 210 0, 0, byteArray))
216 return nullptr; 211 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 212
229 ImageData* ImageData::create(const IntSize& size, 213 return new ImageData(size, byteArray);
230 DOMArrayBufferView* dataArray,
231 const ImageDataColorSettings* colorSettings) {
232 if (!ImageData::validateConstructorArguments(kParamSize | kParamData, &size,
233 0, 0, dataArray, colorSettings))
234 return nullptr;
235 return new ImageData(size, dataArray, colorSettings);
236 } 214 }
237 215
238 ImageData* ImageData::create(unsigned width, 216 ImageData* ImageData::create(unsigned width,
239 unsigned height, 217 unsigned height,
240 ExceptionState& exceptionState) { 218 ExceptionState& exceptionState) {
241 if (!ImageData::validateConstructorArguments(kParamWidth | kParamHeight, 219 if (!ImageData::validateConstructorArguments(kParamWidth | kParamHeight,
242 nullptr, width, height, nullptr, 220 nullptr, width, height, nullptr,
243 nullptr, &exceptionState)) 221 &exceptionState))
244 return nullptr; 222 return nullptr;
245 223
246 DOMArrayBufferView* byteArray = allocateAndValidateDataArray( 224 DOMArrayBufferView* byteArray = allocateAndValidateDataArray(
247 4 * width * height, kUint8ClampedArrayStorageFormat, &exceptionState); 225 4 * width * height, kUint8ClampedArrayStorageFormat, &exceptionState);
248 return byteArray ? new ImageData(IntSize(width, height), byteArray) : nullptr; 226 return byteArray ? new ImageData(IntSize(width, height), byteArray) : nullptr;
249 } 227 }
250 228
251 ImageData* ImageData::create(DOMUint8ClampedArray* data, 229 ImageData* ImageData::create(DOMUint8ClampedArray* data,
252 unsigned width, 230 unsigned width,
253 ExceptionState& exceptionState) { 231 ExceptionState& exceptionState) {
254 if (!ImageData::validateConstructorArguments(kParamData | kParamWidth, 232 if (!ImageData::validateConstructorArguments(
255 nullptr, width, 0, data, nullptr, 233 kParamData | kParamWidth, nullptr, width, 0, data, &exceptionState))
256 &exceptionState))
257 return nullptr; 234 return nullptr;
258 235
259 unsigned height = data->length() / (width * 4); 236 unsigned height = data->length() / (width * 4);
260 return new ImageData(IntSize(width, height), data); 237 return new ImageData(IntSize(width, height), data);
261 } 238 }
262 239
263 ImageData* ImageData::create(DOMUint8ClampedArray* data, 240 ImageData* ImageData::create(DOMUint8ClampedArray* data,
264 unsigned width, 241 unsigned width,
265 unsigned height, 242 unsigned height,
266 ExceptionState& exceptionState) { 243 ExceptionState& exceptionState) {
267 if (!ImageData::validateConstructorArguments( 244 if (!ImageData::validateConstructorArguments(
268 kParamData | kParamWidth | kParamHeight, nullptr, width, height, data, 245 kParamData | kParamWidth | kParamHeight, nullptr, width, height, data,
269 nullptr, &exceptionState)) 246 &exceptionState))
270 return nullptr; 247 return nullptr;
271 248
272 return new ImageData(IntSize(width, height), data); 249 return new ImageData(IntSize(width, height), data);
273 } 250 }
274 251
275 ImageData* ImageData::createImageData( 252 ImageData* ImageData::createImageData(
276 unsigned width, 253 unsigned width,
277 unsigned height, 254 unsigned height,
278 const ImageDataColorSettings& colorSettings, 255 const ImageDataColorSettings& colorSettings,
279 ExceptionState& exceptionState) { 256 ExceptionState& exceptionState) {
280 if (!ImageData::validateConstructorArguments(kParamWidth | kParamHeight, 257 if (!ImageData::validateConstructorArguments(kParamWidth | kParamHeight,
281 nullptr, width, height, nullptr, 258 nullptr, width, height, nullptr,
282 &colorSettings, &exceptionState)) 259 &exceptionState))
283 return nullptr; 260 return nullptr;
284 261
285 ImageDataStorageFormat storageFormat = 262 ImageDataStorageFormat storageFormat =
286 ImageData::imageDataStorageFormat(colorSettings.storageFormat()); 263 ImageData::getImageDataStorageFormat(colorSettings.storageFormat());
287 DOMArrayBufferView* bufferView = allocateAndValidateDataArray( 264 DOMArrayBufferView* bufferView = allocateAndValidateDataArray(
288 4 * width * height, storageFormat, &exceptionState); 265 4 * width * height, storageFormat, &exceptionState);
289 266
290 if (!bufferView) 267 if (!bufferView)
291 return nullptr; 268 return nullptr;
292 269
293 return new ImageData(IntSize(width, height), bufferView, &colorSettings); 270 return new ImageData(IntSize(width, height), bufferView, &colorSettings);
294 } 271 }
295 272
296 ImageData* ImageData::createImageData(ImageDataArray& data, 273 ImageData* ImageData::createImageData(
297 unsigned width, 274 ImageDataArray& data,
298 unsigned height, 275 unsigned width,
299 ImageDataColorSettings& colorSettings, 276 unsigned height,
300 ExceptionState& exceptionState) { 277 const ImageDataColorSettings& colorSettings,
278 ExceptionState& exceptionState) {
301 DOMArrayBufferView* bufferView = nullptr; 279 DOMArrayBufferView* bufferView = nullptr;
302 // When pixels data is provided, we need to override the storage format of 280 if (data.isUint8ClampedArray())
303 // ImageDataColorSettings with the one that matches the data type of the
304 // pixels.
305 String storageFormatName;
306
307 if (data.isUint8ClampedArray()) {
308 bufferView = data.getAsUint8ClampedArray(); 281 bufferView = data.getAsUint8ClampedArray();
309 storageFormatName = kUint8ClampedArrayStorageFormatName; 282 else if (data.isUint16Array())
310 } else if (data.isUint16Array()) {
311 bufferView = data.getAsUint16Array(); 283 bufferView = data.getAsUint16Array();
312 storageFormatName = kUint16ArrayStorageFormatName; 284 else if (data.isFloat32Array())
313 } else if (data.isFloat32Array()) {
314 bufferView = data.getAsFloat32Array(); 285 bufferView = data.getAsFloat32Array();
315 storageFormatName = kFloat32ArrayStorageFormatName; 286 else
316 } else {
317 NOTREACHED(); 287 NOTREACHED();
318 }
319
320 if (storageFormatName != colorSettings.storageFormat())
321 colorSettings.setStorageFormat(storageFormatName);
322 288
323 if (!ImageData::validateConstructorArguments( 289 if (!ImageData::validateConstructorArguments(
324 kParamData | kParamWidth | kParamHeight, nullptr, width, height, 290 kParamData | kParamWidth | kParamHeight, nullptr, width, height,
325 bufferView, &colorSettings, &exceptionState)) 291 bufferView, &exceptionState))
326 return nullptr; 292 return nullptr;
327 293
328 return new ImageData(IntSize(width, height), bufferView, &colorSettings); 294 return new ImageData(IntSize(width, height), bufferView, &colorSettings,
329 } 295 kStorageFormatFromBufferType);
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);
355 } 296 }
356 297
357 ScriptPromise ImageData::createImageBitmap(ScriptState* scriptState, 298 ScriptPromise ImageData::createImageBitmap(ScriptState* scriptState,
358 EventTarget& eventTarget, 299 EventTarget& eventTarget,
359 Optional<IntRect> cropRect, 300 Optional<IntRect> cropRect,
360 const ImageBitmapOptions& options, 301 const ImageBitmapOptions& options,
361 ExceptionState& exceptionState) { 302 ExceptionState& exceptionState) {
362 if ((cropRect && 303 if ((cropRect &&
363 !ImageBitmap::isSourceSizeValid(cropRect->width(), cropRect->height(), 304 !ImageBitmap::isSourceSizeValid(cropRect->width(), cropRect->height(),
364 exceptionState)) || 305 exceptionState)) ||
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
403 return m_data.get(); 344 return m_data.get();
404 return nullptr; 345 return nullptr;
405 } 346 }
406 347
407 DOMUint8ClampedArray* ImageData::data() { 348 DOMUint8ClampedArray* ImageData::data() {
408 if (m_colorSettings.storageFormat() == kUint8ClampedArrayStorageFormatName) 349 if (m_colorSettings.storageFormat() == kUint8ClampedArrayStorageFormatName)
409 return m_data.get(); 350 return m_data.get();
410 return nullptr; 351 return nullptr;
411 } 352 }
412 353
413 CanvasColorSpace ImageData::canvasColorSpace(const String& colorSpaceName) { 354 ImageDataStorageFormat ImageData::getImageDataStorageFormat(
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(
441 const String& storageFormatName) { 355 const String& storageFormatName) {
442 if (storageFormatName == kUint8ClampedArrayStorageFormatName) 356 if (storageFormatName == kUint8ClampedArrayStorageFormatName)
443 return kUint8ClampedArrayStorageFormat; 357 return kUint8ClampedArrayStorageFormat;
444 if (storageFormatName == kUint16ArrayStorageFormatName) 358 if (storageFormatName == kUint16ArrayStorageFormatName)
445 return kUint16ArrayStorageFormat; 359 return kUint16ArrayStorageFormat;
446 if (storageFormatName == kFloat32ArrayStorageFormatName) 360 if (storageFormatName == kFloat32ArrayStorageFormatName)
447 return kFloat32ArrayStorageFormat; 361 return kFloat32ArrayStorageFormat;
448 NOTREACHED(); 362 NOTREACHED();
449 return kUint8ClampedArrayStorageFormat; 363 return kUint8ClampedArrayStorageFormat;
450 } 364 }
451 365
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();
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);
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
572 // For ImageData, the color space is only specified by color settings. 366 // For ImageData, the color space is only specified by color settings.
573 // It cannot have a SkColorSpace. This doesn't mean anything. Fix this. 367 // It cannot have a SkColorSpace. This doesn't mean anything. Fix this.
574 sk_sp<SkColorSpace> ImageData::skColorSpace() { 368 sk_sp<SkColorSpace> ImageData::getSkColorSpace() {
575 if (!RuntimeEnabledFeatures::experimentalCanvasFeaturesEnabled() || 369 if (!RuntimeEnabledFeatures::experimentalCanvasFeaturesEnabled() ||
576 !RuntimeEnabledFeatures::colorCorrectRenderingEnabled()) 370 !RuntimeEnabledFeatures::colorCorrectRenderingEnabled())
577 return nullptr; 371 return nullptr;
578 372
579 return SkColorSpace::MakeSRGB(); 373 return SkColorSpace::MakeSRGB();
580 } 374 }
581 375
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
700 void ImageData::trace(Visitor* visitor) { 376 void ImageData::trace(Visitor* visitor) {
701 visitor->trace(m_data); 377 visitor->trace(m_data);
702 visitor->trace(m_dataU16); 378 visitor->trace(m_dataU16);
703 visitor->trace(m_dataF32); 379 visitor->trace(m_dataF32);
704 visitor->trace(m_dataUnion); 380 visitor->trace(m_dataUnion);
705 } 381 }
706 382
707 ImageData::ImageData(const IntSize& size, 383 ImageData::ImageData(const IntSize& size,
708 DOMArrayBufferView* data, 384 DOMArrayBufferView* data,
709 const ImageDataColorSettings* colorSettings) 385 const ImageDataColorSettings* colorSettings,
386 StorageFormatSource storageFormatSource)
710 : m_size(size) { 387 : m_size(size) {
711 DCHECK_GE(size.width(), 0); 388 DCHECK_GE(size.width(), 0);
712 DCHECK_GE(size.height(), 0); 389 DCHECK_GE(size.height(), 0);
713 DCHECK(data); 390 DCHECK(data);
714 391
715 m_data = nullptr; 392 m_data = nullptr;
716 m_dataU16 = nullptr; 393 m_dataU16 = nullptr;
717 m_dataF32 = nullptr; 394 m_dataF32 = nullptr;
718 395
719 if (colorSettings) { 396 if (colorSettings) {
720 m_colorSettings.setColorSpace(colorSettings->colorSpace()); 397 m_colorSettings.setColorSpace(colorSettings->colorSpace());
721 m_colorSettings.setStorageFormat(colorSettings->storageFormat()); 398 m_colorSettings.setStorageFormat(colorSettings->storageFormat());
722 } 399 }
723 400
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
724 ImageDataStorageFormat storageFormat = 418 ImageDataStorageFormat storageFormat =
725 imageDataStorageFormat(m_colorSettings.storageFormat()); 419 getImageDataStorageFormat(m_colorSettings.storageFormat());
726 420
727 switch (storageFormat) { 421 switch (storageFormat) {
728 case kUint8ClampedArrayStorageFormat: 422 case kUint8ClampedArrayStorageFormat:
729 DCHECK(data->type() == DOMArrayBufferView::ViewType::TypeUint8Clamped); 423 DCHECK(data->type() == DOMArrayBufferView::ViewType::TypeUint8Clamped);
730 m_data = const_cast<DOMUint8ClampedArray*>( 424 m_data = const_cast<DOMUint8ClampedArray*>(
731 static_cast<const DOMUint8ClampedArray*>(data)); 425 static_cast<const DOMUint8ClampedArray*>(data));
732 DCHECK(m_data); 426 DCHECK(m_data);
733 m_dataUnion.setUint8ClampedArray(m_data); 427 m_dataUnion.setUint8ClampedArray(m_data);
734 SECURITY_CHECK(static_cast<unsigned>(size.width() * size.height() * 4) <= 428 SECURITY_CHECK(static_cast<unsigned>(size.width() * size.height() * 4) <=
735 m_data->length()); 429 m_data->length());
(...skipping 18 matching lines...) Expand all
754 SECURITY_CHECK(static_cast<unsigned>(size.width() * size.height() * 4) <= 448 SECURITY_CHECK(static_cast<unsigned>(size.width() * size.height() * 4) <=
755 m_dataF32->length()); 449 m_dataF32->length());
756 break; 450 break;
757 451
758 default: 452 default:
759 NOTREACHED(); 453 NOTREACHED();
760 } 454 }
761 } 455 }
762 456
763 } // namespace blink 457 } // 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