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

Unified Diff: third_party/WebKit/Source/modules/shapedetection/FaceDetector.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 side-by-side diff with in-line comments
Download patch
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 eadf3eb0ae2c8255c96b8c4b276a634b3d7c8022..3c37c16418579dff55b4361b5e935562045fdc9f 100644
--- a/third_party/WebKit/Source/modules/shapedetection/FaceDetector.cpp
+++ b/third_party/WebKit/Source/modules/shapedetection/FaceDetector.cpp
@@ -5,314 +5,26 @@
#include "modules/shapedetection/FaceDetector.h"
#include "core/dom/DOMException.h"
-#include "core/dom/DOMRect.h"
-#include "core/dom/Document.h"
-#include "core/fetch/ImageResource.h"
-#include "core/frame/ImageBitmap.h"
#include "core/frame/LocalDOMWindow.h"
#include "core/frame/LocalFrame.h"
-#include "core/html/HTMLImageElement.h"
-#include "core/html/HTMLVideoElement.h"
#include "core/html/canvas/CanvasImageSource.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"
-#include "wtf/CheckedNumeric.h"
namespace blink {
-namespace {
-
-static CanvasImageSource* toImageSourceInternal(
- const CanvasImageSourceUnion& value) {
- if (value.isHTMLImageElement())
- return value.getAsHTMLImageElement();
-
- if (value.isImageBitmap() &&
- !static_cast<ImageBitmap*>(value.getAsImageBitmap())->isNeutered()) {
- return value.getAsImageBitmap();
- }
-
- if (value.isHTMLVideoElement())
- return value.getAsHTMLVideoElement();
-
- return nullptr;
-}
-
-} // anonymous namespace
-
FaceDetector* FaceDetector::create(ScriptState* scriptState) {
return new FaceDetector(*scriptState->domWindow()->frame());
}
-FaceDetector::FaceDetector(LocalFrame& frame) {
- DCHECK(!m_service.is_bound());
- DCHECK(frame.interfaceProvider());
- frame.interfaceProvider()->getInterface(mojo::GetProxy(&m_service));
-}
+FaceDetector::FaceDetector(LocalFrame& frame) : ShapeDetector(frame) {}
ScriptPromise FaceDetector::detect(ScriptState* scriptState,
const CanvasImageSourceUnion& imageSource) {
- CanvasImageSource* imageSourceInternal = toImageSourceInternal(imageSource);
-
- ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
- ScriptPromise promise = resolver->promise();
-
- if (!imageSourceInternal) {
- // TODO(mcasas): Implement more CanvasImageSources, https://crbug.com/659138
- NOTIMPLEMENTED() << "Unsupported CanvasImageSource";
- resolver->reject(
- DOMException::create(NotFoundError, "Unsupported source."));
- return promise;
- }
-
- if (imageSourceInternal->wouldTaintOrigin(
- scriptState->getExecutionContext()->getSecurityOrigin())) {
- resolver->reject(
- DOMException::create(SecurityError, "Source would taint origin."));
- return promise;
- }
-
- if (imageSource.isHTMLImageElement()) {
- return detectFacesOnImageElement(
- resolver, static_cast<HTMLImageElement*>(imageSourceInternal));
- }
- if (imageSourceInternal->isImageBitmap()) {
- return detectFacesOnImageBitmap(
- resolver, static_cast<ImageBitmap*>(imageSourceInternal));
- }
- if (imageSourceInternal->isVideoElement()) {
- return detectFacesOnVideoElement(
- resolver, static_cast<HTMLVideoElement*>(imageSourceInternal));
- }
-
- NOTREACHED();
- return promise;
-}
-
-ScriptPromise FaceDetector::detectFacesOnImageElement(
- ScriptPromiseResolver* resolver,
- const HTMLImageElement* img) {
- ScriptPromise promise = resolver->promise();
- if (img->bitmapSourceSize().isZero()) {
- resolver->resolve(HeapVector<Member<DOMRect>>());
- return promise;
- }
-
- ImageResource* const imageResource = img->cachedImage();
- if (!imageResource || imageResource->errorOccurred()) {
- resolver->reject(DOMException::create(
- InvalidStateError, "Failed to load or decode HTMLImageElement."));
- return promise;
- }
-
- Image* const blinkImage = imageResource->getImage();
- if (!blinkImage) {
- resolver->reject(DOMException::create(
- InvalidStateError, "Failed to get image from resource."));
- return promise;
- }
-
- const sk_sp<SkImage> image = blinkImage->imageForCurrentFrame();
- DCHECK_EQ(img->naturalWidth(), static_cast<unsigned>(image->width()));
- DCHECK_EQ(img->naturalHeight(), static_cast<unsigned>(image->height()));
-
- if (!image) {
- resolver->reject(DOMException::create(
- InvalidStateError, "Failed to get image from current frame."));
- return promise;
- }
-
- 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);
- if (!sharedBufferHandle.is_valid()) {
- DLOG(ERROR) << "Requested allocation : " << allocationSize
- << "B, larger than |mojo::edk::kMaxSharedBufferSize| == 16MB ";
- // TODO(xianglu): For now we reject the promise if the image is too large.
- // But consider resizing the image to remove restriction on the user side.
- // Also, add LayoutTests for this case later.
- resolver->reject(
- DOMException::create(InvalidStateError, "Image exceeds size limit."));
- return promise;
- }
-
- const mojo::ScopedSharedBufferMapping mappedBuffer =
- sharedBufferHandle->Map(allocationSize);
-
- const SkPixmap pixmap(skiaInfo, mappedBuffer.get(), skiaInfo.minRowBytes());
- if (!image->readPixels(pixmap, 0, 0)) {
- resolver->reject(DOMException::create(
- InvalidStateError,
- "Failed to read pixels: Unable to decompress or unsupported format."));
- return promise;
- }
-
- if (!m_service) {
- resolver->reject(DOMException::create(
- NotSupportedError, "Face detection service unavailable."));
- 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))));
- return promise;
-}
-
-ScriptPromise FaceDetector::detectFacesOnImageBitmap(
- ScriptPromiseResolver* resolver,
- ImageBitmap* imageBitmap) {
- ScriptPromise promise = resolver->promise();
- if (!imageBitmap->originClean()) {
- resolver->reject(
- DOMException::create(SecurityError, "ImageBitmap is not origin clean"));
- return promise;
- }
-
- if (imageBitmap->size().area() == 0) {
- resolver->resolve(HeapVector<Member<DOMRect>>());
- return promise;
- }
-
- SkPixmap pixmap;
- RefPtr<Uint8Array> pixelData;
- uint8_t* pixelDataPtr = nullptr;
- WTF::CheckedNumeric<int> allocationSize = 0;
- // Use |skImage|'s pixels if it has direct access to them, otherwise retrieve
- // them from elsewhere via copyBitmapData().
- sk_sp<SkImage> skImage = imageBitmap->bitmapImage()->imageForCurrentFrame();
- if (skImage->peekPixels(&pixmap)) {
- pixelDataPtr = static_cast<uint8_t*>(pixmap.writable_addr());
- allocationSize = pixmap.getSafeSize();
- } else {
- pixelData = imageBitmap->copyBitmapData(imageBitmap->isPremultiplied()
- ? PremultiplyAlpha
- : DontPremultiplyAlpha,
- N32ColorType);
- pixelDataPtr = pixelData->data();
- allocationSize = imageBitmap->size().area() * 4 /* bytes per pixel */;
- }
-
- return detectFacesOnData(resolver, pixelDataPtr,
- allocationSize.ValueOrDefault(0),
- imageBitmap->width(), imageBitmap->height());
-}
-
-ScriptPromise FaceDetector::detectFacesOnVideoElement(
- ScriptPromiseResolver* resolver,
- const HTMLVideoElement* video) {
- ScriptPromise promise = resolver->promise();
-
- // TODO(mcasas): Check if |video| is actually playing a MediaStream by using
- // HTMLMediaElement::isMediaStreamURL(video->currentSrc().getString()); if
- // there is a local WebCam associated, there might be sophisticated ways to
- // detect faces on it. Until then, treat as a normal <video> element.
-
- // !hasAvailableVideoFrame() is a bundle of invalid states.
- if (!video->hasAvailableVideoFrame()) {
- resolver->reject(DOMException::create(
- InvalidStateError, "Invalid HTMLVideoElement or state."));
- return promise;
- }
-
- const FloatSize videoSize(video->videoWidth(), video->videoHeight());
- SourceImageStatus sourceImageStatus = InvalidSourceImageStatus;
- RefPtr<Image> image =
- video->getSourceImageForCanvas(&sourceImageStatus, PreferNoAcceleration,
- SnapshotReasonDrawImage, videoSize);
-
- DCHECK_EQ(NormalSourceImageStatus, sourceImageStatus);
-
- SkPixmap pixmap;
- RefPtr<Uint8Array> pixelData;
- uint8_t* pixelDataPtr = nullptr;
- WTF::CheckedNumeric<int> allocationSize = 0;
- // Use |skImage|'s pixels if it has direct access to them.
- sk_sp<SkImage> skImage = image->imageForCurrentFrame();
- if (skImage->peekPixels(&pixmap)) {
- pixelDataPtr = static_cast<uint8_t*>(pixmap.writable_addr());
- allocationSize = pixmap.getSafeSize();
- } else {
- // TODO(mcasas): retrieve the pixels from elsewhere.
- NOTREACHED();
- resolver->reject(DOMException::create(
- InvalidStateError, "Failed to get pixels for current frame."));
- return promise;
- }
-
- return detectFacesOnData(resolver, pixelDataPtr,
- allocationSize.ValueOrDefault(0), image->width(),
- image->height());
-}
-
-ScriptPromise FaceDetector::detectFacesOnData(ScriptPromiseResolver* resolver,
- uint8_t* data,
- int size,
- int width,
- int height) {
- DCHECK(data);
- DCHECK(size);
- ScriptPromise promise = resolver->promise();
-
- mojo::ScopedSharedBufferHandle sharedBufferHandle =
- mojo::SharedBufferHandle::Create(size);
- if (!sharedBufferHandle->is_valid()) {
- resolver->reject(
- DOMException::create(InvalidStateError, "Internal allocation error"));
- return promise;
- }
-
- if (!m_service) {
- resolver->reject(DOMException::create(
- NotSupportedError, "Face detection service unavailable."));
- return promise;
- }
-
- const mojo::ScopedSharedBufferMapping mappedBuffer =
- sharedBufferHandle->Map(size);
- DCHECK(mappedBuffer.get());
-
- memcpy(mappedBuffer.get(), data, size);
-
- m_serviceRequests.add(resolver);
- DCHECK(m_service.is_bound());
- m_service->DetectFace(std::move(sharedBufferHandle), width, height,
- 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,
- boundingBox->width,
- boundingBox->height));
- }
-
- resolver->resolve(detectedFaces);
- m_serviceRequests.remove(resolver);
+ return detectShapes(scriptState, ShapeDetector::DetectorType::Face,
+ imageSource);
}
DEFINE_TRACE(FaceDetector) {
- visitor->trace(m_serviceRequests);
+ ShapeDetector::trace(visitor);
}
} // namespace blink

Powered by Google App Engine
This is Rietveld 408576698