| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |