| 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..e03d47a7fdc50d8b156d54c14b47f6d5e49327cd 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();
 | 
|      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.contains(resolver))
 | 
| +        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);
 | 
|  }
 | 
| 
 |