Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(9)

Side by Side Diff: third_party/WebKit/Source/modules/shapedetection/ShapeDetector.cpp

Issue 2502723002: ShapeDetection: implement barcode detection, blink part (Closed)
Patch Set: haraken@ comments Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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/FaceDetector.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"
11 #include "core/frame/ImageBitmap.h" 11 #include "core/frame/ImageBitmap.h"
12 #include "core/frame/LocalDOMWindow.h" 12 #include "core/frame/LocalDOMWindow.h"
13 #include "core/frame/LocalFrame.h" 13 #include "core/frame/LocalFrame.h"
14 #include "core/html/HTMLImageElement.h" 14 #include "core/html/HTMLImageElement.h"
15 #include "core/html/HTMLVideoElement.h" 15 #include "core/html/HTMLVideoElement.h"
16 #include "core/html/canvas/CanvasImageSource.h" 16 #include "core/html/canvas/CanvasImageSource.h"
17 #include "modules/shapedetection/DetectedBarcode.h"
17 #include "platform/graphics/Image.h" 18 #include "platform/graphics/Image.h"
18 #include "public/platform/InterfaceProvider.h" 19 #include "public/platform/InterfaceProvider.h"
19 #include "third_party/skia/include/core/SkImage.h" 20 #include "third_party/skia/include/core/SkImage.h"
20 #include "third_party/skia/include/core/SkImageInfo.h" 21 #include "third_party/skia/include/core/SkImageInfo.h"
21 #include "wtf/CheckedNumeric.h" 22 #include "wtf/CheckedNumeric.h"
22 23
23 namespace blink { 24 namespace blink {
24 25
25 namespace { 26 namespace {
26 27
27 static CanvasImageSource* toImageSourceInternal( 28 static CanvasImageSource* toImageSourceInternal(
28 const CanvasImageSourceUnion& value) { 29 const CanvasImageSourceUnion& value) {
29 if (value.isHTMLImageElement()) 30 if (value.isHTMLImageElement())
30 return value.getAsHTMLImageElement(); 31 return value.getAsHTMLImageElement();
31 32
32 if (value.isImageBitmap() && 33 if (value.isImageBitmap() &&
33 !static_cast<ImageBitmap*>(value.getAsImageBitmap())->isNeutered()) { 34 !static_cast<ImageBitmap*>(value.getAsImageBitmap())->isNeutered()) {
34 return value.getAsImageBitmap(); 35 return value.getAsImageBitmap();
35 } 36 }
36 37
37 if (value.isHTMLVideoElement()) 38 if (value.isHTMLVideoElement())
38 return value.getAsHTMLVideoElement(); 39 return value.getAsHTMLVideoElement();
39 40
40 return nullptr; 41 return nullptr;
41 } 42 }
42 43
43 } // anonymous namespace 44 } // anonymous namespace
44 45
45 FaceDetector* FaceDetector::create(ScriptState* scriptState) { 46 ShapeDetector::ShapeDetector(LocalFrame& frame) {
46 return new FaceDetector(*scriptState->domWindow()->frame());
47 }
48
49 FaceDetector::FaceDetector(LocalFrame& frame) {
50 DCHECK(!m_service.is_bound()); 47 DCHECK(!m_service.is_bound());
51 DCHECK(frame.interfaceProvider()); 48 DCHECK(frame.interfaceProvider());
52 frame.interfaceProvider()->getInterface(mojo::GetProxy(&m_service)); 49 frame.interfaceProvider()->getInterface(mojo::GetProxy(&m_service));
53 } 50 }
54 51
55 ScriptPromise FaceDetector::detect(ScriptState* scriptState, 52 ScriptPromise ShapeDetector::detectShapes(
56 const CanvasImageSourceUnion& imageSource) { 53 ScriptState* scriptState,
54 DetectorType detectorType,
55 const CanvasImageSourceUnion& imageSource) {
57 CanvasImageSource* imageSourceInternal = toImageSourceInternal(imageSource); 56 CanvasImageSource* imageSourceInternal = toImageSourceInternal(imageSource);
58 57
59 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); 58 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
60 ScriptPromise promise = resolver->promise(); 59 ScriptPromise promise = resolver->promise();
61 60
62 if (!imageSourceInternal) { 61 if (!imageSourceInternal) {
63 // TODO(mcasas): Implement more CanvasImageSources, https://crbug.com/659138 62 // TODO(mcasas): Implement more CanvasImageSources, https://crbug.com/659138
64 NOTIMPLEMENTED() << "Unsupported CanvasImageSource"; 63 NOTIMPLEMENTED() << "Unsupported CanvasImageSource";
65 resolver->reject( 64 resolver->reject(
66 DOMException::create(NotFoundError, "Unsupported source.")); 65 DOMException::create(NotFoundError, "Unsupported source."));
67 return promise; 66 return promise;
68 } 67 }
69 68
70 if (imageSourceInternal->wouldTaintOrigin( 69 if (imageSourceInternal->wouldTaintOrigin(
71 scriptState->getExecutionContext()->getSecurityOrigin())) { 70 scriptState->getExecutionContext()->getSecurityOrigin())) {
72 resolver->reject( 71 resolver->reject(
73 DOMException::create(SecurityError, "Source would taint origin.")); 72 DOMException::create(SecurityError, "Source would taint origin."));
74 return promise; 73 return promise;
75 } 74 }
76 75
77 if (imageSource.isHTMLImageElement()) { 76 if (imageSource.isHTMLImageElement()) {
78 return detectFacesOnImageElement( 77 return detectShapesOnImageElement(
79 resolver, static_cast<HTMLImageElement*>(imageSourceInternal)); 78 detectorType, resolver,
79 static_cast<HTMLImageElement*>(imageSourceInternal));
80 } 80 }
81 if (imageSourceInternal->isImageBitmap()) { 81 if (imageSourceInternal->isImageBitmap()) {
82 return detectFacesOnImageBitmap( 82 return detectShapesOnImageBitmap(
83 resolver, static_cast<ImageBitmap*>(imageSourceInternal)); 83 detectorType, resolver, static_cast<ImageBitmap*>(imageSourceInternal));
84 } 84 }
85 if (imageSourceInternal->isVideoElement()) { 85 if (imageSourceInternal->isVideoElement()) {
86 return detectFacesOnVideoElement( 86 return detectShapesOnVideoElement(
87 resolver, static_cast<HTMLVideoElement*>(imageSourceInternal)); 87 detectorType, resolver,
88 static_cast<HTMLVideoElement*>(imageSourceInternal));
88 } 89 }
89 90
90 NOTREACHED(); 91 NOTREACHED();
91 return promise; 92 return promise;
92 } 93 }
93 94
94 ScriptPromise FaceDetector::detectFacesOnImageElement( 95 ScriptPromise ShapeDetector::detectShapesOnImageElement(
96 DetectorType detectorType,
95 ScriptPromiseResolver* resolver, 97 ScriptPromiseResolver* resolver,
96 const HTMLImageElement* img) { 98 const HTMLImageElement* img) {
97 ScriptPromise promise = resolver->promise(); 99 ScriptPromise promise = resolver->promise();
98 if (img->bitmapSourceSize().isZero()) { 100 if (img->bitmapSourceSize().isZero()) {
99 resolver->resolve(HeapVector<Member<DOMRect>>()); 101 resolver->resolve(HeapVector<Member<DOMRect>>());
100 return promise; 102 return promise;
101 } 103 }
102 104
103 ImageResource* const imageResource = img->cachedImage(); 105 ImageResource* const imageResource = img->cachedImage();
104 if (!imageResource || imageResource->errorOccurred()) { 106 if (!imageResource || imageResource->errorOccurred()) {
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
148 const SkPixmap pixmap(skiaInfo, mappedBuffer.get(), skiaInfo.minRowBytes()); 150 const SkPixmap pixmap(skiaInfo, mappedBuffer.get(), skiaInfo.minRowBytes());
149 if (!image->readPixels(pixmap, 0, 0)) { 151 if (!image->readPixels(pixmap, 0, 0)) {
150 resolver->reject(DOMException::create( 152 resolver->reject(DOMException::create(
151 InvalidStateError, 153 InvalidStateError,
152 "Failed to read pixels: Unable to decompress or unsupported format.")); 154 "Failed to read pixels: Unable to decompress or unsupported format."));
153 return promise; 155 return promise;
154 } 156 }
155 157
156 if (!m_service) { 158 if (!m_service) {
157 resolver->reject(DOMException::create( 159 resolver->reject(DOMException::create(
158 NotSupportedError, "Face detection service unavailable.")); 160 NotSupportedError, "Shape detection service unavailable."));
159 return promise; 161 return promise;
160 } 162 }
161 163
162 m_serviceRequests.add(resolver); 164 m_serviceRequests.add(resolver);
163 DCHECK(m_service.is_bound()); 165 DCHECK(m_service.is_bound());
164 m_service->DetectFace(std::move(sharedBufferHandle), img->naturalWidth(), 166 if (detectorType == DetectorType::Face) {
165 img->naturalHeight(), 167 m_service->DetectFaces(
166 convertToBaseCallback(WTF::bind( 168 std::move(sharedBufferHandle), img->naturalWidth(),
167 &FaceDetector::onDetectFace, wrapPersistent(this), 169 img->naturalHeight(),
168 wrapPersistent(resolver)))); 170 convertToBaseCallback(WTF::bind(&ShapeDetector::onDetectFaces,
171 wrapPersistent(this),
172 wrapPersistent(resolver))));
173 } else if (detectorType == DetectorType::Barcode) {
174 m_service->DetectBarcodes(
175 std::move(sharedBufferHandle), img->naturalWidth(),
176 img->naturalHeight(),
177 convertToBaseCallback(WTF::bind(&ShapeDetector::onDetectBarcodes,
178 wrapPersistent(this),
179 wrapPersistent(resolver))));
180 } else {
181 NOTREACHED() << "Unsupported detector type";
182 }
183
169 return promise; 184 return promise;
170 } 185 }
171 186
172 ScriptPromise FaceDetector::detectFacesOnImageBitmap( 187 ScriptPromise ShapeDetector::detectShapesOnImageBitmap(
188 DetectorType detectorType,
173 ScriptPromiseResolver* resolver, 189 ScriptPromiseResolver* resolver,
174 ImageBitmap* imageBitmap) { 190 ImageBitmap* imageBitmap) {
175 ScriptPromise promise = resolver->promise(); 191 ScriptPromise promise = resolver->promise();
176 if (!imageBitmap->originClean()) { 192 if (!imageBitmap->originClean()) {
177 resolver->reject( 193 resolver->reject(
178 DOMException::create(SecurityError, "ImageBitmap is not origin clean")); 194 DOMException::create(SecurityError, "ImageBitmap is not origin clean"));
179 return promise; 195 return promise;
180 } 196 }
181 197
182 if (imageBitmap->size().area() == 0) { 198 if (imageBitmap->size().area() == 0) {
(...skipping 13 matching lines...) Expand all
196 allocationSize = pixmap.getSafeSize(); 212 allocationSize = pixmap.getSafeSize();
197 } else { 213 } else {
198 pixelData = imageBitmap->copyBitmapData(imageBitmap->isPremultiplied() 214 pixelData = imageBitmap->copyBitmapData(imageBitmap->isPremultiplied()
199 ? PremultiplyAlpha 215 ? PremultiplyAlpha
200 : DontPremultiplyAlpha, 216 : DontPremultiplyAlpha,
201 N32ColorType); 217 N32ColorType);
202 pixelDataPtr = pixelData->data(); 218 pixelDataPtr = pixelData->data();
203 allocationSize = imageBitmap->size().area() * 4 /* bytes per pixel */; 219 allocationSize = imageBitmap->size().area() * 4 /* bytes per pixel */;
204 } 220 }
205 221
206 return detectFacesOnData(resolver, pixelDataPtr, 222 return detectShapesOnData(detectorType, resolver, pixelDataPtr,
207 allocationSize.ValueOrDefault(0), 223 allocationSize.ValueOrDefault(0),
208 imageBitmap->width(), imageBitmap->height()); 224 imageBitmap->width(), imageBitmap->height());
209 } 225 }
210 226
211 ScriptPromise FaceDetector::detectFacesOnVideoElement( 227 ScriptPromise ShapeDetector::detectShapesOnVideoElement(
228 DetectorType detectorType,
212 ScriptPromiseResolver* resolver, 229 ScriptPromiseResolver* resolver,
213 const HTMLVideoElement* video) { 230 const HTMLVideoElement* video) {
214 ScriptPromise promise = resolver->promise(); 231 ScriptPromise promise = resolver->promise();
215 232
216 // TODO(mcasas): Check if |video| is actually playing a MediaStream by using 233 // TODO(mcasas): Check if |video| is actually playing a MediaStream by using
217 // HTMLMediaElement::isMediaStreamURL(video->currentSrc().getString()); if 234 // HTMLMediaElement::isMediaStreamURL(video->currentSrc().getString()); if
218 // there is a local WebCam associated, there might be sophisticated ways to 235 // there is a local WebCam associated, there might be sophisticated ways to
219 // detect faces on it. Until then, treat as a normal <video> element. 236 // detect faces on it. Until then, treat as a normal <video> element.
220 237
221 // !hasAvailableVideoFrame() is a bundle of invalid states. 238 // !hasAvailableVideoFrame() is a bundle of invalid states.
(...skipping 21 matching lines...) Expand all
243 pixelDataPtr = static_cast<uint8_t*>(pixmap.writable_addr()); 260 pixelDataPtr = static_cast<uint8_t*>(pixmap.writable_addr());
244 allocationSize = pixmap.getSafeSize(); 261 allocationSize = pixmap.getSafeSize();
245 } else { 262 } else {
246 // TODO(mcasas): retrieve the pixels from elsewhere. 263 // TODO(mcasas): retrieve the pixels from elsewhere.
247 NOTREACHED(); 264 NOTREACHED();
248 resolver->reject(DOMException::create( 265 resolver->reject(DOMException::create(
249 InvalidStateError, "Failed to get pixels for current frame.")); 266 InvalidStateError, "Failed to get pixels for current frame."));
250 return promise; 267 return promise;
251 } 268 }
252 269
253 return detectFacesOnData(resolver, pixelDataPtr, 270 return detectShapesOnData(detectorType, resolver, pixelDataPtr,
254 allocationSize.ValueOrDefault(0), image->width(), 271 allocationSize.ValueOrDefault(0), image->width(),
255 image->height()); 272 image->height());
256 } 273 }
257 274
258 ScriptPromise FaceDetector::detectFacesOnData(ScriptPromiseResolver* resolver, 275 ScriptPromise ShapeDetector::detectShapesOnData(DetectorType detectorType,
259 uint8_t* data, 276 ScriptPromiseResolver* resolver,
260 int size, 277 uint8_t* data,
261 int width, 278 int size,
262 int height) { 279 int width,
280 int height) {
263 DCHECK(data); 281 DCHECK(data);
264 DCHECK(size); 282 DCHECK(size);
265 ScriptPromise promise = resolver->promise(); 283 ScriptPromise promise = resolver->promise();
266 284
267 mojo::ScopedSharedBufferHandle sharedBufferHandle = 285 mojo::ScopedSharedBufferHandle sharedBufferHandle =
268 mojo::SharedBufferHandle::Create(size); 286 mojo::SharedBufferHandle::Create(size);
269 if (!sharedBufferHandle->is_valid()) { 287 if (!sharedBufferHandle->is_valid()) {
270 resolver->reject( 288 resolver->reject(
271 DOMException::create(InvalidStateError, "Internal allocation error")); 289 DOMException::create(InvalidStateError, "Internal allocation error"));
272 return promise; 290 return promise;
273 } 291 }
274 292
275 if (!m_service) { 293 if (!m_service) {
276 resolver->reject(DOMException::create( 294 resolver->reject(DOMException::create(
277 NotSupportedError, "Face detection service unavailable.")); 295 NotSupportedError, "Shape detection service unavailable."));
278 return promise; 296 return promise;
279 } 297 }
280 298
281 const mojo::ScopedSharedBufferMapping mappedBuffer = 299 const mojo::ScopedSharedBufferMapping mappedBuffer =
282 sharedBufferHandle->Map(size); 300 sharedBufferHandle->Map(size);
283 DCHECK(mappedBuffer.get()); 301 DCHECK(mappedBuffer.get());
284 302
285 memcpy(mappedBuffer.get(), data, size); 303 memcpy(mappedBuffer.get(), data, size);
286 304
287 m_serviceRequests.add(resolver); 305 m_serviceRequests.add(resolver);
288 DCHECK(m_service.is_bound()); 306 DCHECK(m_service.is_bound());
289 m_service->DetectFace(std::move(sharedBufferHandle), width, height, 307 if (detectorType == DetectorType::Face) {
290 convertToBaseCallback(WTF::bind( 308 m_service->DetectFaces(
291 &FaceDetector::onDetectFace, wrapPersistent(this), 309 std::move(sharedBufferHandle), width, height,
292 wrapPersistent(resolver)))); 310 convertToBaseCallback(WTF::bind(&ShapeDetector::onDetectFaces,
311 wrapPersistent(this),
312 wrapPersistent(resolver))));
313 } else if (detectorType == DetectorType::Barcode) {
314 m_service->DetectBarcodes(
315 std::move(sharedBufferHandle), width, height,
316 convertToBaseCallback(WTF::bind(&ShapeDetector::onDetectBarcodes,
317 wrapPersistent(this),
318 wrapPersistent(resolver))));
319 } else {
320 NOTREACHED() << "Unsupported detector type";
321 }
293 sharedBufferHandle.reset(); 322 sharedBufferHandle.reset();
294 return promise; 323 return promise;
295 } 324 }
296 325
297 void FaceDetector::onDetectFace( 326 void ShapeDetector::onDetectFaces(
298 ScriptPromiseResolver* resolver, 327 ScriptPromiseResolver* resolver,
299 mojom::blink::FaceDetectionResultPtr faceDetectionResult) { 328 mojom::blink::FaceDetectionResultPtr faceDetectionResult) {
300 if (!m_serviceRequests.contains(resolver)) 329 if (!m_serviceRequests.contains(resolver))
301 return; 330 return;
302 331
303 HeapVector<Member<DOMRect>> detectedFaces; 332 HeapVector<Member<DOMRect>> detectedFaces;
304 for (const auto& boundingBox : faceDetectionResult->boundingBoxes) { 333 for (const auto& boundingBox : faceDetectionResult->boundingBoxes) {
305 detectedFaces.append(DOMRect::create(boundingBox->x, boundingBox->y, 334 detectedFaces.append(DOMRect::create(boundingBox->x, boundingBox->y,
306 boundingBox->width, 335 boundingBox->width,
307 boundingBox->height)); 336 boundingBox->height));
308 } 337 }
309 338
310 resolver->resolve(detectedFaces); 339 resolver->resolve(detectedFaces);
311 m_serviceRequests.remove(resolver); 340 m_serviceRequests.remove(resolver);
312 } 341 }
313 342
314 DEFINE_TRACE(FaceDetector) { 343 void ShapeDetector::onDetectBarcodes(
344 ScriptPromiseResolver* resolver,
345 Vector<mojom::blink::BarcodeDetectionResultPtr> barcodeDetectionResults) {
346 if (!m_serviceRequests.contains(resolver))
347 return;
348 m_serviceRequests.remove(resolver);
349
350 HeapVector<Member<DetectedBarcode>> detectedBarcodes;
351 for (const auto& barcode : barcodeDetectionResults) {
352 detectedBarcodes.append(DetectedBarcode::create(
353 barcode->raw_value,
354 DOMRect::create(barcode->bounding_box->x, barcode->bounding_box->y,
355 barcode->bounding_box->width,
356 barcode->bounding_box->height)));
357 }
358
359 resolver->resolve(detectedBarcodes);
360 }
361
362 DEFINE_TRACE(ShapeDetector) {
315 visitor->trace(m_serviceRequests); 363 visitor->trace(m_serviceRequests);
316 } 364 }
317 365
318 } // namespace blink 366 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698