Index: third_party/WebKit/Source/modules/shapedetection/FaceDetector.cpp |
diff --git a/third_party/WebKit/Source/modules/shapedetection/FaceDetector.cpp b/third_party/WebKit/Source/modules/shapedetection/FaceDetector.cpp |
index 0f0d5f4b3e87bba02c85682f9cc5f14f3c08d13b..08e423d9d7a6674651df1cb50983fb678c48e721 100644 |
--- a/third_party/WebKit/Source/modules/shapedetection/FaceDetector.cpp |
+++ b/third_party/WebKit/Source/modules/shapedetection/FaceDetector.cpp |
@@ -4,21 +4,131 @@ |
#include "modules/shapedetection/FaceDetector.h" |
-#include "bindings/core/v8/ScriptPromiseResolver.h" |
#include "core/dom/DOMException.h" |
+#include "core/dom/DOMRect.h" |
+#include "core/dom/Document.h" |
+#include "core/fetch/ImageResource.h" |
+#include "core/frame/LocalFrame.h" |
+#include "core/html/HTMLImageElement.h" |
+#include "platform/graphics/Image.h" |
+#include "public/platform/InterfaceProvider.h" |
+#include "third_party/skia/include/core/SkImage.h" |
+#include "third_party/skia/include/core/SkImageInfo.h" |
namespace blink { |
-FaceDetector* FaceDetector::create() { |
- return new FaceDetector(); |
+namespace { |
+ |
+mojo::ScopedSharedBufferHandle getSharedBufferHandle( |
+ const HTMLImageElement* img) { |
+ ImageResource* const imageResource = img->cachedImage(); |
+ if (!imageResource) { |
+ DLOG(ERROR) << "Failed to convert HTMLImageElement to ImageSource."; |
+ return mojo::ScopedSharedBufferHandle(); |
+ } |
+ |
+ Image* const blinkImage = imageResource->getImage(); |
+ if (!blinkImage) { |
+ DLOG(ERROR) << "Failed to convert ImageSource to blink::Image."; |
mcasas
2016/10/03 22:18:09
nit: just for cases like this, we can also conside
xianglu
2016/10/04 00:58:26
Yeah. But in that way the message will be too long
|
+ return mojo::ScopedSharedBufferHandle(); |
+ } |
+ |
+ const sk_sp<SkImage> image = blinkImage->imageForCurrentFrame(); |
+ DCHECK_EQ(img->naturalWidth(), image->width()); |
+ DCHECK_EQ(img->naturalHeight(), image->height()); |
+ |
+ if (!image) { |
+ DLOG(ERROR) << "Failed to convert blink::Image to sk_sp<SkImage>."; |
+ return mojo::ScopedSharedBufferHandle(); |
+ } |
+ |
+ const SkImageInfo skiaInfo = |
+ SkImageInfo::MakeN32(image->width(), image->height(), image->alphaType()); |
+ |
+ const uint32_t allocationSize = skiaInfo.getSafeSize(skiaInfo.minRowBytes()); |
+ mojo::ScopedSharedBufferHandle sharedBufferHandle = |
+ mojo::SharedBufferHandle::Create(allocationSize); |
+ const mojo::ScopedSharedBufferMapping mappedBuffer = |
+ sharedBufferHandle->Map(allocationSize); |
+ DCHECK(mappedBuffer); |
+ |
+ const SkPixmap pixmap(skiaInfo, mappedBuffer.get(), skiaInfo.minRowBytes()); |
+ if (!image->readPixels(pixmap, 0, 0)) { |
+ DLOG(ERROR) << "Failed to read pixels from sk_sp<SkImage>."; |
+ return mojo::ScopedSharedBufferHandle(); |
+ } |
+ |
+ return sharedBufferHandle; |
+} |
+ |
+} // anonymous namespace |
+ |
+FaceDetector* FaceDetector::create(const Document& document) { |
+ return new FaceDetector(*document.frame()); |
+} |
+ |
+FaceDetector::FaceDetector(LocalFrame& frame) { |
+ DCHECK(!m_service.is_bound()); |
+ DCHECK(frame.interfaceProvider()); |
+ frame.interfaceProvider()->getInterface(mojo::GetProxy(&m_service)); |
} |
ScriptPromise FaceDetector::detect(ScriptState* scriptState, |
- const HTMLImageElement* image) { |
+ const HTMLImageElement* img) { |
ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); |
ScriptPromise promise = resolver->promise(); |
- resolver->reject(DOMException::create(NotSupportedError, "Not implemented")); |
+ |
+ if (!m_service) { |
+ resolver->reject(DOMException::create( |
+ NotFoundError, "Face detection service unavailable.")); |
+ return promise; |
+ } |
+ |
+ if (!img) { |
+ resolver->reject(DOMException::create( |
+ SyntaxError, "The provided HTMLImageElement is empty.")); |
+ return promise; |
+ } |
+ |
+ // TODO(xianglu): Add security check when the spec is ready. https://crbug.com/646083 |
mcasas
2016/10/03 22:18:09
nit: reflow this comment line to 80 chars wide plz
xianglu
2016/10/04 00:58:26
Done.
|
+ mojo::ScopedSharedBufferHandle sharedBufferHandle = |
+ getSharedBufferHandle(img); |
+ if (!sharedBufferHandle->is_valid()) { |
+ resolver->reject( |
+ DOMException::create(SyntaxError, "Failed to get sharedBufferHandle.")); |
+ return promise; |
+ } |
+ |
+ m_serviceRequests.add(resolver); |
+ DCHECK(m_service.is_bound()); |
+ m_service->DetectFace(std::move(sharedBufferHandle), img->naturalWidth(), |
+ img->naturalHeight(), |
+ convertToBaseCallback(WTF::bind( |
+ &FaceDetector::onDetectFace, wrapPersistent(this), |
+ wrapPersistent(resolver)))); |
+ sharedBufferHandle.reset(); |
return promise; |
} |
+void FaceDetector::onDetectFace( |
+ ScriptPromiseResolver* resolver, |
+ mojom::blink::FaceDetectionResultPtr faceDetectionResult) { |
+ if (!m_serviceRequests.contains(resolver)) |
+ return; |
+ |
+ HeapVector<Member<DOMRect>> detectedFaces; |
+ for (const auto& boundingBox : faceDetectionResult->boundingBoxes) { |
+ detectedFaces.append(DOMRect::create(boundingBox->x, boundingBox->y, |
mcasas
2016/10/03 22:18:09
nit: consider adding here a contract on the boundi
xianglu
2016/10/04 00:58:26
Done.
|
+ boundingBox->width, |
+ boundingBox->height)); |
+ } |
+ |
+ resolver->resolve(detectedFaces); |
+ m_serviceRequests.remove(resolver); |
+} |
+ |
+DEFINE_TRACE(FaceDetector) { |
+ visitor->trace(m_serviceRequests); |
+} |
+ |
} // namespace blink |