Chromium Code Reviews| Index: third_party/WebKit/Source/modules/shapedetection/ShapeDetector.cpp |
| diff --git a/third_party/WebKit/Source/modules/shapedetection/ShapeDetector.cpp b/third_party/WebKit/Source/modules/shapedetection/ShapeDetector.cpp |
| index abfa2e3ddf937b308d08632890be87dd3294b2fc..5f51769a7f04a06b425ca9bd328eb5606a60d84e 100644 |
| --- a/third_party/WebKit/Source/modules/shapedetection/ShapeDetector.cpp |
| +++ b/third_party/WebKit/Source/modules/shapedetection/ShapeDetector.cpp |
| @@ -9,14 +9,11 @@ |
| #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 "modules/shapedetection/DetectedBarcode.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" |
| @@ -44,91 +41,67 @@ static CanvasImageSource* toImageSourceInternal( |
| } // anonymous namespace |
| ShapeDetector::ShapeDetector(LocalFrame& frame) { |
| - DCHECK(!m_faceService.is_bound()); |
| - DCHECK(!m_barcodeService.is_bound()); |
| DCHECK(frame.interfaceProvider()); |
| - frame.interfaceProvider()->getInterface(mojo::GetProxy(&m_faceService)); |
| - frame.interfaceProvider()->getInterface(mojo::GetProxy(&m_barcodeService)); |
| - m_faceService.set_connection_error_handler(convertToBaseCallback(WTF::bind( |
| - &ShapeDetector::onFaceServiceConnectionError, wrapWeakPersistent(this)))); |
| - m_barcodeService.set_connection_error_handler(convertToBaseCallback( |
| - WTF::bind(&ShapeDetector::onBarcodeServiceConnectionError, |
| - wrapWeakPersistent(this)))); |
| } |
| -ShapeDetector::ShapeDetector(LocalFrame& frame, |
| - const FaceDetectorOptions& options) |
| - : ShapeDetector(frame) { |
| - m_faceDetectorOptions = mojom::blink::FaceDetectorOptions::New(); |
| - m_faceDetectorOptions->max_detected_faces = options.maxDetectedFaces(); |
| - m_faceDetectorOptions->fast_mode = options.fastMode(); |
| -} |
| - |
| -ScriptPromise ShapeDetector::detectShapes( |
| +bool ShapeDetector::preprocessImageSource( |
| ScriptState* scriptState, |
| - DetectorType detectorType, |
| + ScriptPromiseResolver* resolver, |
| 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; |
| + return false; |
| } |
| if (imageSourceInternal->wouldTaintOrigin( |
| scriptState->getExecutionContext()->getSecurityOrigin())) { |
| resolver->reject( |
| DOMException::create(SecurityError, "Source would taint origin.")); |
| - return promise; |
| + return false; |
| } |
| if (imageSource.isHTMLImageElement()) { |
| - return detectShapesOnImageElement( |
| - detectorType, resolver, |
| - static_cast<HTMLImageElement*>(imageSourceInternal)); |
| + return preprocessImageElement( |
| + resolver, static_cast<HTMLImageElement*>(imageSourceInternal)); |
| } |
| if (imageSourceInternal->isImageBitmap()) { |
| - return detectShapesOnImageBitmap( |
| - detectorType, resolver, static_cast<ImageBitmap*>(imageSourceInternal)); |
| + return preprocessImageBitmap( |
| + resolver, static_cast<ImageBitmap*>(imageSourceInternal)); |
| } |
| if (imageSourceInternal->isVideoElement()) { |
| - return detectShapesOnVideoElement( |
| - detectorType, resolver, |
| - static_cast<HTMLVideoElement*>(imageSourceInternal)); |
| + return preprocessVideoElement( |
| + resolver, static_cast<HTMLVideoElement*>(imageSourceInternal)); |
| } |
| NOTREACHED(); |
| - return promise; |
| + return false; |
| } |
| -ScriptPromise ShapeDetector::detectShapesOnImageElement( |
| - DetectorType detectorType, |
| - ScriptPromiseResolver* resolver, |
| - const HTMLImageElement* img) { |
| - ScriptPromise promise = resolver->promise(); |
| +bool ShapeDetector::preprocessImageElement(ScriptPromiseResolver* resolver, |
| + const HTMLImageElement* img) { |
| if (img->bitmapSourceSize().isZero()) { |
| resolver->resolve(HeapVector<Member<DOMRect>>()); |
| - return promise; |
| + return false; |
| } |
| ImageResource* const imageResource = img->cachedImage(); |
| if (!imageResource || imageResource->errorOccurred()) { |
| resolver->reject(DOMException::create( |
| InvalidStateError, "Failed to load or decode HTMLImageElement.")); |
| - return promise; |
| + return false; |
| } |
| Image* const blinkImage = imageResource->getImage(); |
| if (!blinkImage) { |
| resolver->reject(DOMException::create( |
| InvalidStateError, "Failed to get image from resource.")); |
| - return promise; |
| + return false; |
| } |
| const sk_sp<SkImage> image = blinkImage->imageForCurrentFrame(); |
| @@ -138,7 +111,7 @@ ScriptPromise ShapeDetector::detectShapesOnImageElement( |
| if (!image) { |
| resolver->reject(DOMException::create( |
| InvalidStateError, "Failed to get image from current frame.")); |
| - return promise; |
| + return false; |
| } |
| const SkImageInfo skiaInfo = |
| @@ -146,9 +119,8 @@ ScriptPromise ShapeDetector::detectShapesOnImageElement( |
| const uint32_t allocationSize = skiaInfo.getSafeSize(skiaInfo.minRowBytes()); |
| - mojo::ScopedSharedBufferHandle sharedBufferHandle = |
| - mojo::SharedBufferHandle::Create(allocationSize); |
| - if (!sharedBufferHandle.is_valid()) { |
| + m_sharedBufferHandle = mojo::SharedBufferHandle::Create(allocationSize); |
| + if (!m_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. |
| @@ -156,66 +128,37 @@ ScriptPromise ShapeDetector::detectShapesOnImageElement( |
| // Also, add LayoutTests for this case later. |
| resolver->reject( |
| DOMException::create(InvalidStateError, "Image exceeds size limit.")); |
| - return promise; |
| + return false; |
| } |
| const mojo::ScopedSharedBufferMapping mappedBuffer = |
| - sharedBufferHandle->Map(allocationSize); |
| + m_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; |
| + return false; |
| } |
| - if (detectorType == DetectorType::Face) { |
| - if (!m_faceService) { |
| - resolver->reject(DOMException::create( |
| - NotSupportedError, "Face detection service unavailable.")); |
| - return promise; |
| - } |
| - m_faceServiceRequests.add(resolver); |
| - m_faceService->Detect(std::move(sharedBufferHandle), img->naturalWidth(), |
| - img->naturalHeight(), m_faceDetectorOptions.Clone(), |
| - convertToBaseCallback(WTF::bind( |
| - &ShapeDetector::onDetectFaces, |
| - wrapPersistent(this), wrapPersistent(resolver)))); |
| - } else if (detectorType == DetectorType::Barcode) { |
| - if (!m_barcodeService) { |
| - resolver->reject(DOMException::create( |
| - NotSupportedError, "Barcode detection service unavailable.")); |
| - return promise; |
| - } |
| - m_barcodeServiceRequests.add(resolver); |
| - m_barcodeService->Detect( |
| - std::move(sharedBufferHandle), img->naturalWidth(), |
| - img->naturalHeight(), |
| - convertToBaseCallback(WTF::bind(&ShapeDetector::onDetectBarcodes, |
| - wrapPersistent(this), |
| - wrapPersistent(resolver)))); |
| - } else { |
| - NOTREACHED() << "Unsupported detector type"; |
| - } |
| + m_imageWidth = img->naturalWidth(); |
| + m_imageHeight = img->naturalHeight(); |
|
mcasas
2016/12/06 04:40:20
Instead of holding on to |m_sharedBufferHandle|,
|
xianglu
2016/12/06 20:20:10
Done.
|
| - return promise; |
| + return true; |
| } |
| -ScriptPromise ShapeDetector::detectShapesOnImageBitmap( |
| - DetectorType detectorType, |
| - ScriptPromiseResolver* resolver, |
| - ImageBitmap* imageBitmap) { |
| - ScriptPromise promise = resolver->promise(); |
| +bool ShapeDetector::preprocessImageBitmap(ScriptPromiseResolver* resolver, |
| + ImageBitmap* imageBitmap) { |
| if (!imageBitmap->originClean()) { |
| resolver->reject( |
| DOMException::create(SecurityError, "ImageBitmap is not origin clean")); |
| - return promise; |
| + return false; |
| } |
| if (imageBitmap->size().area() == 0) { |
| resolver->resolve(HeapVector<Member<DOMRect>>()); |
| - return promise; |
| + return false; |
| } |
| SkPixmap pixmap; |
| @@ -237,17 +180,15 @@ ScriptPromise ShapeDetector::detectShapesOnImageBitmap( |
| allocationSize = imageBitmap->size().area() * 4 /* bytes per pixel */; |
| } |
| - return detectShapesOnData(detectorType, resolver, pixelDataPtr, |
| - allocationSize.ValueOrDefault(0), |
| - imageBitmap->width(), imageBitmap->height()); |
| + m_imageWidth = imageBitmap->width(); |
| + m_imageHeight = imageBitmap->height(); |
| + return getSharedBufferOnData(resolver, pixelDataPtr, |
| + allocationSize.ValueOrDefault(0), |
| + imageBitmap->width(), imageBitmap->height()); |
| } |
| -ScriptPromise ShapeDetector::detectShapesOnVideoElement( |
| - DetectorType detectorType, |
| - ScriptPromiseResolver* resolver, |
| - const HTMLVideoElement* video) { |
| - ScriptPromise promise = resolver->promise(); |
| - |
| +bool ShapeDetector::preprocessVideoElement(ScriptPromiseResolver* resolver, |
| + const HTMLVideoElement* video) { |
| // 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 |
| @@ -257,7 +198,7 @@ ScriptPromise ShapeDetector::detectShapesOnVideoElement( |
| if (!video->hasAvailableVideoFrame()) { |
| resolver->reject(DOMException::create( |
| InvalidStateError, "Invalid HTMLVideoElement or state.")); |
| - return promise; |
| + return false; |
| } |
| const FloatSize videoSize(video->videoWidth(), video->videoHeight()); |
| @@ -282,124 +223,39 @@ ScriptPromise ShapeDetector::detectShapesOnVideoElement( |
| NOTREACHED(); |
| resolver->reject(DOMException::create( |
| InvalidStateError, "Failed to get pixels for current frame.")); |
| - return promise; |
| + return false; |
| } |
| - return detectShapesOnData(detectorType, resolver, pixelDataPtr, |
| - allocationSize.ValueOrDefault(0), image->width(), |
| - image->height()); |
| + m_imageWidth = image->width(); |
| + m_imageHeight = image->height(); |
| + return getSharedBufferOnData(resolver, pixelDataPtr, |
| + allocationSize.ValueOrDefault(0), image->width(), |
| + image->height()); |
| } |
| -ScriptPromise ShapeDetector::detectShapesOnData(DetectorType detectorType, |
| - ScriptPromiseResolver* resolver, |
| - uint8_t* data, |
| - int size, |
| - int width, |
| - int height) { |
| +bool ShapeDetector::getSharedBufferOnData(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()) { |
| + m_sharedBufferHandle = mojo::SharedBufferHandle::Create(size); |
| + if (!m_sharedBufferHandle->is_valid()) { |
| resolver->reject( |
| DOMException::create(InvalidStateError, "Internal allocation error")); |
| - return promise; |
| + return false; |
| } |
| const mojo::ScopedSharedBufferMapping mappedBuffer = |
| - sharedBufferHandle->Map(size); |
| + m_sharedBufferHandle->Map(size); |
| DCHECK(mappedBuffer.get()); |
| memcpy(mappedBuffer.get(), data, size); |
| - if (detectorType == DetectorType::Face) { |
| - if (!m_faceService) { |
| - resolver->reject(DOMException::create( |
| - NotSupportedError, "Face detection service unavailable.")); |
| - return promise; |
| - } |
| - m_faceServiceRequests.add(resolver); |
| - m_faceService->Detect(std::move(sharedBufferHandle), width, height, |
| - m_faceDetectorOptions.Clone(), |
| - convertToBaseCallback(WTF::bind( |
| - &ShapeDetector::onDetectFaces, |
| - wrapPersistent(this), wrapPersistent(resolver)))); |
| - } else if (detectorType == DetectorType::Barcode) { |
| - if (!m_barcodeService) { |
| - resolver->reject(DOMException::create( |
| - NotSupportedError, "Barcode detection service unavailable.")); |
| - return promise; |
| - } |
| - m_barcodeServiceRequests.add(resolver); |
| - m_barcodeService->Detect( |
| - std::move(sharedBufferHandle), width, height, |
| - convertToBaseCallback(WTF::bind(&ShapeDetector::onDetectBarcodes, |
| - wrapPersistent(this), |
| - wrapPersistent(resolver)))); |
| - } else { |
| - NOTREACHED() << "Unsupported detector type"; |
| - } |
| - sharedBufferHandle.reset(); |
| - return promise; |
| -} |
| - |
| -void ShapeDetector::onDetectFaces( |
| - ScriptPromiseResolver* resolver, |
| - mojom::blink::FaceDetectionResultPtr faceDetectionResult) { |
| - DCHECK(m_faceServiceRequests.contains(resolver)); |
| - m_faceServiceRequests.remove(resolver); |
| - |
| - HeapVector<Member<DOMRect>> detectedFaces; |
| - for (const auto& boundingBox : faceDetectionResult->bounding_boxes) { |
| - detectedFaces.append(DOMRect::create(boundingBox->x, boundingBox->y, |
| - boundingBox->width, |
| - boundingBox->height)); |
| - } |
| - |
| - resolver->resolve(detectedFaces); |
| -} |
| - |
| -void ShapeDetector::onDetectBarcodes( |
| - ScriptPromiseResolver* resolver, |
| - Vector<mojom::blink::BarcodeDetectionResultPtr> barcodeDetectionResults) { |
| - DCHECK(m_barcodeServiceRequests.contains(resolver)); |
| - m_barcodeServiceRequests.remove(resolver); |
| - |
| - HeapVector<Member<DetectedBarcode>> detectedBarcodes; |
| - for (const auto& barcode : barcodeDetectionResults) { |
| - detectedBarcodes.append(DetectedBarcode::create( |
| - barcode->raw_value, |
| - DOMRect::create(barcode->bounding_box->x, barcode->bounding_box->y, |
| - barcode->bounding_box->width, |
| - barcode->bounding_box->height))); |
| - } |
| - |
| - resolver->resolve(detectedBarcodes); |
| + return true; |
| } |
| -void ShapeDetector::onFaceServiceConnectionError() { |
| - for (const auto& request : m_faceServiceRequests) { |
| - request->reject(DOMException::create(NotSupportedError, |
| - "Face Detection not implemented.")); |
| - } |
| - m_faceServiceRequests.clear(); |
| - m_faceService.reset(); |
| -} |
| - |
| -void ShapeDetector::onBarcodeServiceConnectionError() { |
| - for (const auto& request : m_barcodeServiceRequests) { |
| - request->reject(DOMException::create(NotSupportedError, |
| - "Barcode Detection not implemented.")); |
| - } |
| - m_barcodeServiceRequests.clear(); |
| - m_barcodeService.reset(); |
| -} |
| - |
| -DEFINE_TRACE(ShapeDetector) { |
| - visitor->trace(m_faceServiceRequests); |
| - visitor->trace(m_barcodeServiceRequests); |
| -} |
| } // namespace blink |