| 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/ShapeDetector.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" |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 57 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); | 57 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); |
| 58 ScriptPromise promise = resolver->promise(); | 58 ScriptPromise promise = resolver->promise(); |
| 59 | 59 |
| 60 CanvasImageSource* canvasImageSource; | 60 CanvasImageSource* canvasImageSource; |
| 61 if (imageSource.isHTMLImageElement()) { | 61 if (imageSource.isHTMLImageElement()) { |
| 62 canvasImageSource = imageSource.getAsHTMLImageElement(); | 62 canvasImageSource = imageSource.getAsHTMLImageElement(); |
| 63 } else if (imageSource.isImageBitmap()) { | 63 } else if (imageSource.isImageBitmap()) { |
| 64 canvasImageSource = imageSource.getAsImageBitmap(); | 64 canvasImageSource = imageSource.getAsImageBitmap(); |
| 65 } else if (imageSource.isHTMLVideoElement()) { | 65 } else if (imageSource.isHTMLVideoElement()) { |
| 66 canvasImageSource = imageSource.getAsHTMLVideoElement(); | 66 canvasImageSource = imageSource.getAsHTMLVideoElement(); |
| 67 } else if (imageSource.isHTMLCanvasElement()) { |
| 68 canvasImageSource = imageSource.getAsHTMLCanvasElement(); |
| 69 } else if (imageSource.isOffscreenCanvas()) { |
| 70 canvasImageSource = imageSource.getAsOffscreenCanvas(); |
| 67 } else { | 71 } else { |
| 68 // TODO(mcasas): Implement more CanvasImageSources, https://crbug.com/659138 | 72 NOTREACHED() << "Unsupported CanvasImageSource"; |
| 69 NOTIMPLEMENTED() << "Unsupported CanvasImageSource"; | |
| 70 resolver->reject( | 73 resolver->reject( |
| 71 DOMException::create(NotFoundError, "Unsupported source.")); | 74 DOMException::create(NotSupportedError, "Unsupported source.")); |
| 72 return promise; | 75 return promise; |
| 73 } | 76 } |
| 74 | 77 |
| 75 if (canvasImageSource->wouldTaintOrigin( | 78 if (canvasImageSource->wouldTaintOrigin( |
| 76 scriptState->getExecutionContext()->getSecurityOrigin())) { | 79 scriptState->getExecutionContext()->getSecurityOrigin())) { |
| 77 resolver->reject( | 80 resolver->reject( |
| 78 DOMException::create(SecurityError, "Source would taint origin.")); | 81 DOMException::create(SecurityError, "Source would taint origin.")); |
| 79 return promise; | 82 return promise; |
| 80 } | 83 } |
| 81 | 84 |
| 82 if (imageSource.isHTMLImageElement()) { | 85 if (imageSource.isHTMLImageElement()) { |
| 83 return detectShapesOnImageElement(resolver, | 86 return detectShapesOnImageElement(resolver, |
| 84 imageSource.getAsHTMLImageElement()); | 87 imageSource.getAsHTMLImageElement()); |
| 85 } else if (imageSource.isImageBitmap()) { | |
| 86 return detectShapesOnImageBitmap(resolver, imageSource.getAsImageBitmap()); | |
| 87 } else if (imageSource.isHTMLVideoElement()) { | |
| 88 return detectShapesOnVideoElement(resolver, | |
| 89 imageSource.getAsHTMLVideoElement()); | |
| 90 } | 88 } |
| 91 | 89 |
| 92 NOTREACHED(); | 90 // TODO(mcasas): Check if |video| is actually playing a MediaStream by using |
| 93 return promise; | 91 // HTMLMediaElement::isMediaStreamURL(video->currentSrc().getString()); if |
| 92 // there is a local WebCam associated, there might be sophisticated ways to |
| 93 // detect faces on it. Until then, treat as a normal <video> element. |
| 94 |
| 95 const FloatSize size(canvasImageSource->sourceWidth(), |
| 96 canvasImageSource->sourceHeight()); |
| 97 |
| 98 SourceImageStatus sourceImageStatus = InvalidSourceImageStatus; |
| 99 RefPtr<Image> image = canvasImageSource->getSourceImageForCanvas( |
| 100 &sourceImageStatus, PreferNoAcceleration, SnapshotReasonDrawImage, size); |
| 101 if (!image || sourceImageStatus != NormalSourceImageStatus) { |
| 102 resolver->reject( |
| 103 DOMException::create(InvalidStateError, "Invalid element or state.")); |
| 104 return promise; |
| 105 } |
| 106 |
| 107 SkPixmap pixmap; |
| 108 RefPtr<Uint8Array> pixelData; |
| 109 uint8_t* pixelDataPtr = nullptr; |
| 110 WTF::CheckedNumeric<int> allocationSize = 0; |
| 111 |
| 112 sk_sp<SkImage> skImage = image->imageForCurrentFrame(); |
| 113 // Use |skImage|'s pixels if it has direct access to them. |
| 114 if (skImage->peekPixels(&pixmap)) { |
| 115 pixelDataPtr = static_cast<uint8_t*>(pixmap.writable_addr()); |
| 116 allocationSize = pixmap.getSafeSize(); |
| 117 } else if (imageSource.isImageBitmap()) { |
| 118 ImageBitmap* imageBitmap = imageSource.getAsImageBitmap(); |
| 119 pixelData = imageBitmap->copyBitmapData(imageBitmap->isPremultiplied() |
| 120 ? PremultiplyAlpha |
| 121 : DontPremultiplyAlpha, |
| 122 N32ColorType); |
| 123 pixelDataPtr = pixelData->data(); |
| 124 allocationSize = imageBitmap->size().area() * 4 /* bytes per pixel */; |
| 125 } else { |
| 126 // TODO(mcasas): retrieve the pixels from elsewhere. |
| 127 NOTREACHED(); |
| 128 resolver->reject(DOMException::create( |
| 129 InvalidStateError, "Failed to get pixels for current frame.")); |
| 130 return promise; |
| 131 } |
| 132 |
| 133 mojo::ScopedSharedBufferHandle sharedBufferHandle = getSharedBufferOnData( |
| 134 resolver, pixelDataPtr, allocationSize.ValueOrDefault(0)); |
| 135 if (!sharedBufferHandle->is_valid()) |
| 136 return promise; |
| 137 |
| 138 return doDetect(resolver, std::move(sharedBufferHandle), image->width(), |
| 139 image->height()); |
| 94 } | 140 } |
| 95 | 141 |
| 96 ScriptPromise ShapeDetector::detectShapesOnImageElement( | 142 ScriptPromise ShapeDetector::detectShapesOnImageElement( |
| 97 ScriptPromiseResolver* resolver, | 143 ScriptPromiseResolver* resolver, |
| 98 const HTMLImageElement* img) { | 144 const HTMLImageElement* img) { |
| 99 ScriptPromise promise = resolver->promise(); | 145 ScriptPromise promise = resolver->promise(); |
| 100 | 146 |
| 101 if (img->bitmapSourceSize().isZero()) { | 147 if (img->bitmapSourceSize().isZero()) { |
| 102 resolver->resolve(HeapVector<Member<DOMRect>>()); | 148 resolver->resolve(HeapVector<Member<DOMRect>>()); |
| 103 return promise; | 149 return promise; |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 153 resolver->reject(DOMException::create( | 199 resolver->reject(DOMException::create( |
| 154 InvalidStateError, | 200 InvalidStateError, |
| 155 "Failed to read pixels: Unable to decompress or unsupported format.")); | 201 "Failed to read pixels: Unable to decompress or unsupported format.")); |
| 156 return promise; | 202 return promise; |
| 157 } | 203 } |
| 158 | 204 |
| 159 return doDetect(resolver, std::move(sharedBufferHandle), img->naturalWidth(), | 205 return doDetect(resolver, std::move(sharedBufferHandle), img->naturalWidth(), |
| 160 img->naturalHeight()); | 206 img->naturalHeight()); |
| 161 } | 207 } |
| 162 | 208 |
| 163 ScriptPromise ShapeDetector::detectShapesOnImageBitmap( | |
| 164 ScriptPromiseResolver* resolver, | |
| 165 ImageBitmap* imageBitmap) { | |
| 166 ScriptPromise promise = resolver->promise(); | |
| 167 | |
| 168 if (imageBitmap->isNeutered()) { | |
| 169 resolver->reject( | |
| 170 DOMException::create(InvalidStateError, "Neutered ImageBitmap.")); | |
| 171 return promise; | |
| 172 } | |
| 173 | |
| 174 if (imageBitmap->size().area() == 0) { | |
| 175 resolver->resolve(HeapVector<Member<DOMRect>>()); | |
| 176 return promise; | |
| 177 } | |
| 178 | |
| 179 SkPixmap pixmap; | |
| 180 RefPtr<Uint8Array> pixelData; | |
| 181 uint8_t* pixelDataPtr = nullptr; | |
| 182 WTF::CheckedNumeric<int> allocationSize = 0; | |
| 183 // Use |skImage|'s pixels if it has direct access to them, otherwise retrieve | |
| 184 // them from elsewhere via copyBitmapData(). | |
| 185 sk_sp<SkImage> skImage = imageBitmap->bitmapImage()->imageForCurrentFrame(); | |
| 186 if (skImage->peekPixels(&pixmap)) { | |
| 187 pixelDataPtr = static_cast<uint8_t*>(pixmap.writable_addr()); | |
| 188 allocationSize = pixmap.getSafeSize(); | |
| 189 } else { | |
| 190 pixelData = imageBitmap->copyBitmapData(imageBitmap->isPremultiplied() | |
| 191 ? PremultiplyAlpha | |
| 192 : DontPremultiplyAlpha, | |
| 193 N32ColorType); | |
| 194 pixelDataPtr = pixelData->data(); | |
| 195 allocationSize = imageBitmap->size().area() * 4 /* bytes per pixel */; | |
| 196 } | |
| 197 | |
| 198 mojo::ScopedSharedBufferHandle sharedBufferHandle = getSharedBufferOnData( | |
| 199 resolver, pixelDataPtr, allocationSize.ValueOrDefault(0)); | |
| 200 if (!sharedBufferHandle->is_valid()) | |
| 201 return promise; | |
| 202 | |
| 203 return doDetect(resolver, std::move(sharedBufferHandle), imageBitmap->width(), | |
| 204 imageBitmap->height()); | |
| 205 } | |
| 206 | |
| 207 ScriptPromise ShapeDetector::detectShapesOnVideoElement( | |
| 208 ScriptPromiseResolver* resolver, | |
| 209 const HTMLVideoElement* video) { | |
| 210 ScriptPromise promise = resolver->promise(); | |
| 211 // TODO(mcasas): Check if |video| is actually playing a MediaStream by using | |
| 212 // HTMLMediaElement::isMediaStreamURL(video->currentSrc().getString()); if | |
| 213 // there is a local WebCam associated, there might be sophisticated ways to | |
| 214 // detect faces on it. Until then, treat as a normal <video> element. | |
| 215 | |
| 216 // !hasAvailableVideoFrame() is a bundle of invalid states. | |
| 217 if (!video->hasAvailableVideoFrame()) { | |
| 218 resolver->reject(DOMException::create( | |
| 219 InvalidStateError, "Invalid HTMLVideoElement or state.")); | |
| 220 return promise; | |
| 221 } | |
| 222 | |
| 223 const FloatSize videoSize(video->videoWidth(), video->videoHeight()); | |
| 224 SourceImageStatus sourceImageStatus = InvalidSourceImageStatus; | |
| 225 RefPtr<Image> image = | |
| 226 video->getSourceImageForCanvas(&sourceImageStatus, PreferNoAcceleration, | |
| 227 SnapshotReasonDrawImage, videoSize); | |
| 228 | |
| 229 DCHECK_EQ(NormalSourceImageStatus, sourceImageStatus); | |
| 230 | |
| 231 SkPixmap pixmap; | |
| 232 RefPtr<Uint8Array> pixelData; | |
| 233 uint8_t* pixelDataPtr = nullptr; | |
| 234 WTF::CheckedNumeric<int> allocationSize = 0; | |
| 235 // Use |skImage|'s pixels if it has direct access to them. | |
| 236 sk_sp<SkImage> skImage = image->imageForCurrentFrame(); | |
| 237 if (skImage->peekPixels(&pixmap)) { | |
| 238 pixelDataPtr = static_cast<uint8_t*>(pixmap.writable_addr()); | |
| 239 allocationSize = pixmap.getSafeSize(); | |
| 240 } else { | |
| 241 // TODO(mcasas): retrieve the pixels from elsewhere. | |
| 242 NOTREACHED(); | |
| 243 resolver->reject(DOMException::create( | |
| 244 InvalidStateError, "Failed to get pixels for current frame.")); | |
| 245 return promise; | |
| 246 } | |
| 247 | |
| 248 mojo::ScopedSharedBufferHandle sharedBufferHandle = getSharedBufferOnData( | |
| 249 resolver, pixelDataPtr, allocationSize.ValueOrDefault(0)); | |
| 250 if (!sharedBufferHandle->is_valid()) | |
| 251 return promise; | |
| 252 | |
| 253 return doDetect(resolver, std::move(sharedBufferHandle), image->width(), | |
| 254 image->height()); | |
| 255 } | |
| 256 | |
| 257 } // namespace blink | 209 } // namespace blink |
| OLD | NEW |