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

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

Issue 2555213002: Implement color management for ImageData (Closed)
Patch Set: Addressing issues Created 4 years 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 16 matching lines...) Expand all
27 */ 27 */
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 "wtf/CheckedNumeric.h"
38 37
39 namespace blink { 38 namespace blink {
40 39
40 bool ImageData::validateConstructorArguments(const unsigned& paramFlags,
41 const IntSize* size,
42 const unsigned& width,
43 const unsigned& height,
44 const DOMUint8ClampedArray* data,
45 const String* colorSpace,
46 ExceptionState* exceptionState) {
47 return ImageData::validateConstructorArguments<DOMUint8ClampedArray>(
48 paramFlags, size, width, height, data, colorSpace, exceptionState);
49 }
50
51 DOMUint8ClampedArray* ImageData::allocateAndValidateUint8ClampedArray(
52 const unsigned& length,
53 ExceptionState* exceptionState) {
54 return ImageData::allocateAndValidateDataArray<DOMUint8ClampedArray>(
55 length, exceptionState);
56 }
57
41 ImageData* ImageData::create(const IntSize& size) { 58 ImageData* ImageData::create(const IntSize& size) {
59 if (!ImageData::validateConstructorArguments(kParamSize, &size))
60 return nullptr;
61 DOMUint8ClampedArray* byteArray =
62 ImageData::allocateAndValidateUint8ClampedArray(4 * size.width() *
63 size.height());
64 if (!byteArray)
65 return nullptr;
66 return new ImageData(size, byteArray);
67 }
68
69 // This function accepts size (0, 0).
70 ImageData* ImageData::createForTest(const IntSize& size) {
42 CheckedNumeric<unsigned> dataSize = 4; 71 CheckedNumeric<unsigned> dataSize = 4;
43 dataSize *= size.width(); 72 dataSize *= size.width();
44 dataSize *= size.height(); 73 dataSize *= size.height();
45 if (!dataSize.IsValid()) 74 if (!dataSize.IsValid())
46 return nullptr; 75 return nullptr;
47 76
48 DOMUint8ClampedArray* byteArray = 77 DOMUint8ClampedArray* byteArray =
49 DOMUint8ClampedArray::createOrNull(dataSize.ValueOrDie()); 78 DOMUint8ClampedArray::createOrNull(dataSize.ValueOrDie());
50 if (!byteArray) 79 if (!byteArray)
51 return nullptr; 80 return nullptr;
52 81
53 return new ImageData(size, byteArray); 82 return new ImageData(size, byteArray);
54 } 83 }
55 84
56 ImageData* ImageData::create(const IntSize& size, 85 ImageData* ImageData::create(const IntSize& size,
57 DOMUint8ClampedArray* byteArray) { 86 DOMUint8ClampedArray* byteArray) {
58 CheckedNumeric<unsigned> dataSize = 4; 87 if (!ImageData::validateConstructorArguments(kParamSize | kParamData, &size,
59 dataSize *= size.width(); 88 0, 0, byteArray))
60 dataSize *= size.height();
61 if (!dataSize.IsValid())
62 return nullptr; 89 return nullptr;
63
64 if (!dataSize.IsValid() || dataSize.ValueOrDie() > byteArray->length())
65 return nullptr;
66
67 return new ImageData(size, byteArray); 90 return new ImageData(size, byteArray);
68 } 91 }
69 92
70 ImageData* ImageData::create(unsigned width, 93 ImageData* ImageData::create(unsigned width,
71 unsigned height, 94 unsigned height,
72 ExceptionState& exceptionState) { 95 ExceptionState& exceptionState) {
73 if (!width || !height) { 96 if (!ImageData::validateConstructorArguments(kParamWidth | kParamHeight,
74 exceptionState.throwDOMException( 97 nullptr, width, height, nullptr,
75 IndexSizeError, String::format("The source %s is zero or not a number.", 98 nullptr, &exceptionState))
76 width ? "height" : "width"));
77 return nullptr; 99 return nullptr;
78 }
79
80 CheckedNumeric<unsigned> dataSize = 4;
81 dataSize *= width;
82 dataSize *= height;
83 if (!dataSize.IsValid() || static_cast<int>(width) < 0 ||
84 static_cast<int>(height) < 0) {
85 exceptionState.throwDOMException(
86 IndexSizeError,
87 "The requested image size exceeds the supported range.");
88 return nullptr;
89 }
90
91 DOMUint8ClampedArray* byteArray = 100 DOMUint8ClampedArray* byteArray =
92 DOMUint8ClampedArray::createOrNull(dataSize.ValueOrDie()); 101 ImageData::allocateAndValidateUint8ClampedArray(4 * width * height,
93 if (!byteArray) { 102 &exceptionState);
94 exceptionState.throwDOMException(V8Error, 103 return byteArray ? new ImageData(IntSize(width, height), byteArray) : nullptr;
95 "Out of memory at ImageData creation");
96 return nullptr;
97 }
98
99 return new ImageData(IntSize(width, height), byteArray);
100 }
101
102 bool ImageData::validateConstructorArguments(DOMUint8ClampedArray* data,
103 unsigned width,
104 unsigned& lengthInPixels,
105 ExceptionState& exceptionState) {
106 if (!width) {
107 exceptionState.throwDOMException(
108 IndexSizeError, "The source width is zero or not a number.");
109 return false;
110 }
111 DCHECK(data);
112 unsigned length = data->length();
113 if (!length) {
114 exceptionState.throwDOMException(IndexSizeError,
115 "The input data has a zero byte length.");
116 return false;
117 }
118 if (length % 4) {
119 exceptionState.throwDOMException(
120 IndexSizeError, "The input data byte length is not a multiple of 4.");
121 return false;
122 }
123 length /= 4;
124 if (length % width) {
125 exceptionState.throwDOMException(
126 IndexSizeError,
127 "The input data byte length is not a multiple of (4 * width).");
128 return false;
129 }
130 lengthInPixels = length;
131 return true;
132 } 104 }
133 105
134 ImageData* ImageData::create(DOMUint8ClampedArray* data, 106 ImageData* ImageData::create(DOMUint8ClampedArray* data,
135 unsigned width, 107 unsigned width,
136 ExceptionState& exceptionState) { 108 ExceptionState& exceptionState) {
137 unsigned lengthInPixels = 0; 109 if (!ImageData::validateConstructorArguments(kParamData | kParamWidth,
138 if (!validateConstructorArguments(data, width, lengthInPixels, 110 nullptr, width, 0, data, nullptr,
139 exceptionState)) { 111 &exceptionState))
140 DCHECK(exceptionState.hadException());
141 return nullptr; 112 return nullptr;
142 } 113 unsigned height = data->length() / (width * 4);
143 DCHECK_GT(lengthInPixels, 0u);
144 DCHECK_GT(width, 0u);
145 unsigned height = lengthInPixels / width;
146 return new ImageData(IntSize(width, height), data); 114 return new ImageData(IntSize(width, height), data);
147 } 115 }
148 116
149 ImageData* ImageData::create(DOMUint8ClampedArray* data, 117 ImageData* ImageData::create(DOMUint8ClampedArray* data,
150 unsigned width, 118 unsigned width,
151 unsigned height, 119 unsigned height,
152 ExceptionState& exceptionState) { 120 ExceptionState& exceptionState) {
153 unsigned lengthInPixels = 0; 121 if (!ImageData::validateConstructorArguments(
154 if (!validateConstructorArguments(data, width, lengthInPixels, 122 kParamData | kParamWidth | kParamHeight, nullptr, width, height, data,
155 exceptionState)) { 123 nullptr, &exceptionState))
156 DCHECK(exceptionState.hadException());
157 return nullptr; 124 return nullptr;
158 }
159 DCHECK_GT(lengthInPixels, 0u);
160 DCHECK_GT(width, 0u);
161 if (height != lengthInPixels / width) {
162 exceptionState.throwDOMException(
163 IndexSizeError,
164 "The input data byte length is not equal to (4 * width * height).");
165 return nullptr;
166 }
167 return new ImageData(IntSize(width, height), data); 125 return new ImageData(IntSize(width, height), data);
168 } 126 }
169 127
128 ImageDataColorSpace ImageData::getImageDataColorSpace(String colorSpaceName) {
129 if (colorSpaceName == kLegacyImageDataColorSpaceName)
130 return kLegacyImageDataColorSpace;
131 if (colorSpaceName == kSRGBImageDataColorSpaceName)
132 return kSRGBImageDataColorSpace;
133 if (colorSpaceName == kLinearRGBImageDataColorSpaceName)
134 return kLinearRGBImageDataColorSpace;
135 NOTREACHED();
136 return kLegacyImageDataColorSpace;
137 }
138
139 String ImageData::getImageDataColorSpaceName(ImageDataColorSpace colorSpace) {
140 switch (colorSpace) {
141 case kLegacyImageDataColorSpace:
142 return kLegacyImageDataColorSpaceName;
143 case kSRGBImageDataColorSpace:
144 return kSRGBImageDataColorSpaceName;
145 case kLinearRGBImageDataColorSpace:
146 return kLinearRGBImageDataColorSpaceName;
147 }
148 NOTREACHED();
149 return String();
150 }
151
152 ImageData* ImageData::createImageData(unsigned width,
153 unsigned height,
154 String colorSpace,
155 ExceptionState& exceptionState) {
156 if (!ImageData::validateConstructorArguments(
157 kParamWidth | kParamHeight | kParamColorSpace, nullptr, width, height,
158 nullptr, &colorSpace, &exceptionState))
159 return nullptr;
160
161 DOMUint8ClampedArray* byteArray =
162 ImageData::allocateAndValidateUint8ClampedArray(4 * width * height,
163 &exceptionState);
164 return byteArray
165 ? new ImageData(IntSize(width, height), byteArray, colorSpace)
166 : nullptr;
167 }
168
169 ImageData* ImageData::createImageData(DOMUint8ClampedArray* data,
170 unsigned width,
171 String colorSpace,
172 ExceptionState& exceptionState) {
173 if (!ImageData::validateConstructorArguments(
174 kParamData | kParamWidth | kParamColorSpace, nullptr, width, 0, data,
175 &colorSpace, &exceptionState))
176 return nullptr;
177 unsigned height = data->length() / (width * 4);
178 return new ImageData(IntSize(width, height), data, colorSpace);
179 }
180
181 ImageData* ImageData::createImageData(DOMUint8ClampedArray* data,
182 unsigned width,
183 unsigned height,
184 String colorSpace,
185 ExceptionState& exceptionState) {
186 if (!ImageData::validateConstructorArguments(
187 kParamData | kParamWidth | kParamHeight | kParamColorSpace, nullptr,
188 width, height, data, &colorSpace, &exceptionState))
189 return nullptr;
190 return new ImageData(IntSize(width, height), data, colorSpace);
191 }
192
193 // TODO(zakerinasab): Fix this when ImageBitmap color correction code is landed.
194 // Tip: If the source Image Data has a color space, createImageBitmap must
195 // respect this color space even when no color space tag is passed to it.
170 ScriptPromise ImageData::createImageBitmap(ScriptState* scriptState, 196 ScriptPromise ImageData::createImageBitmap(ScriptState* scriptState,
171 EventTarget& eventTarget, 197 EventTarget& eventTarget,
172 Optional<IntRect> cropRect, 198 Optional<IntRect> cropRect,
173 const ImageBitmapOptions& options, 199 const ImageBitmapOptions& options,
174 ExceptionState& exceptionState) { 200 ExceptionState& exceptionState) {
175 if ((cropRect && 201 if ((cropRect &&
176 !ImageBitmap::isSourceSizeValid(cropRect->width(), cropRect->height(), 202 !ImageBitmap::isSourceSizeValid(cropRect->width(), cropRect->height(),
177 exceptionState)) || 203 exceptionState)) ||
178 !ImageBitmap::isSourceSizeValid(bitmapSourceSize().width(), 204 !ImageBitmap::isSourceSizeValid(bitmapSourceSize().width(),
179 bitmapSourceSize().height(), 205 bitmapSourceSize().height(),
(...skipping 24 matching lines...) Expand all
204 v8::Local<v8::Value> pixelArray = toV8(m_data.get(), wrapper, isolate); 230 v8::Local<v8::Value> pixelArray = toV8(m_data.get(), wrapper, isolate);
205 if (pixelArray.IsEmpty() || 231 if (pixelArray.IsEmpty() ||
206 !v8CallBoolean(wrapper->DefineOwnProperty( 232 !v8CallBoolean(wrapper->DefineOwnProperty(
207 isolate->GetCurrentContext(), v8AtomicString(isolate, "data"), 233 isolate->GetCurrentContext(), v8AtomicString(isolate, "data"),
208 pixelArray, v8::ReadOnly))) 234 pixelArray, v8::ReadOnly)))
209 return v8::Local<v8::Object>(); 235 return v8::Local<v8::Object>();
210 } 236 }
211 return wrapper; 237 return wrapper;
212 } 238 }
213 239
214 ImageData::ImageData(const IntSize& size, DOMUint8ClampedArray* byteArray) 240 ImageData::ImageData(const IntSize& size,
215 : m_size(size), m_data(byteArray) { 241 DOMUint8ClampedArray* byteArray,
242 String colorSpaceName)
243 : m_size(size),
244 m_colorSpace(getImageDataColorSpace(colorSpaceName)),
245 m_data(byteArray) {
216 DCHECK_GE(size.width(), 0); 246 DCHECK_GE(size.width(), 0);
217 DCHECK_GE(size.height(), 0); 247 DCHECK_GE(size.height(), 0);
218 SECURITY_CHECK(static_cast<unsigned>(size.width() * size.height() * 4) <= 248 SECURITY_CHECK(static_cast<unsigned>(size.width() * size.height() * 4) <=
219 m_data->length()); 249 m_data->length());
220 } 250 }
221 251
222 } // namespace blink 252 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698