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/fetch/ImageResource.h" | 10 #include "core/fetch/ImageResource.h" |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
57 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); | 57 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); |
58 ScriptPromise promise = resolver->promise(); | 58 ScriptPromise promise = resolver->promise(); |
59 | 59 |
60 CanvasImageSource* canvasImageSource; | 60 CanvasImageSource* canvasImageSource; |
61 if (imageSource.isHTMLImageElement()) { | 61 if (imageSource.isHTMLImageElement()) { |
62 canvasImageSource = imageSource.getAsHTMLImageElement(); | 62 canvasImageSource = imageSource.getAsHTMLImageElement(); |
63 } else if (imageSource.isImageBitmap()) { | 63 } else if (imageSource.isImageBitmap()) { |
64 canvasImageSource = imageSource.getAsImageBitmap(); | 64 canvasImageSource = imageSource.getAsImageBitmap(); |
65 } else if (imageSource.isHTMLVideoElement()) { | 65 } else if (imageSource.isHTMLVideoElement()) { |
66 canvasImageSource = imageSource.getAsHTMLVideoElement(); | 66 canvasImageSource = imageSource.getAsHTMLVideoElement(); |
| 67 } else if (imageSource.isHTMLCanvasElement()) { |
| 68 canvasImageSource = imageSource.getAsHTMLCanvasElement(); |
| 69 } else if (imageSource.isOffscreenCanvas()) { |
| 70 canvasImageSource = imageSource.getAsOffscreenCanvas(); |
67 } else { | 71 } else { |
68 // TODO(mcasas): Implement more CanvasImageSources, https://crbug.com/659138 | 72 NOTREACHED() << "Unsupported CanvasImageSource"; |
69 NOTIMPLEMENTED() << "Unsupported CanvasImageSource"; | |
70 resolver->reject( | 73 resolver->reject( |
71 DOMException::create(NotFoundError, "Unsupported source.")); | 74 DOMException::create(NotSupportedError, "Unsupported source.")); |
72 return promise; | 75 return promise; |
73 } | 76 } |
74 | 77 |
75 if (canvasImageSource->wouldTaintOrigin( | 78 if (canvasImageSource->wouldTaintOrigin( |
76 scriptState->getExecutionContext()->getSecurityOrigin())) { | 79 scriptState->getExecutionContext()->getSecurityOrigin())) { |
77 resolver->reject( | 80 resolver->reject( |
78 DOMException::create(SecurityError, "Source would taint origin.")); | 81 DOMException::create(SecurityError, "Source would taint origin.")); |
79 return promise; | 82 return promise; |
80 } | 83 } |
81 | 84 |
82 if (imageSource.isHTMLImageElement()) { | 85 if (imageSource.isHTMLImageElement()) { |
83 return detectShapesOnImageElement(resolver, | 86 return detectShapesOnImageElement(resolver, |
84 imageSource.getAsHTMLImageElement()); | 87 imageSource.getAsHTMLImageElement()); |
85 } else if (imageSource.isImageBitmap()) { | |
86 return detectShapesOnImageBitmap(resolver, imageSource.getAsImageBitmap()); | |
87 } else if (imageSource.isHTMLVideoElement()) { | |
88 return detectShapesOnVideoElement(resolver, | |
89 imageSource.getAsHTMLVideoElement()); | |
90 } | 88 } |
91 | 89 |
92 NOTREACHED(); | 90 // TODO(mcasas): Check if |video| is actually playing a MediaStream by using |
93 return promise; | 91 // HTMLMediaElement::isMediaStreamURL(video->currentSrc().getString()); if |
| 92 // there is a local WebCam associated, there might be sophisticated ways to |
| 93 // detect faces on it. Until then, treat as a normal <video> element. |
| 94 |
| 95 const FloatSize size(canvasImageSource->sourceWidth(), |
| 96 canvasImageSource->sourceHeight()); |
| 97 |
| 98 SourceImageStatus sourceImageStatus = InvalidSourceImageStatus; |
| 99 RefPtr<Image> image = canvasImageSource->getSourceImageForCanvas( |
| 100 &sourceImageStatus, PreferNoAcceleration, SnapshotReasonDrawImage, size); |
| 101 if (!image || sourceImageStatus != NormalSourceImageStatus) { |
| 102 resolver->reject( |
| 103 DOMException::create(InvalidStateError, "Invalid element or state.")); |
| 104 return promise; |
| 105 } |
| 106 |
| 107 SkPixmap pixmap; |
| 108 RefPtr<Uint8Array> pixelData; |
| 109 uint8_t* pixelDataPtr = nullptr; |
| 110 WTF::CheckedNumeric<int> allocationSize = 0; |
| 111 |
| 112 sk_sp<SkImage> skImage = image->imageForCurrentFrame(); |
| 113 // Use |skImage|'s pixels if it has direct access to them. |
| 114 if (skImage->peekPixels(&pixmap)) { |
| 115 pixelDataPtr = static_cast<uint8_t*>(pixmap.writable_addr()); |
| 116 allocationSize = pixmap.getSafeSize(); |
| 117 } else if (imageSource.isImageBitmap()) { |
| 118 ImageBitmap* imageBitmap = imageSource.getAsImageBitmap(); |
| 119 pixelData = imageBitmap->copyBitmapData(imageBitmap->isPremultiplied() |
| 120 ? PremultiplyAlpha |
| 121 : DontPremultiplyAlpha, |
| 122 N32ColorType); |
| 123 pixelDataPtr = pixelData->data(); |
| 124 allocationSize = imageBitmap->size().area() * 4 /* bytes per pixel */; |
| 125 } else { |
| 126 // TODO(mcasas): retrieve the pixels from elsewhere. |
| 127 NOTREACHED(); |
| 128 resolver->reject(DOMException::create( |
| 129 InvalidStateError, "Failed to get pixels for current frame.")); |
| 130 return promise; |
| 131 } |
| 132 |
| 133 mojo::ScopedSharedBufferHandle sharedBufferHandle = getSharedBufferOnData( |
| 134 resolver, pixelDataPtr, allocationSize.ValueOrDefault(0)); |
| 135 if (!sharedBufferHandle->is_valid()) |
| 136 return promise; |
| 137 |
| 138 return doDetect(resolver, std::move(sharedBufferHandle), image->width(), |
| 139 image->height()); |
94 } | 140 } |
95 | 141 |
96 ScriptPromise ShapeDetector::detectShapesOnImageElement( | 142 ScriptPromise ShapeDetector::detectShapesOnImageElement( |
97 ScriptPromiseResolver* resolver, | 143 ScriptPromiseResolver* resolver, |
98 const HTMLImageElement* img) { | 144 const HTMLImageElement* img) { |
99 ScriptPromise promise = resolver->promise(); | 145 ScriptPromise promise = resolver->promise(); |
100 | 146 |
101 if (img->bitmapSourceSize().isZero()) { | 147 if (img->bitmapSourceSize().isZero()) { |
102 resolver->resolve(HeapVector<Member<DOMRect>>()); | 148 resolver->resolve(HeapVector<Member<DOMRect>>()); |
103 return promise; | 149 return promise; |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
153 resolver->reject(DOMException::create( | 199 resolver->reject(DOMException::create( |
154 InvalidStateError, | 200 InvalidStateError, |
155 "Failed to read pixels: Unable to decompress or unsupported format.")); | 201 "Failed to read pixels: Unable to decompress or unsupported format.")); |
156 return promise; | 202 return promise; |
157 } | 203 } |
158 | 204 |
159 return doDetect(resolver, std::move(sharedBufferHandle), img->naturalWidth(), | 205 return doDetect(resolver, std::move(sharedBufferHandle), img->naturalWidth(), |
160 img->naturalHeight()); | 206 img->naturalHeight()); |
161 } | 207 } |
162 | 208 |
163 ScriptPromise ShapeDetector::detectShapesOnImageBitmap( | |
164 ScriptPromiseResolver* resolver, | |
165 ImageBitmap* imageBitmap) { | |
166 ScriptPromise promise = resolver->promise(); | |
167 | |
168 if (imageBitmap->isNeutered()) { | |
169 resolver->reject( | |
170 DOMException::create(InvalidStateError, "Neutered ImageBitmap.")); | |
171 return promise; | |
172 } | |
173 | |
174 if (imageBitmap->size().area() == 0) { | |
175 resolver->resolve(HeapVector<Member<DOMRect>>()); | |
176 return promise; | |
177 } | |
178 | |
179 SkPixmap pixmap; | |
180 RefPtr<Uint8Array> pixelData; | |
181 uint8_t* pixelDataPtr = nullptr; | |
182 WTF::CheckedNumeric<int> allocationSize = 0; | |
183 // Use |skImage|'s pixels if it has direct access to them, otherwise retrieve | |
184 // them from elsewhere via copyBitmapData(). | |
185 sk_sp<SkImage> skImage = imageBitmap->bitmapImage()->imageForCurrentFrame(); | |
186 if (skImage->peekPixels(&pixmap)) { | |
187 pixelDataPtr = static_cast<uint8_t*>(pixmap.writable_addr()); | |
188 allocationSize = pixmap.getSafeSize(); | |
189 } else { | |
190 pixelData = imageBitmap->copyBitmapData(imageBitmap->isPremultiplied() | |
191 ? PremultiplyAlpha | |
192 : DontPremultiplyAlpha, | |
193 N32ColorType); | |
194 pixelDataPtr = pixelData->data(); | |
195 allocationSize = imageBitmap->size().area() * 4 /* bytes per pixel */; | |
196 } | |
197 | |
198 mojo::ScopedSharedBufferHandle sharedBufferHandle = getSharedBufferOnData( | |
199 resolver, pixelDataPtr, allocationSize.ValueOrDefault(0)); | |
200 if (!sharedBufferHandle->is_valid()) | |
201 return promise; | |
202 | |
203 return doDetect(resolver, std::move(sharedBufferHandle), imageBitmap->width(), | |
204 imageBitmap->height()); | |
205 } | |
206 | |
207 ScriptPromise ShapeDetector::detectShapesOnVideoElement( | |
208 ScriptPromiseResolver* resolver, | |
209 const HTMLVideoElement* video) { | |
210 ScriptPromise promise = resolver->promise(); | |
211 // TODO(mcasas): Check if |video| is actually playing a MediaStream by using | |
212 // HTMLMediaElement::isMediaStreamURL(video->currentSrc().getString()); if | |
213 // there is a local WebCam associated, there might be sophisticated ways to | |
214 // detect faces on it. Until then, treat as a normal <video> element. | |
215 | |
216 // !hasAvailableVideoFrame() is a bundle of invalid states. | |
217 if (!video->hasAvailableVideoFrame()) { | |
218 resolver->reject(DOMException::create( | |
219 InvalidStateError, "Invalid HTMLVideoElement or state.")); | |
220 return promise; | |
221 } | |
222 | |
223 const FloatSize videoSize(video->videoWidth(), video->videoHeight()); | |
224 SourceImageStatus sourceImageStatus = InvalidSourceImageStatus; | |
225 RefPtr<Image> image = | |
226 video->getSourceImageForCanvas(&sourceImageStatus, PreferNoAcceleration, | |
227 SnapshotReasonDrawImage, videoSize); | |
228 | |
229 DCHECK_EQ(NormalSourceImageStatus, sourceImageStatus); | |
230 | |
231 SkPixmap pixmap; | |
232 RefPtr<Uint8Array> pixelData; | |
233 uint8_t* pixelDataPtr = nullptr; | |
234 WTF::CheckedNumeric<int> allocationSize = 0; | |
235 // Use |skImage|'s pixels if it has direct access to them. | |
236 sk_sp<SkImage> skImage = image->imageForCurrentFrame(); | |
237 if (skImage->peekPixels(&pixmap)) { | |
238 pixelDataPtr = static_cast<uint8_t*>(pixmap.writable_addr()); | |
239 allocationSize = pixmap.getSafeSize(); | |
240 } else { | |
241 // TODO(mcasas): retrieve the pixels from elsewhere. | |
242 NOTREACHED(); | |
243 resolver->reject(DOMException::create( | |
244 InvalidStateError, "Failed to get pixels for current frame.")); | |
245 return promise; | |
246 } | |
247 | |
248 mojo::ScopedSharedBufferHandle sharedBufferHandle = getSharedBufferOnData( | |
249 resolver, pixelDataPtr, allocationSize.ValueOrDefault(0)); | |
250 if (!sharedBufferHandle->is_valid()) | |
251 return promise; | |
252 | |
253 return doDetect(resolver, std::move(sharedBufferHandle), image->width(), | |
254 image->height()); | |
255 } | |
256 | |
257 } // namespace blink | 209 } // namespace blink |
OLD | NEW |