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/DOMRect.h" | 8 #include "core/dom/DOMRect.h" |
9 #include "core/dom/Document.h" | 9 #include "core/dom/Document.h" |
10 #include "core/frame/ImageBitmap.h" | 10 #include "core/frame/ImageBitmap.h" |
11 #include "core/frame/LocalFrame.h" | 11 #include "core/frame/LocalFrame.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::ColorType::RGBA_8888 | 34 mojo::SharedBufferHandle::Create(size); |
32 : skia::mojom::ColorType::BGRA_8888; | 35 if (!sharedBufferHandle->is_valid()) { |
33 bitmap->width = width; | 36 resolver->reject( |
34 bitmap->height = height; | 37 DOMException::create(InvalidStateError, "Internal allocation error")); |
35 bitmap->pixel_data = std::move(bitmapData); | 38 return sharedBufferHandle; |
| 39 } |
36 | 40 |
37 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; |
38 } | 47 } |
39 | 48 |
40 } // anonymous namespace | 49 } // anonymous namespace |
41 | 50 |
42 ScriptPromise ShapeDetector::detect(ScriptState* scriptState, | 51 ScriptPromise ShapeDetector::detect(ScriptState* scriptState, |
43 const ImageBitmapSourceUnion& imageSource) { | 52 const ImageBitmapSourceUnion& imageSource) { |
44 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); | 53 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); |
45 ScriptPromise promise = resolver->promise(); | 54 ScriptPromise promise = resolver->promise(); |
46 | 55 |
47 // ImageDatas cannot be tainted by definition. | 56 // ImageDatas cannot be tainted by definition. |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
120 pixelDataPtr = pixelData->data(); | 129 pixelDataPtr = pixelData->data(); |
121 allocationSize = imageBitmap->size().area() * 4 /* bytes per pixel */; | 130 allocationSize = imageBitmap->size().area() * 4 /* bytes per pixel */; |
122 } else { | 131 } else { |
123 // TODO(mcasas): retrieve the pixels from elsewhere. | 132 // TODO(mcasas): retrieve the pixels from elsewhere. |
124 NOTREACHED(); | 133 NOTREACHED(); |
125 resolver->reject(DOMException::create( | 134 resolver->reject(DOMException::create( |
126 InvalidStateError, "Failed to get pixels for current frame.")); | 135 InvalidStateError, "Failed to get pixels for current frame.")); |
127 return promise; | 136 return promise; |
128 } | 137 } |
129 | 138 |
130 WTF::Vector<uint8_t> bitmapData; | 139 mojo::ScopedSharedBufferHandle sharedBufferHandle = getSharedBufferOnData( |
131 bitmapData.append(pixelDataPtr, | 140 resolver, pixelDataPtr, allocationSize.ValueOrDefault(0)); |
132 static_cast<int>(allocationSize.ValueOrDefault(0))); | 141 if (!sharedBufferHandle->is_valid()) |
| 142 return promise; |
133 | 143 |
134 return doDetect(resolver, | 144 return doDetect(resolver, std::move(sharedBufferHandle), image->width(), |
135 createBitmapFromData(image->width(), image->height(), | 145 image->height()); |
136 std::move(bitmapData))); | |
137 } | 146 } |
138 | 147 |
139 ScriptPromise ShapeDetector::detectShapesOnImageData( | 148 ScriptPromise ShapeDetector::detectShapesOnImageData( |
140 ScriptPromiseResolver* resolver, | 149 ScriptPromiseResolver* resolver, |
141 ImageData* imageData) { | 150 ImageData* imageData) { |
142 ScriptPromise promise = resolver->promise(); | 151 ScriptPromise promise = resolver->promise(); |
143 | 152 |
144 if (imageData->size().isZero()) { | 153 if (imageData->size().isZero()) { |
145 resolver->resolve(HeapVector<Member<DOMRect>>()); | 154 resolver->resolve(HeapVector<Member<DOMRect>>()); |
146 return promise; | 155 return promise; |
147 } | 156 } |
148 | 157 |
149 uint8_t* const data = imageData->data()->data(); | 158 uint8_t* const data = imageData->data()->data(); |
150 WTF::CheckedNumeric<int> allocationSize = imageData->size().area() * 4; | 159 WTF::CheckedNumeric<int> allocationSize = imageData->size().area() * 4; |
151 WTF::Vector<uint8_t> bitmapData; | |
152 bitmapData.append(data, static_cast<int>(allocationSize.ValueOrDefault(0))); | |
153 | 160 |
154 return doDetect(resolver, | 161 mojo::ScopedSharedBufferHandle sharedBufferHandle = |
155 createBitmapFromData(imageData->width(), imageData->height(), | 162 getSharedBufferOnData(resolver, data, allocationSize.ValueOrDefault(0)); |
156 std::move(bitmapData))); | 163 if (!sharedBufferHandle->is_valid()) |
| 164 return promise; |
| 165 |
| 166 return doDetect(resolver, std::move(sharedBufferHandle), imageData->width(), |
| 167 imageData->height()); |
157 } | 168 } |
158 | 169 |
159 ScriptPromise ShapeDetector::detectShapesOnImageElement( | 170 ScriptPromise ShapeDetector::detectShapesOnImageElement( |
160 ScriptPromiseResolver* resolver, | 171 ScriptPromiseResolver* resolver, |
161 const HTMLImageElement* img) { | 172 const HTMLImageElement* img) { |
162 ScriptPromise promise = resolver->promise(); | 173 ScriptPromise promise = resolver->promise(); |
163 | 174 |
164 if (img->bitmapSourceSize().isZero()) { | 175 if (img->bitmapSourceSize().isZero()) { |
165 resolver->resolve(HeapVector<Member<DOMRect>>()); | 176 resolver->resolve(HeapVector<Member<DOMRect>>()); |
166 return promise; | 177 return promise; |
(...skipping 20 matching lines...) Expand all Loading... |
187 DCHECK_EQ(img->naturalHeight(), static_cast<unsigned>(image->height())); | 198 DCHECK_EQ(img->naturalHeight(), static_cast<unsigned>(image->height())); |
188 | 199 |
189 if (!image) { | 200 if (!image) { |
190 resolver->reject(DOMException::create( | 201 resolver->reject(DOMException::create( |
191 InvalidStateError, "Failed to get image from current frame.")); | 202 InvalidStateError, "Failed to get image from current frame.")); |
192 return promise; | 203 return promise; |
193 } | 204 } |
194 | 205 |
195 const SkImageInfo skiaInfo = | 206 const SkImageInfo skiaInfo = |
196 SkImageInfo::MakeN32(image->width(), image->height(), image->alphaType()); | 207 SkImageInfo::MakeN32(image->width(), image->height(), image->alphaType()); |
197 size_t rowBytes = skiaInfo.minRowBytes(); | |
198 | 208 |
199 Vector<uint8_t> bitmapData(skiaInfo.getSafeSize(rowBytes)); | 209 const uint32_t allocationSize = skiaInfo.getSafeSize(skiaInfo.minRowBytes()); |
200 const SkPixmap pixmap(skiaInfo, bitmapData.data(), rowBytes); | 210 |
| 211 mojo::ScopedSharedBufferHandle sharedBufferHandle = |
| 212 mojo::SharedBufferHandle::Create(allocationSize); |
| 213 if (!sharedBufferHandle.is_valid()) { |
| 214 DLOG(ERROR) << "Requested allocation : " << allocationSize |
| 215 << "B, larger than |mojo::edk::kMaxSharedBufferSize| == 16MB "; |
| 216 // TODO(xianglu): For now we reject the promise if the image is too large. |
| 217 // But consider resizing the image to remove restriction on the user side. |
| 218 // Also, add LayoutTests for this case later. |
| 219 resolver->reject( |
| 220 DOMException::create(InvalidStateError, "Image exceeds size limit.")); |
| 221 return promise; |
| 222 } |
| 223 |
| 224 const mojo::ScopedSharedBufferMapping mappedBuffer = |
| 225 sharedBufferHandle->Map(allocationSize); |
| 226 |
| 227 const SkPixmap pixmap(skiaInfo, mappedBuffer.get(), skiaInfo.minRowBytes()); |
201 if (!image->readPixels(pixmap, 0, 0)) { | 228 if (!image->readPixels(pixmap, 0, 0)) { |
202 resolver->reject(DOMException::create( | 229 resolver->reject(DOMException::create( |
203 InvalidStateError, | 230 InvalidStateError, |
204 "Failed to read pixels: Unable to decompress or unsupported format.")); | 231 "Failed to read pixels: Unable to decompress or unsupported format.")); |
205 return promise; | 232 return promise; |
206 } | 233 } |
207 | 234 |
208 return doDetect( | 235 return doDetect(resolver, std::move(sharedBufferHandle), img->naturalWidth(), |
209 resolver, createBitmapFromData(img->naturalWidth(), img->naturalHeight(), | 236 img->naturalHeight()); |
210 std::move(bitmapData))); | |
211 } | 237 } |
212 | 238 |
213 } // namespace blink | 239 } // namespace blink |
OLD | NEW |