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

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

Issue 2555213002: Implement color management for ImageData (Closed)
Patch Set: Addressing comments. 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
11 * notice, this list of conditions and the following disclaimer in the 11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution. 12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14 * its contributors may be used to endorse or promote products derived 14 * its contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission. 15 * from this software without specific prior written permission.
16 * 16 *
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */ 27 */
28 28
29 #include "core/html/ImageData.h" 29 #include "core/html/Float32ImageData.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/V8Float32Array.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" 37 #include "wtf/CheckedNumeric.h"
38 38
39 namespace blink { 39 namespace blink {
40 40
41 ImageData* ImageData::create(const IntSize& size) { 41 Float32ImageData* Float32ImageData::create(const IntSize& size) {
42 CheckedNumeric<unsigned> dataSize = 4; 42 CheckedNumeric<unsigned> dataSize = 4;
43 dataSize *= size.width(); 43 dataSize *= size.width();
44 dataSize *= size.height(); 44 dataSize *= size.height();
45 if (!dataSize.IsValid()) 45 if (!dataSize.IsValid())
46 return nullptr; 46 return nullptr;
47 47
48 DOMUint8ClampedArray* byteArray = 48 DOMFloat32Array* float32Array =
49 DOMUint8ClampedArray::createOrNull(dataSize.ValueOrDie()); 49 DOMFloat32Array::createOrNull(dataSize.ValueOrDie());
50 if (!byteArray) 50 if (!float32Array)
51 return nullptr; 51 return nullptr;
52 52
53 return new ImageData(size, byteArray); 53 return new Float32ImageData(size, float32Array);
54 } 54 }
55 55
56 ImageData* ImageData::create(const IntSize& size, 56 Float32ImageData* Float32ImageData::create(const IntSize& size,
57 DOMUint8ClampedArray* byteArray) { 57 DOMFloat32Array* float32Array) {
58 CheckedNumeric<unsigned> dataSize = 4; 58 CheckedNumeric<unsigned> dataSize = 4;
59 dataSize *= size.width(); 59 dataSize *= size.width();
60 dataSize *= size.height(); 60 dataSize *= size.height();
61 if (!dataSize.IsValid()) 61 if (!dataSize.IsValid())
62 return nullptr; 62 return nullptr;
63 63
64 if (!dataSize.IsValid() || dataSize.ValueOrDie() > byteArray->length()) 64 if (!dataSize.IsValid() || dataSize.ValueOrDie() > float32Array->length())
65 return nullptr; 65 return nullptr;
66 66
67 return new ImageData(size, byteArray); 67 return new Float32ImageData(size, float32Array);
68 } 68 }
69 69
70 ImageData* ImageData::create(unsigned width, 70 Float32ImageData* Float32ImageData::create(unsigned width,
71 unsigned height, 71 unsigned height,
72 ExceptionState& exceptionState) { 72 ExceptionState& exceptionState) {
73 if (!width || !height) { 73 if (!width || !height) {
74 exceptionState.throwDOMException( 74 exceptionState.throwDOMException(
75 IndexSizeError, String::format("The source %s is zero or not a number.", 75 IndexSizeError, String::format("The source %s is zero or not a number.",
76 width ? "height" : "width"));
77 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 DOMFloat32Array* float32Array =
92 DOMFloat32Array::createOrNull(dataSize.ValueOrDie());
93 if (!float32Array) {
94 exceptionState.throwDOMException(
95 V8Error, "Out of memory at Float32ImageData creation");
96 return nullptr;
97 }
98
99 return new Float32ImageData(IntSize(width, height), float32Array);
100 }
101
102 Float32ImageData* Float32ImageData::create(unsigned width,
103 unsigned height,
104 String colorSpace,
105 ExceptionState& exceptionState) {
106 if (!width || !height) {
107 exceptionState.throwDOMException(
108 IndexSizeError, String::format("The source %s is zero or not a number.",
76 width ? "height" : "width")); 109 width ? "height" : "width"));
77 return nullptr; 110 return nullptr;
78 } 111 }
79 112
80 CheckedNumeric<unsigned> dataSize = 4; 113 CheckedNumeric<unsigned> dataSize = 4;
81 dataSize *= width; 114 dataSize *= width;
82 dataSize *= height; 115 dataSize *= height;
83 if (!dataSize.IsValid() || static_cast<int>(width) < 0 || 116 if (!dataSize.IsValid() || static_cast<int>(width) < 0 ||
84 static_cast<int>(height) < 0) { 117 static_cast<int>(height) < 0) {
85 exceptionState.throwDOMException( 118 exceptionState.throwDOMException(
86 IndexSizeError, 119 IndexSizeError,
87 "The requested image size exceeds the supported range."); 120 "The requested image size exceeds the supported range.");
88 return nullptr; 121 return nullptr;
89 } 122 }
90 123
91 DOMUint8ClampedArray* byteArray = 124 DOMFloat32Array* float32Array =
92 DOMUint8ClampedArray::createOrNull(dataSize.ValueOrDie()); 125 DOMFloat32Array::createOrNull(dataSize.ValueOrDie());
93 if (!byteArray) { 126 if (!float32Array) {
94 exceptionState.throwDOMException(V8Error, 127 exceptionState.throwDOMException(
95 "Out of memory at ImageData creation"); 128 V8Error, "Out of memory at Float32ImageData creation");
96 return nullptr; 129 return nullptr;
97 } 130 }
98 131
99 return new ImageData(IntSize(width, height), byteArray); 132 return new Float32ImageData(IntSize(width, height), float32Array, colorSpace);
100 } 133 }
101 134
102 bool ImageData::validateConstructorArguments(DOMUint8ClampedArray* data, 135 bool Float32ImageData::validateConstructorArguments(
103 unsigned width, 136 DOMFloat32Array* data,
104 unsigned& lengthInPixels, 137 unsigned width,
105 ExceptionState& exceptionState) { 138 unsigned& lengthInPixels,
139 ExceptionState& exceptionState) {
106 if (!width) { 140 if (!width) {
107 exceptionState.throwDOMException( 141 exceptionState.throwDOMException(
108 IndexSizeError, "The source width is zero or not a number."); 142 IndexSizeError, "The source width is zero or not a number.");
109 return false; 143 return false;
110 } 144 }
111 DCHECK(data); 145 DCHECK(data);
112 unsigned length = data->length(); 146 unsigned length = data->length();
113 if (!length) { 147 if (!length) {
114 exceptionState.throwDOMException(IndexSizeError, 148 exceptionState.throwDOMException(IndexSizeError,
115 "The input data has a zero byte length."); 149 "The input data has a zero byte length.");
116 return false; 150 return false;
117 } 151 }
118 if (length % 4) { 152 if (length % 4) {
119 exceptionState.throwDOMException( 153 exceptionState.throwDOMException(
120 IndexSizeError, "The input data byte length is not a multiple of 4."); 154 IndexSizeError, "The input data length is not a multiple of 4.");
121 return false; 155 return false;
122 } 156 }
123 length /= 4; 157 length /= 4;
124 if (length % width) { 158 if (length % width) {
125 exceptionState.throwDOMException( 159 exceptionState.throwDOMException(
126 IndexSizeError, 160 IndexSizeError,
127 "The input data byte length is not a multiple of (4 * width)."); 161 "The input data length is not a multiple of (4 * width).");
128 return false; 162 return false;
129 } 163 }
130 lengthInPixels = length; 164 lengthInPixels = length;
131 return true; 165 return true;
132 } 166 }
133 167
134 ImageData* ImageData::create(DOMUint8ClampedArray* data, 168 bool Float32ImageData::validateConstructorArguments(
135 unsigned width, 169 DOMFloat32Array* data,
136 ExceptionState& exceptionState) { 170 unsigned width,
171 unsigned& lengthInPixels,
172 String colorSpace,
173 ExceptionState& exceptionState) {
174 if (colorSpace != kLinearRGBImageDataColorSpaceName) {
175 exceptionState.throwDOMException(NotSupportedError,
176 "The input color space is not supported "
177 "in Float32Array-backed image data.");
178 return false;
179 }
180 return validateConstructorArguments(data, width, lengthInPixels,
181 exceptionState);
182 }
183
184 Float32ImageData* Float32ImageData::create(DOMFloat32Array* data,
185 unsigned width,
186 ExceptionState& exceptionState) {
137 unsigned lengthInPixels = 0; 187 unsigned lengthInPixels = 0;
138 if (!validateConstructorArguments(data, width, lengthInPixels, 188 if (!validateConstructorArguments(data, width, lengthInPixels,
139 exceptionState)) { 189 exceptionState)) {
140 DCHECK(exceptionState.hadException()); 190 DCHECK(exceptionState.hadException());
141 return nullptr; 191 return nullptr;
142 } 192 }
143 DCHECK_GT(lengthInPixels, 0u); 193 DCHECK_GT(lengthInPixels, 0u);
144 DCHECK_GT(width, 0u); 194 DCHECK_GT(width, 0u);
145 unsigned height = lengthInPixels / width; 195 unsigned height = lengthInPixels / width;
146 return new ImageData(IntSize(width, height), data); 196 return new Float32ImageData(IntSize(width, height), data);
147 } 197 }
148 198
149 ImageData* ImageData::create(DOMUint8ClampedArray* data, 199 Float32ImageData* Float32ImageData::create(DOMFloat32Array* data,
150 unsigned width, 200 unsigned width,
151 unsigned height, 201 unsigned height,
152 ExceptionState& exceptionState) { 202 ExceptionState& exceptionState) {
153 unsigned lengthInPixels = 0; 203 unsigned lengthInPixels = 0;
154 if (!validateConstructorArguments(data, width, lengthInPixels, 204 if (!validateConstructorArguments(data, width, lengthInPixels,
155 exceptionState)) { 205 exceptionState)) {
156 DCHECK(exceptionState.hadException()); 206 DCHECK(exceptionState.hadException());
157 return nullptr; 207 return nullptr;
158 } 208 }
159 DCHECK_GT(lengthInPixels, 0u); 209 DCHECK_GT(lengthInPixels, 0u);
160 DCHECK_GT(width, 0u); 210 DCHECK_GT(width, 0u);
161 if (height != lengthInPixels / width) { 211 if (height != lengthInPixels / width) {
162 exceptionState.throwDOMException( 212 exceptionState.throwDOMException(
163 IndexSizeError, 213 IndexSizeError,
164 "The input data byte length is not equal to (4 * width * height)."); 214 "The input data byte length is not equal to (4 * width * height).");
165 return nullptr; 215 return nullptr;
166 } 216 }
167 return new ImageData(IntSize(width, height), data); 217 return new Float32ImageData(IntSize(width, height), data);
168 } 218 }
169 219
170 ScriptPromise ImageData::createImageBitmap(ScriptState* scriptState, 220 Float32ImageData* Float32ImageData::create(DOMFloat32Array* data,
171 EventTarget& eventTarget, 221 unsigned width,
172 Optional<IntRect> cropRect, 222 unsigned height,
173 const ImageBitmapOptions& options, 223 String colorSpace,
174 ExceptionState& exceptionState) { 224 ExceptionState& exceptionState) {
225 unsigned lengthInPixels = 0;
226 if (!validateConstructorArguments(data, width, lengthInPixels, colorSpace,
227 exceptionState)) {
228 DCHECK(exceptionState.hadException());
229 return nullptr;
230 }
231 DCHECK_GT(lengthInPixels, 0u);
232 DCHECK_GT(width, 0u);
233 if (height != lengthInPixels / width) {
234 exceptionState.throwDOMException(
235 IndexSizeError,
236 "The input data byte length is not equal to (4 * width * height).");
237 return nullptr;
238 }
239 return new Float32ImageData(IntSize(width, height), data, colorSpace);
240 }
241
242 // TODO(zakerinasab): Fix this when ImageBitmap color correction code is landed.
243 // Tip: If the source Image Data has a color space, createImageBitmap must
244 // respect this color space even when no color space tag is passed to it.
245 ScriptPromise Float32ImageData::createImageBitmap(
246 ScriptState* scriptState,
247 EventTarget& eventTarget,
248 Optional<IntRect> cropRect,
249 const ImageBitmapOptions& options,
250 ExceptionState& exceptionState) {
175 if ((cropRect && 251 if ((cropRect &&
176 !ImageBitmap::isSourceSizeValid(cropRect->width(), cropRect->height(), 252 !ImageBitmap::isSourceSizeValid(cropRect->width(), cropRect->height(),
177 exceptionState)) || 253 exceptionState)) ||
178 !ImageBitmap::isSourceSizeValid(bitmapSourceSize().width(), 254 !ImageBitmap::isSourceSizeValid(bitmapSourceSize().width(),
179 bitmapSourceSize().height(), 255 bitmapSourceSize().height(),
180 exceptionState)) 256 exceptionState))
181 return ScriptPromise(); 257 return ScriptPromise();
182 if (data()->bufferBase()->isNeutered()) { 258 if (data()->bufferBase()->isNeutered()) {
183 exceptionState.throwDOMException(InvalidStateError, 259 exceptionState.throwDOMException(InvalidStateError,
184 "The source data has been neutered."); 260 "The source data has been neutered.");
185 return ScriptPromise(); 261 return ScriptPromise();
186 } 262 }
187 if (!ImageBitmap::isResizeOptionValid(options, exceptionState)) 263 if (!ImageBitmap::isResizeOptionValid(options, exceptionState))
188 return ScriptPromise(); 264 return ScriptPromise();
189 return ImageBitmapSource::fulfillImageBitmap( 265 return ImageBitmapSource::fulfillImageBitmap(
190 scriptState, ImageBitmap::create(this, cropRect, options)); 266 scriptState, ImageBitmap::create(this, cropRect, options));
191 } 267 }
192 268
193 v8::Local<v8::Object> ImageData::associateWithWrapper( 269 v8::Local<v8::Object> Float32ImageData::associateWithWrapper(
194 v8::Isolate* isolate, 270 v8::Isolate* isolate,
195 const WrapperTypeInfo* wrapperType, 271 const WrapperTypeInfo* wrapperType,
196 v8::Local<v8::Object> wrapper) { 272 v8::Local<v8::Object> wrapper) {
197 wrapper = 273 wrapper =
198 ScriptWrappable::associateWithWrapper(isolate, wrapperType, wrapper); 274 ScriptWrappable::associateWithWrapper(isolate, wrapperType, wrapper);
199 275
200 if (!wrapper.IsEmpty() && m_data.get()) { 276 if (!wrapper.IsEmpty() && m_data.get()) {
201 // Create a V8 Uint8ClampedArray object and set the "data" property 277 // Create a V8 Float32Array object and set the "data" property
202 // of the ImageData object to the created v8 object, eliminating the 278 // of the Float32ImageData object to the created v8 object, eliminating the
203 // C++ callback when accessing the "data" property. 279 // C++ callback when accessing the "data" property.
204 v8::Local<v8::Value> pixelArray = toV8(m_data.get(), wrapper, isolate); 280 v8::Local<v8::Value> pixelArray = toV8(m_data.get(), wrapper, isolate);
205 if (pixelArray.IsEmpty() || 281 if (pixelArray.IsEmpty() ||
206 !v8CallBoolean(wrapper->DefineOwnProperty( 282 !v8CallBoolean(wrapper->DefineOwnProperty(
207 isolate->GetCurrentContext(), v8AtomicString(isolate, "data"), 283 isolate->GetCurrentContext(), v8AtomicString(isolate, "data"),
208 pixelArray, v8::ReadOnly))) 284 pixelArray, v8::ReadOnly)))
209 return v8::Local<v8::Object>(); 285 return v8::Local<v8::Object>();
210 } 286 }
211 return wrapper; 287 return wrapper;
212 } 288 }
213 289
214 ImageData::ImageData(const IntSize& size, DOMUint8ClampedArray* byteArray) 290 Float32ImageData::Float32ImageData(const IntSize& size,
215 : m_size(size), m_data(byteArray) { 291 DOMFloat32Array* float32Array,
292 String colorSpaceName)
293 : m_size(size),
294 m_colorSpace(ImageData::getImageDataColorSpace(colorSpaceName)),
295 m_data(float32Array) {
216 DCHECK_GE(size.width(), 0); 296 DCHECK_GE(size.width(), 0);
217 DCHECK_GE(size.height(), 0); 297 DCHECK_GE(size.height(), 0);
218 SECURITY_CHECK(static_cast<unsigned>(size.width() * size.height() * 4) <= 298 SECURITY_CHECK(static_cast<unsigned>(size.width() * size.height() * 4) <=
219 m_data->length()); 299 m_data->length());
220 } 300 }
221 301
222 } // namespace blink 302 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698