Chromium Code Reviews| Index: third_party/WebKit/Source/modules/imagecapture/ImageCapture.cpp |
| diff --git a/third_party/WebKit/Source/modules/imagecapture/ImageCapture.cpp b/third_party/WebKit/Source/modules/imagecapture/ImageCapture.cpp |
| index 4d55d83591e040e7535a3136cc91632e70e77d1a..cddf632ce75c0b11d99de9f224596b0e7a1b9696 100644 |
| --- a/third_party/WebKit/Source/modules/imagecapture/ImageCapture.cpp |
| +++ b/third_party/WebKit/Source/modules/imagecapture/ImageCapture.cpp |
| @@ -8,15 +8,31 @@ |
| #include "bindings/core/v8/ScriptPromiseResolver.h" |
| #include "core/dom/DOMException.h" |
| #include "core/dom/ExceptionCode.h" |
| +#include "core/fileapi/Blob.h" |
| #include "core/frame/ImageBitmap.h" |
| #include "modules/EventTargetModules.h" |
| #include "modules/mediastream/MediaStreamTrack.h" |
| +#include "platform/mojo/MojoHelper.h" |
| #include "public/platform/Platform.h" |
| +#include "public/platform/ServiceRegistry.h" |
| #include "public/platform/WebImageCaptureFrameGrabber.h" |
| #include "public/platform/WebMediaStreamTrack.h" |
| namespace blink { |
| +namespace { |
| + |
| +const char kNoServiceError[] = "ImageCapture service unavailable."; |
| + |
| +bool trackIsInactive(const MediaStreamTrack& track) |
| +{ |
| + // Spec instructs to return an exception if the Track's readyState() is not |
| + // "live". Also reject if the track is disabled or muted. |
| + return track.readyState() != "live" || !track.enabled() || track.muted(); |
| +} |
| + |
| +} // anonymous namespace |
| + |
| ImageCapture* ImageCapture::create(ExecutionContext* context, MediaStreamTrack* track, ExceptionState& exceptionState) |
| { |
| if (track->kind() != "video") { |
| @@ -30,6 +46,9 @@ ImageCapture* ImageCapture::create(ExecutionContext* context, MediaStreamTrack* |
| ImageCapture::~ImageCapture() |
| { |
| DCHECK(!hasEventListeners()); |
| + // There should be no more outstanding |m_serviceRequests| at this point |
| + // since each of them holds a persistent handle to this object. |
| + DCHECK(m_serviceRequests.isEmpty()); |
| } |
| const AtomicString& ImageCapture::interfaceName() const |
| @@ -50,26 +69,49 @@ bool ImageCapture::hasPendingActivity() const |
| void ImageCapture::contextDestroyed() |
| { |
| removeAllEventListeners(); |
| + m_serviceRequests.clear(); |
|
haraken
2016/04/29 06:50:20
I'm just curious but don't you need to reject the
mcasas
2016/04/29 21:03:14
I'm checking other callers like
USB::contextDestro
|
| DCHECK(!hasEventListeners()); |
| } |
| +ScriptPromise ImageCapture::takePhoto(ScriptState* scriptState, ExceptionState& exceptionState) |
| +{ |
| + |
| + ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); |
| + ScriptPromise promise = resolver->promise(); |
| + |
| + if (trackIsInactive(*m_streamTrack)) { |
| + resolver->reject(DOMException::create(InvalidStateError, "The associated Track is in an invalid state.")); |
| + return promise; |
| + } |
| + |
| + if (!m_service) { |
| + resolver->reject(DOMException::create(NotFoundError, kNoServiceError)); |
| + return promise; |
| + } |
| + |
| + m_serviceRequests.add(resolver); |
| + |
| + // m_streamTrack->component()->source()->id() is the renderer "name" of the camera; |
| + // TODO(mcasas) consider sending the security origin as well: |
| + // scriptState->getExecutionContext()->getSecurityOrigin()->toString() |
| + m_service->TakePhoto(m_streamTrack->component()->source()->id(), createBaseCallback(bind<String, String>(&ImageCapture::onTakePhoto, this, resolver))); |
| + return promise; |
| +} |
| + |
| ScriptPromise ImageCapture::grabFrame(ScriptState* scriptState, ExceptionState& exceptionState) |
| { |
| ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); |
| ScriptPromise promise = resolver->promise(); |
| - // Spec instructs to return an exception if the track's ready state is not "live". Also reject if the track is disabled or muted. |
| - if (m_streamTrack->readyState() != "live" || !m_streamTrack->enabled() || m_streamTrack->muted()) { |
| + if (trackIsInactive(*m_streamTrack)) { |
| resolver->reject(DOMException::create(InvalidStateError, "The associated Track is in an invalid state.")); |
| return promise; |
| } |
| // Create |m_frameGrabber| the first time. |
| - if (!m_frameGrabber) { |
| + if (!m_frameGrabber) |
| m_frameGrabber = adoptPtr(Platform::current()->createImageCaptureFrameGrabber()); |
| - } |
| - |
| if (!m_frameGrabber) { |
| resolver->reject(DOMException::create(UnknownError, "Couldn't create platform resources")); |
| return promise; |
| @@ -88,6 +130,30 @@ ImageCapture::ImageCapture(ExecutionContext* context, MediaStreamTrack* track) |
| , m_streamTrack(track) |
| { |
| DCHECK(m_streamTrack); |
| + DCHECK(!m_service.is_bound()); |
| + |
| + Platform::current()->serviceRegistry()->connectToRemoteService(mojo::GetProxy(&m_service)); |
| + |
| + m_service.set_connection_error_handler(createBaseCallback(bind(&ImageCapture::onServiceConnectionError, WeakPersistentThisPointer<ImageCapture>(this)))); |
| +} |
| + |
| +void ImageCapture::onTakePhoto(ScriptPromiseResolver* resolver, const String& mimeType, const String& data) |
| +{ |
| + if (m_serviceRequests.isEmpty()) |
|
haraken
2016/04/29 06:50:20
Nit: A better check might be if(!m_serviceRequests
mcasas
2016/04/29 21:03:14
Done.
|
| + return; |
| + |
| + WTF::CString string = data.utf8(); |
| + DCHECK(!string.isNull()); |
| + resolver->resolve(Blob::create(reinterpret_cast<unsigned char*>(string.mutableData()), string.length(), mimeType)); |
| + m_serviceRequests.remove(resolver); |
| +} |
| + |
| +void ImageCapture::onServiceConnectionError() |
| +{ |
| + m_service.reset(); |
| + for (ScriptPromiseResolver* resolver : m_serviceRequests) |
| + resolver->reject(DOMException::create(NotFoundError, kNoServiceError)); |
| + m_serviceRequests.clear(); |
| } |
| bool ImageCapture::addEventListenerInternal(const AtomicString& eventType, EventListener* listener, const EventListenerOptions& options) |
| @@ -98,6 +164,7 @@ bool ImageCapture::addEventListenerInternal(const AtomicString& eventType, Event |
| DEFINE_TRACE(ImageCapture) |
| { |
| visitor->trace(m_streamTrack); |
| + visitor->trace(m_serviceRequests); |
| EventTargetWithInlineData::trace(visitor); |
| ContextLifecycleObserver::trace(visitor); |
| } |