| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "modules/shapedetection/ShapeDetector.h" | 5 #include "modules/shapedetection/ShapeDetector.h" |
| 6 | 6 |
| 7 #include "core/dom/DOMException.h" | 7 #include "core/dom/DOMException.h" |
| 8 #include "core/dom/Document.h" | 8 #include "core/dom/Document.h" |
| 9 #include "core/frame/ImageBitmap.h" | 9 #include "core/frame/ImageBitmap.h" |
| 10 #include "core/frame/LocalFrame.h" | 10 #include "core/frame/LocalFrame.h" |
| 11 #include "core/geometry/DOMRect.h" | 11 #include "core/geometry/DOMRect.h" |
| 12 #include "core/html/HTMLImageElement.h" | 12 #include "core/html/HTMLImageElement.h" |
| 13 #include "core/html/HTMLVideoElement.h" | 13 #include "core/html/HTMLVideoElement.h" |
| 14 #include "core/html/ImageData.h" | 14 #include "core/html/ImageData.h" |
| 15 #include "core/loader/resource/ImageResourceContent.h" | 15 #include "core/loader/resource/ImageResourceContent.h" |
| 16 #include "platform/graphics/Image.h" | 16 #include "platform/graphics/Image.h" |
| 17 #include "third_party/skia/include/core/SkImage.h" | 17 #include "third_party/skia/include/core/SkImage.h" |
| 18 #include "third_party/skia/include/core/SkImageInfo.h" | 18 #include "third_party/skia/include/core/SkImageInfo.h" |
| 19 #include "wtf/CheckedNumeric.h" | 19 #include "wtf/CheckedNumeric.h" |
| 20 | 20 |
| 21 namespace blink { | 21 namespace blink { |
| 22 | 22 |
| 23 namespace { | 23 namespace { |
| 24 | 24 |
| 25 skia::mojom::blink::BitmapPtr createBitmapFromData(int width, | 25 mojo::ScopedSharedBufferHandle getSharedBufferOnData( |
| 26 int height, | 26 ScriptPromiseResolver* resolver, |
| 27 Vector<uint8_t> bitmapData) { | 27 uint8_t* data, |
| 28 skia::mojom::blink::BitmapPtr bitmap = skia::mojom::blink::Bitmap::New(); | 28 int size) { |
| 29 DCHECK(data); |
| 30 DCHECK(size); |
| 31 ScriptPromise promise = resolver->promise(); |
| 29 | 32 |
| 30 bitmap->color_type = (kN32_SkColorType == kRGBA_8888_SkColorType) | 33 mojo::ScopedSharedBufferHandle sharedBufferHandle = |
| 31 ? skia::mojom::blink::ColorType::RGBA_8888 | 34 mojo::SharedBufferHandle::Create(size); |
| 32 : skia::mojom::blink::ColorType::BGRA_8888; | 35 if (!sharedBufferHandle->is_valid()) { |
| 33 bitmap->alpha_type = skia::mojom::blink::AlphaType::ALPHA_TYPE_OPAQUE; | 36 resolver->reject( |
| 34 bitmap->profile_type = skia::mojom::blink::ColorProfileType::LINEAR; | 37 DOMException::create(InvalidStateError, "Internal allocation error")); |
| 35 bitmap->width = width; | 38 return sharedBufferHandle; |
| 36 bitmap->height = height; | 39 } |
| 37 bitmap->row_bytes = width * 4 /* bytes per pixel */; | |
| 38 bitmap->pixel_data = std::move(bitmapData); | |
| 39 | 40 |
| 40 return bitmap; | 41 const mojo::ScopedSharedBufferMapping mappedBuffer = |
| 42 sharedBufferHandle->Map(size); |
| 43 DCHECK(mappedBuffer.get()); |
| 44 memcpy(mappedBuffer.get(), data, size); |
| 45 |
| 46 return sharedBufferHandle; |
| 41 } | 47 } |
| 42 | 48 |
| 43 } // anonymous namespace | 49 } // anonymous namespace |
| 44 | 50 |
| 45 ScriptPromise ShapeDetector::detect(ScriptState* scriptState, | 51 ScriptPromise ShapeDetector::detect(ScriptState* scriptState, |
| 46 const ImageBitmapSourceUnion& imageSource) { | 52 const ImageBitmapSourceUnion& imageSource) { |
| 47 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); | 53 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); |
| 48 ScriptPromise promise = resolver->promise(); | 54 ScriptPromise promise = resolver->promise(); |
| 49 | 55 |
| 50 // ImageDatas cannot be tainted by definition. | 56 // ImageDatas cannot be tainted by definition. |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 121 pixelDataPtr = pixelData->data(); | 127 pixelDataPtr = pixelData->data(); |
| 122 allocationSize = imageBitmap->size().area() * 4 /* bytes per pixel */; | 128 allocationSize = imageBitmap->size().area() * 4 /* bytes per pixel */; |
| 123 } else { | 129 } else { |
| 124 // TODO(mcasas): retrieve the pixels from elsewhere. | 130 // TODO(mcasas): retrieve the pixels from elsewhere. |
| 125 NOTREACHED(); | 131 NOTREACHED(); |
| 126 resolver->reject(DOMException::create( | 132 resolver->reject(DOMException::create( |
| 127 InvalidStateError, "Failed to get pixels for current frame.")); | 133 InvalidStateError, "Failed to get pixels for current frame.")); |
| 128 return promise; | 134 return promise; |
| 129 } | 135 } |
| 130 | 136 |
| 131 WTF::Vector<uint8_t> bitmapData; | 137 mojo::ScopedSharedBufferHandle sharedBufferHandle = getSharedBufferOnData( |
| 132 bitmapData.append(pixelDataPtr, | 138 resolver, pixelDataPtr, allocationSize.ValueOrDefault(0)); |
| 133 static_cast<int>(allocationSize.ValueOrDefault(0))); | 139 if (!sharedBufferHandle->is_valid()) |
| 140 return promise; |
| 134 | 141 |
| 135 return doDetect(resolver, | 142 return doDetect(resolver, std::move(sharedBufferHandle), image->width(), |
| 136 createBitmapFromData(image->width(), image->height(), | 143 image->height()); |
| 137 std::move(bitmapData))); | |
| 138 } | 144 } |
| 139 | 145 |
| 140 ScriptPromise ShapeDetector::detectShapesOnImageData( | 146 ScriptPromise ShapeDetector::detectShapesOnImageData( |
| 141 ScriptPromiseResolver* resolver, | 147 ScriptPromiseResolver* resolver, |
| 142 ImageData* imageData) { | 148 ImageData* imageData) { |
| 143 ScriptPromise promise = resolver->promise(); | 149 ScriptPromise promise = resolver->promise(); |
| 144 | 150 |
| 145 if (imageData->size().isZero()) { | 151 if (imageData->size().isZero()) { |
| 146 resolver->resolve(HeapVector<Member<DOMRect>>()); | 152 resolver->resolve(HeapVector<Member<DOMRect>>()); |
| 147 return promise; | 153 return promise; |
| 148 } | 154 } |
| 149 | 155 |
| 150 uint8_t* const data = imageData->data()->data(); | 156 uint8_t* const data = imageData->data()->data(); |
| 151 WTF::CheckedNumeric<int> allocationSize = imageData->size().area() * 4; | 157 WTF::CheckedNumeric<int> allocationSize = imageData->size().area() * 4; |
| 152 WTF::Vector<uint8_t> bitmapData; | |
| 153 bitmapData.append(data, static_cast<int>(allocationSize.ValueOrDefault(0))); | |
| 154 | 158 |
| 155 return doDetect(resolver, | 159 mojo::ScopedSharedBufferHandle sharedBufferHandle = |
| 156 createBitmapFromData(imageData->width(), imageData->height(), | 160 getSharedBufferOnData(resolver, data, allocationSize.ValueOrDefault(0)); |
| 157 std::move(bitmapData))); | 161 if (!sharedBufferHandle->is_valid()) |
| 162 return promise; |
| 163 |
| 164 return doDetect(resolver, std::move(sharedBufferHandle), imageData->width(), |
| 165 imageData->height()); |
| 158 } | 166 } |
| 159 | 167 |
| 160 ScriptPromise ShapeDetector::detectShapesOnImageElement( | 168 ScriptPromise ShapeDetector::detectShapesOnImageElement( |
| 161 ScriptPromiseResolver* resolver, | 169 ScriptPromiseResolver* resolver, |
| 162 const HTMLImageElement* img) { | 170 const HTMLImageElement* img) { |
| 163 ScriptPromise promise = resolver->promise(); | 171 ScriptPromise promise = resolver->promise(); |
| 164 | 172 |
| 165 if (img->bitmapSourceSize().isZero()) { | 173 if (img->bitmapSourceSize().isZero()) { |
| 166 resolver->resolve(HeapVector<Member<DOMRect>>()); | 174 resolver->resolve(HeapVector<Member<DOMRect>>()); |
| 167 return promise; | 175 return promise; |
| (...skipping 18 matching lines...) Expand all Loading... |
| 186 DCHECK_EQ(img->naturalHeight(), static_cast<unsigned>(image->height())); | 194 DCHECK_EQ(img->naturalHeight(), static_cast<unsigned>(image->height())); |
| 187 | 195 |
| 188 if (!image) { | 196 if (!image) { |
| 189 resolver->reject(DOMException::create( | 197 resolver->reject(DOMException::create( |
| 190 InvalidStateError, "Failed to get image from current frame.")); | 198 InvalidStateError, "Failed to get image from current frame.")); |
| 191 return promise; | 199 return promise; |
| 192 } | 200 } |
| 193 | 201 |
| 194 const SkImageInfo skiaInfo = | 202 const SkImageInfo skiaInfo = |
| 195 SkImageInfo::MakeN32(image->width(), image->height(), image->alphaType()); | 203 SkImageInfo::MakeN32(image->width(), image->height(), image->alphaType()); |
| 196 size_t rowBytes = skiaInfo.minRowBytes(); | |
| 197 | 204 |
| 198 Vector<uint8_t> bitmapData(skiaInfo.getSafeSize(rowBytes)); | 205 const uint32_t allocationSize = skiaInfo.getSafeSize(skiaInfo.minRowBytes()); |
| 199 const SkPixmap pixmap(skiaInfo, bitmapData.data(), rowBytes); | 206 |
| 207 mojo::ScopedSharedBufferHandle sharedBufferHandle = |
| 208 mojo::SharedBufferHandle::Create(allocationSize); |
| 209 if (!sharedBufferHandle.is_valid()) { |
| 210 DLOG(ERROR) << "Requested allocation : " << allocationSize |
| 211 << "B, larger than |mojo::edk::kMaxSharedBufferSize| == 16MB "; |
| 212 // TODO(xianglu): For now we reject the promise if the image is too large. |
| 213 // But consider resizing the image to remove restriction on the user side. |
| 214 // Also, add LayoutTests for this case later. |
| 215 resolver->reject( |
| 216 DOMException::create(InvalidStateError, "Image exceeds size limit.")); |
| 217 return promise; |
| 218 } |
| 219 |
| 220 const mojo::ScopedSharedBufferMapping mappedBuffer = |
| 221 sharedBufferHandle->Map(allocationSize); |
| 222 |
| 223 const SkPixmap pixmap(skiaInfo, mappedBuffer.get(), skiaInfo.minRowBytes()); |
| 200 if (!image->readPixels(pixmap, 0, 0)) { | 224 if (!image->readPixels(pixmap, 0, 0)) { |
| 201 resolver->reject(DOMException::create( | 225 resolver->reject(DOMException::create( |
| 202 InvalidStateError, | 226 InvalidStateError, |
| 203 "Failed to read pixels: Unable to decompress or unsupported format.")); | 227 "Failed to read pixels: Unable to decompress or unsupported format.")); |
| 204 return promise; | 228 return promise; |
| 205 } | 229 } |
| 206 | 230 |
| 207 return doDetect( | 231 return doDetect(resolver, std::move(sharedBufferHandle), img->naturalWidth(), |
| 208 resolver, createBitmapFromData(img->naturalWidth(), img->naturalHeight(), | 232 img->naturalHeight()); |
| 209 std::move(bitmapData))); | |
| 210 } | 233 } |
| 211 | 234 |
| 212 } // namespace blink | 235 } // namespace blink |
| OLD | NEW |