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/FaceDetector.h" | 5 #include "modules/shapedetection/FaceDetector.h" |
6 | 6 |
7 #include "bindings/core/v8/ScriptPromiseResolver.h" | |
8 #include "core/dom/DOMException.h" | 7 #include "core/dom/DOMException.h" |
| 8 #include "core/dom/DOMRect.h" |
| 9 #include "core/dom/Document.h" |
| 10 #include "core/fetch/ImageResource.h" |
| 11 #include "core/frame/LocalDOMWindow.h" |
| 12 #include "core/frame/LocalFrame.h" |
| 13 #include "core/html/HTMLImageElement.h" |
| 14 #include "platform/graphics/Image.h" |
| 15 #include "public/platform/InterfaceProvider.h" |
| 16 #include "third_party/skia/include/core/SkImage.h" |
| 17 #include "third_party/skia/include/core/SkImageInfo.h" |
9 | 18 |
10 namespace blink { | 19 namespace blink { |
11 | 20 |
12 FaceDetector* FaceDetector::create() { | 21 namespace { |
13 return new FaceDetector(); | 22 |
| 23 mojo::ScopedSharedBufferHandle getSharedBufferHandle( |
| 24 const HTMLImageElement* img) { |
| 25 ImageResource* const imageResource = img->cachedImage(); |
| 26 if (!imageResource) { |
| 27 DLOG(ERROR) << "Failed to convert HTMLImageElement to ImageSource."; |
| 28 return mojo::ScopedSharedBufferHandle(); |
| 29 } |
| 30 |
| 31 Image* const blinkImage = imageResource->getImage(); |
| 32 if (!blinkImage) { |
| 33 DLOG(ERROR) << "Failed to convert ImageSource to blink::Image."; |
| 34 return mojo::ScopedSharedBufferHandle(); |
| 35 } |
| 36 |
| 37 const sk_sp<SkImage> image = blinkImage->imageForCurrentFrame(); |
| 38 DCHECK_EQ(img->naturalWidth(), image->width()); |
| 39 DCHECK_EQ(img->naturalHeight(), image->height()); |
| 40 |
| 41 if (!image) { |
| 42 DLOG(ERROR) << "Failed to convert blink::Image to sk_sp<SkImage>."; |
| 43 return mojo::ScopedSharedBufferHandle(); |
| 44 } |
| 45 |
| 46 const SkImageInfo skiaInfo = |
| 47 SkImageInfo::MakeN32(image->width(), image->height(), image->alphaType()); |
| 48 |
| 49 const uint32_t allocationSize = skiaInfo.getSafeSize(skiaInfo.minRowBytes()); |
| 50 mojo::ScopedSharedBufferHandle sharedBufferHandle = |
| 51 mojo::SharedBufferHandle::Create(allocationSize); |
| 52 const mojo::ScopedSharedBufferMapping mappedBuffer = |
| 53 sharedBufferHandle->Map(allocationSize); |
| 54 DCHECK(mappedBuffer); |
| 55 |
| 56 const SkPixmap pixmap(skiaInfo, mappedBuffer.get(), skiaInfo.minRowBytes()); |
| 57 if (!image->readPixels(pixmap, 0, 0)) { |
| 58 DLOG(ERROR) << "Failed to read pixels from sk_sp<SkImage>."; |
| 59 return mojo::ScopedSharedBufferHandle(); |
| 60 } |
| 61 |
| 62 return sharedBufferHandle; |
| 63 } |
| 64 |
| 65 } // anonymous namespace |
| 66 |
| 67 FaceDetector* FaceDetector::create(ScriptState* scriptState) { |
| 68 return new FaceDetector(*scriptState->domWindow()->frame()); |
| 69 } |
| 70 |
| 71 FaceDetector::FaceDetector(LocalFrame& frame) { |
| 72 DCHECK(!m_service.is_bound()); |
| 73 DCHECK(frame.interfaceProvider()); |
| 74 frame.interfaceProvider()->getInterface(mojo::GetProxy(&m_service)); |
14 } | 75 } |
15 | 76 |
16 ScriptPromise FaceDetector::detect(ScriptState* scriptState, | 77 ScriptPromise FaceDetector::detect(ScriptState* scriptState, |
17 const HTMLImageElement* image) { | 78 const HTMLImageElement* img) { |
18 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); | 79 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); |
19 ScriptPromise promise = resolver->promise(); | 80 ScriptPromise promise = resolver->promise(); |
20 resolver->reject(DOMException::create(NotSupportedError, "Not implemented")); | 81 |
| 82 if (!m_service) { |
| 83 resolver->reject(DOMException::create( |
| 84 NotFoundError, "Face detection service unavailable.")); |
| 85 return promise; |
| 86 } |
| 87 |
| 88 if (!img) { |
| 89 resolver->reject(DOMException::create( |
| 90 SyntaxError, "The provided HTMLImageElement is empty.")); |
| 91 return promise; |
| 92 } |
| 93 |
| 94 // TODO(xianglu): Add security check when the spec is ready. |
| 95 // https://crbug.com/646083 |
| 96 mojo::ScopedSharedBufferHandle sharedBufferHandle = |
| 97 getSharedBufferHandle(img); |
| 98 if (!sharedBufferHandle->is_valid()) { |
| 99 resolver->reject( |
| 100 DOMException::create(SyntaxError, "Failed to get sharedBufferHandle.")); |
| 101 return promise; |
| 102 } |
| 103 |
| 104 m_serviceRequests.add(resolver); |
| 105 DCHECK(m_service.is_bound()); |
| 106 m_service->DetectFace(std::move(sharedBufferHandle), img->naturalWidth(), |
| 107 img->naturalHeight(), |
| 108 convertToBaseCallback(WTF::bind( |
| 109 &FaceDetector::onDetectFace, wrapPersistent(this), |
| 110 wrapPersistent(resolver)))); |
| 111 sharedBufferHandle.reset(); |
21 return promise; | 112 return promise; |
22 } | 113 } |
23 | 114 |
| 115 void FaceDetector::onDetectFace( |
| 116 ScriptPromiseResolver* resolver, |
| 117 mojom::blink::FaceDetectionResultPtr faceDetectionResult) { |
| 118 if (!m_serviceRequests.contains(resolver)) |
| 119 return; |
| 120 |
| 121 HeapVector<Member<DOMRect>> detectedFaces; |
| 122 for (const auto& boundingBox : faceDetectionResult->boundingBoxes) { |
| 123 detectedFaces.append(DOMRect::create(boundingBox->x, boundingBox->y, |
| 124 boundingBox->width, |
| 125 boundingBox->height)); |
| 126 } |
| 127 |
| 128 resolver->resolve(detectedFaces); |
| 129 m_serviceRequests.remove(resolver); |
| 130 } |
| 131 |
| 132 DEFINE_TRACE(FaceDetector) { |
| 133 visitor->trace(m_serviceRequests); |
| 134 } |
| 135 |
24 } // namespace blink | 136 } // namespace blink |
OLD | NEW |