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 mojo::ScopedSharedBufferHandle getSharedBufferOnData( | 25 skia::mojom::blink::BitmapPtr createBitmapFromData(int width, |
26 ScriptPromiseResolver* resolver, | 26 int height, |
27 uint8_t* data, | 27 Vector<uint8_t> bitmapData) { |
28 int size) { | 28 skia::mojom::blink::BitmapPtr bitmap = skia::mojom::blink::Bitmap::New(); |
29 DCHECK(data); | |
30 DCHECK(size); | |
31 ScriptPromise promise = resolver->promise(); | |
32 | 29 |
33 mojo::ScopedSharedBufferHandle sharedBufferHandle = | 30 bitmap->color_type = (kN32_SkColorType == kRGBA_8888_SkColorType) |
34 mojo::SharedBufferHandle::Create(size); | 31 ? skia::mojom::ColorType::RGBA_8888 |
35 if (!sharedBufferHandle->is_valid()) { | 32 : skia::mojom::ColorType::BGRA_8888; |
36 resolver->reject( | 33 bitmap->width = width; |
37 DOMException::create(InvalidStateError, "Internal allocation error")); | 34 bitmap->height = height; |
38 return sharedBufferHandle; | 35 bitmap->pixel_data = std::move(bitmapData); |
39 } | |
40 | 36 |
41 const mojo::ScopedSharedBufferMapping mappedBuffer = | 37 return bitmap; |
42 sharedBufferHandle->Map(size); | |
43 DCHECK(mappedBuffer.get()); | |
44 memcpy(mappedBuffer.get(), data, size); | |
45 | |
46 return sharedBufferHandle; | |
47 } | 38 } |
48 | 39 |
49 } // anonymous namespace | 40 } // anonymous namespace |
50 | 41 |
51 ScriptPromise ShapeDetector::detect(ScriptState* scriptState, | 42 ScriptPromise ShapeDetector::detect(ScriptState* scriptState, |
52 const ImageBitmapSourceUnion& imageSource) { | 43 const ImageBitmapSourceUnion& imageSource) { |
53 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); | 44 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); |
54 ScriptPromise promise = resolver->promise(); | 45 ScriptPromise promise = resolver->promise(); |
55 | 46 |
56 // ImageDatas cannot be tainted by definition. | 47 // ImageDatas cannot be tainted by definition. |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
127 pixelDataPtr = pixelData->data(); | 118 pixelDataPtr = pixelData->data(); |
128 allocationSize = imageBitmap->size().area() * 4 /* bytes per pixel */; | 119 allocationSize = imageBitmap->size().area() * 4 /* bytes per pixel */; |
129 } else { | 120 } else { |
130 // TODO(mcasas): retrieve the pixels from elsewhere. | 121 // TODO(mcasas): retrieve the pixels from elsewhere. |
131 NOTREACHED(); | 122 NOTREACHED(); |
132 resolver->reject(DOMException::create( | 123 resolver->reject(DOMException::create( |
133 InvalidStateError, "Failed to get pixels for current frame.")); | 124 InvalidStateError, "Failed to get pixels for current frame.")); |
134 return promise; | 125 return promise; |
135 } | 126 } |
136 | 127 |
137 mojo::ScopedSharedBufferHandle sharedBufferHandle = getSharedBufferOnData( | 128 WTF::Vector<uint8_t> bitmapData; |
138 resolver, pixelDataPtr, allocationSize.ValueOrDefault(0)); | 129 bitmapData.append(pixelDataPtr, |
139 if (!sharedBufferHandle->is_valid()) | 130 static_cast<int>(allocationSize.ValueOrDefault(0))); |
140 return promise; | |
141 | 131 |
142 return doDetect(resolver, std::move(sharedBufferHandle), image->width(), | 132 return doDetect(resolver, |
143 image->height()); | 133 createBitmapFromData(image->width(), image->height(), |
| 134 std::move(bitmapData))); |
144 } | 135 } |
145 | 136 |
146 ScriptPromise ShapeDetector::detectShapesOnImageData( | 137 ScriptPromise ShapeDetector::detectShapesOnImageData( |
147 ScriptPromiseResolver* resolver, | 138 ScriptPromiseResolver* resolver, |
148 ImageData* imageData) { | 139 ImageData* imageData) { |
149 ScriptPromise promise = resolver->promise(); | 140 ScriptPromise promise = resolver->promise(); |
150 | 141 |
151 if (imageData->size().isZero()) { | 142 if (imageData->size().isZero()) { |
152 resolver->resolve(HeapVector<Member<DOMRect>>()); | 143 resolver->resolve(HeapVector<Member<DOMRect>>()); |
153 return promise; | 144 return promise; |
154 } | 145 } |
155 | 146 |
156 uint8_t* const data = imageData->data()->data(); | 147 uint8_t* const data = imageData->data()->data(); |
157 WTF::CheckedNumeric<int> allocationSize = imageData->size().area() * 4; | 148 WTF::CheckedNumeric<int> allocationSize = imageData->size().area() * 4; |
| 149 WTF::Vector<uint8_t> bitmapData; |
| 150 bitmapData.append(data, static_cast<int>(allocationSize.ValueOrDefault(0))); |
158 | 151 |
159 mojo::ScopedSharedBufferHandle sharedBufferHandle = | 152 return doDetect(resolver, |
160 getSharedBufferOnData(resolver, data, allocationSize.ValueOrDefault(0)); | 153 createBitmapFromData(imageData->width(), imageData->height(), |
161 if (!sharedBufferHandle->is_valid()) | 154 std::move(bitmapData))); |
162 return promise; | |
163 | |
164 return doDetect(resolver, std::move(sharedBufferHandle), imageData->width(), | |
165 imageData->height()); | |
166 } | 155 } |
167 | 156 |
168 ScriptPromise ShapeDetector::detectShapesOnImageElement( | 157 ScriptPromise ShapeDetector::detectShapesOnImageElement( |
169 ScriptPromiseResolver* resolver, | 158 ScriptPromiseResolver* resolver, |
170 const HTMLImageElement* img) { | 159 const HTMLImageElement* img) { |
171 ScriptPromise promise = resolver->promise(); | 160 ScriptPromise promise = resolver->promise(); |
172 | 161 |
173 if (img->bitmapSourceSize().isZero()) { | 162 if (img->bitmapSourceSize().isZero()) { |
174 resolver->resolve(HeapVector<Member<DOMRect>>()); | 163 resolver->resolve(HeapVector<Member<DOMRect>>()); |
175 return promise; | 164 return promise; |
(...skipping 18 matching lines...) Expand all Loading... |
194 DCHECK_EQ(img->naturalHeight(), static_cast<unsigned>(image->height())); | 183 DCHECK_EQ(img->naturalHeight(), static_cast<unsigned>(image->height())); |
195 | 184 |
196 if (!image) { | 185 if (!image) { |
197 resolver->reject(DOMException::create( | 186 resolver->reject(DOMException::create( |
198 InvalidStateError, "Failed to get image from current frame.")); | 187 InvalidStateError, "Failed to get image from current frame.")); |
199 return promise; | 188 return promise; |
200 } | 189 } |
201 | 190 |
202 const SkImageInfo skiaInfo = | 191 const SkImageInfo skiaInfo = |
203 SkImageInfo::MakeN32(image->width(), image->height(), image->alphaType()); | 192 SkImageInfo::MakeN32(image->width(), image->height(), image->alphaType()); |
| 193 size_t rowBytes = skiaInfo.minRowBytes(); |
204 | 194 |
205 const uint32_t allocationSize = skiaInfo.getSafeSize(skiaInfo.minRowBytes()); | 195 Vector<uint8_t> bitmapData(skiaInfo.getSafeSize(rowBytes)); |
206 | 196 const SkPixmap pixmap(skiaInfo, bitmapData.data(), rowBytes); |
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()); | |
224 if (!image->readPixels(pixmap, 0, 0)) { | 197 if (!image->readPixels(pixmap, 0, 0)) { |
225 resolver->reject(DOMException::create( | 198 resolver->reject(DOMException::create( |
226 InvalidStateError, | 199 InvalidStateError, |
227 "Failed to read pixels: Unable to decompress or unsupported format.")); | 200 "Failed to read pixels: Unable to decompress or unsupported format.")); |
228 return promise; | 201 return promise; |
229 } | 202 } |
230 | 203 |
231 return doDetect(resolver, std::move(sharedBufferHandle), img->naturalWidth(), | 204 return doDetect( |
232 img->naturalHeight()); | 205 resolver, createBitmapFromData(img->naturalWidth(), img->naturalHeight(), |
| 206 std::move(bitmapData))); |
233 } | 207 } |
234 | 208 |
235 } // namespace blink | 209 } // namespace blink |
OLD | NEW |