Commit 4479d72b authored by jrummell@chromium.org's avatar jrummell@chromium.org

Simplify use of ContentDecryptionModuleResult with promises

Since ContentDecryptionModuleResult objects are often used to return
promises, add ContentDecryptionModuleResultPromise as a base class
that includes the promise and allow existing classes to only override
the complete() method that they expect to get called.

BUG=358271
TEST=existing EME tests pass

Review URL: https://codereview.chromium.org/687533004

git-svn-id: svn://svn.chromium.org/blink/trunk@185168 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 30f0845f
...@@ -3,14 +3,11 @@ ...@@ -3,14 +3,11 @@
// found in the LICENSE file. // found in the LICENSE file.
#include "config.h" #include "config.h"
#include "modules/encryptedmedia/SimpleContentDecryptionModuleResult.h" #include "modules/encryptedmedia/ContentDecryptionModuleResultPromise.h"
#include "bindings/core/v8/ScriptPromise.h" #include "bindings/core/v8/ScriptPromise.h"
#include "bindings/core/v8/ScriptPromiseResolver.h"
#include "bindings/core/v8/ScriptState.h" #include "bindings/core/v8/ScriptState.h"
#include "bindings/core/v8/V8Binding.h"
#include "core/dom/DOMException.h" #include "core/dom/DOMException.h"
#include "platform/Logging.h"
#include "public/platform/WebString.h" #include "public/platform/WebString.h"
#include "wtf/Assertions.h" #include "wtf/Assertions.h"
...@@ -41,41 +38,51 @@ ExceptionCode WebCdmExceptionToExceptionCode(WebContentDecryptionModuleException ...@@ -41,41 +38,51 @@ ExceptionCode WebCdmExceptionToExceptionCode(WebContentDecryptionModuleException
return UnknownError; return UnknownError;
} }
SimpleContentDecryptionModuleResult::SimpleContentDecryptionModuleResult(ScriptState* scriptState) ContentDecryptionModuleResultPromise::ContentDecryptionModuleResultPromise(ScriptState* scriptState)
: m_resolver(ScriptPromiseResolver::create(scriptState)) : m_resolver(ScriptPromiseResolver::create(scriptState))
{ {
} }
SimpleContentDecryptionModuleResult::~SimpleContentDecryptionModuleResult() ContentDecryptionModuleResultPromise::~ContentDecryptionModuleResultPromise()
{ {
} }
void SimpleContentDecryptionModuleResult::complete() void ContentDecryptionModuleResultPromise::complete()
{ {
m_resolver->resolve(V8UndefinedType()); ASSERT_NOT_REACHED();
m_resolver.clear(); reject(InvalidStateError, "Unexpected completion.");
} }
void SimpleContentDecryptionModuleResult::completeWithSession(WebContentDecryptionModuleResult::SessionStatus status) void ContentDecryptionModuleResultPromise::completeWithSession(WebContentDecryptionModuleResult::SessionStatus status)
{ {
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
completeWithDOMException(InvalidStateError, "Unexpected completion."); reject(InvalidStateError, "Unexpected completion.");
} }
void SimpleContentDecryptionModuleResult::completeWithError(WebContentDecryptionModuleException exceptionCode, unsigned long systemCode, const WebString& errorMessage) void ContentDecryptionModuleResultPromise::completeWithError(WebContentDecryptionModuleException exceptionCode, unsigned long systemCode, const WebString& errorMessage)
{ {
completeWithDOMException(WebCdmExceptionToExceptionCode(exceptionCode), errorMessage); reject(WebCdmExceptionToExceptionCode(exceptionCode), errorMessage);
} }
ScriptPromise SimpleContentDecryptionModuleResult::promise() ScriptPromise ContentDecryptionModuleResultPromise::promise()
{ {
return m_resolver->promise(); return m_resolver->promise();
} }
void SimpleContentDecryptionModuleResult::completeWithDOMException(ExceptionCode code, const String& errorMessage) void ContentDecryptionModuleResultPromise::reject(ExceptionCode code, const String& errorMessage)
{ {
m_resolver->reject(DOMException::create(code, errorMessage)); m_resolver->reject(DOMException::create(code, errorMessage));
m_resolver.clear(); m_resolver.clear();
} }
ExecutionContext* ContentDecryptionModuleResultPromise::executionContext() const
{
return m_resolver->executionContext();
}
void ContentDecryptionModuleResultPromise::trace(Visitor* visitor)
{
ContentDecryptionModuleResult::trace(visitor);
}
} // namespace blink } // namespace blink
...@@ -2,47 +2,57 @@ ...@@ -2,47 +2,57 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#ifndef SimpleContentDecryptionModuleResult_h #ifndef ContentDecryptionModuleResultPromise_h
#define SimpleContentDecryptionModuleResult_h #define ContentDecryptionModuleResultPromise_h
#include "bindings/core/v8/ScriptPromiseResolver.h"
#include "core/dom/ExceptionCode.h" #include "core/dom/ExceptionCode.h"
#include "platform/ContentDecryptionModuleResult.h" #include "platform/ContentDecryptionModuleResult.h"
#include "wtf/Forward.h"
namespace blink { namespace blink {
class ScriptPromise;
class ScriptPromiseResolver;
class ScriptState;
class WebString;
ExceptionCode WebCdmExceptionToExceptionCode(WebContentDecryptionModuleException); ExceptionCode WebCdmExceptionToExceptionCode(WebContentDecryptionModuleException);
// This class wraps the promise resolver and is passed (indirectly) to Chromium // This class wraps the promise resolver to simplify creation of
// to fullfill the promise. This implementation of complete() will resolve the // ContentDecryptionModuleResult objects. The default implementations of the
// promise with undefined, while completeWithError() reject the promise with an // complete(), completeWithSession(), etc. methods will reject the promise
// exception. completeWithSession() is not expected to be called, and will // with an error. It needs to be subclassed and the appropriate complete()
// reject the promise. // method overridden to resolve the promise as needed.
class SimpleContentDecryptionModuleResult : public ContentDecryptionModuleResult { class ContentDecryptionModuleResultPromise : public ContentDecryptionModuleResult {
public: public:
explicit SimpleContentDecryptionModuleResult(ScriptState*); virtual ~ContentDecryptionModuleResultPromise();
virtual ~SimpleContentDecryptionModuleResult();
// ContentDecryptionModuleResult implementation. // ContentDecryptionModuleResult implementation.
virtual void complete() override; virtual void complete() override;
virtual void completeWithSession(WebContentDecryptionModuleResult::SessionStatus) override; virtual void completeWithSession(WebContentDecryptionModuleResult::SessionStatus) override;
virtual void completeWithError(WebContentDecryptionModuleException, unsigned long systemCode, const WebString&) override; virtual void completeWithError(WebContentDecryptionModuleException, unsigned long systemCode, const WebString&) final;
// It is only valid to call this before completion. // It is only valid to call this before completion.
ScriptPromise promise(); ScriptPromise promise();
private: virtual void trace(Visitor*);
// Reject the promise with a DOMException.
void completeWithDOMException(ExceptionCode, const String& errorMessage); protected:
explicit ContentDecryptionModuleResultPromise(ScriptState*);
// Resolves the promise with |value|. Used by subclasses to resolve the
// promise.
template <typename... T>
void resolve(T... value)
{
m_resolver->resolve(value...);
m_resolver.clear();
}
// Rejects the promise with a DOMException.
void reject(ExceptionCode, const String& errorMessage);
ExecutionContext* executionContext() const;
private:
RefPtr<ScriptPromiseResolver> m_resolver; RefPtr<ScriptPromiseResolver> m_resolver;
}; };
} // namespace blink } // namespace blink
#endif // SimpleContentDecryptionModuleResult_h #endif // ContentDecryptionModuleResultPromise_h
...@@ -15,9 +15,9 @@ ...@@ -15,9 +15,9 @@
#include "core/html/HTMLMediaElement.h" #include "core/html/HTMLMediaElement.h"
#include "core/html/MediaKeyError.h" #include "core/html/MediaKeyError.h"
#include "core/html/MediaKeyEvent.h" #include "core/html/MediaKeyEvent.h"
#include "modules/encryptedmedia/ContentDecryptionModuleResultPromise.h"
#include "modules/encryptedmedia/MediaEncryptedEvent.h" #include "modules/encryptedmedia/MediaEncryptedEvent.h"
#include "modules/encryptedmedia/MediaKeys.h" #include "modules/encryptedmedia/MediaKeys.h"
#include "modules/encryptedmedia/SimpleContentDecryptionModuleResult.h"
#include "platform/ContentDecryptionModuleResult.h" #include "platform/ContentDecryptionModuleResult.h"
#include "platform/Logging.h" #include "platform/Logging.h"
#include "platform/RuntimeEnabledFeatures.h" #include "platform/RuntimeEnabledFeatures.h"
......
...@@ -36,9 +36,10 @@ ...@@ -36,9 +36,10 @@
#include "core/events/Event.h" #include "core/events/Event.h"
#include "core/events/GenericEventQueue.h" #include "core/events/GenericEventQueue.h"
#include "core/html/MediaKeyError.h" #include "core/html/MediaKeyError.h"
#include "modules/encryptedmedia/ContentDecryptionModuleResultPromise.h"
#include "modules/encryptedmedia/MediaKeyMessageEvent.h" #include "modules/encryptedmedia/MediaKeyMessageEvent.h"
#include "modules/encryptedmedia/MediaKeys.h" #include "modules/encryptedmedia/MediaKeys.h"
#include "modules/encryptedmedia/SimpleContentDecryptionModuleResult.h" #include "modules/encryptedmedia/SimpleContentDecryptionModuleResultPromise.h"
#include "platform/ContentDecryptionModuleResult.h" #include "platform/ContentDecryptionModuleResult.h"
#include "platform/ContentType.h" #include "platform/ContentType.h"
#include "platform/Logging.h" #include "platform/Logging.h"
...@@ -201,62 +202,37 @@ private: ...@@ -201,62 +202,37 @@ private:
// completeWithSession() will resolve the promise with void, while // completeWithSession() will resolve the promise with void, while
// completeWithError() will reject the promise with an exception. complete() // completeWithError() will reject the promise with an exception. complete()
// is not expected to be called, and will reject the promise. // is not expected to be called, and will reject the promise.
class NewSessionResult : public ContentDecryptionModuleResult { class NewSessionResultPromise : public ContentDecryptionModuleResultPromise {
public: public:
NewSessionResult(ScriptState* scriptState, MediaKeySession* session) NewSessionResultPromise(ScriptState* scriptState, MediaKeySession* session)
: m_resolver(ScriptPromiseResolver::create(scriptState)) : ContentDecryptionModuleResultPromise(scriptState)
, m_session(session) , m_session(session)
{ {
WTF_LOG(Media, "NewSessionResult(%p)", this);
} }
virtual ~NewSessionResult() virtual ~NewSessionResultPromise()
{ {
WTF_LOG(Media, "~NewSessionResult(%p)", this);
} }
// ContentDecryptionModuleResult implementation. // ContentDecryptionModuleResult implementation.
virtual void complete() override
{
ASSERT_NOT_REACHED();
completeWithDOMException(InvalidStateError, "Unexpected completion.");
}
virtual void completeWithSession(WebContentDecryptionModuleResult::SessionStatus status) override virtual void completeWithSession(WebContentDecryptionModuleResult::SessionStatus status) override
{ {
if (status != WebContentDecryptionModuleResult::NewSession) { if (status != WebContentDecryptionModuleResult::NewSession) {
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
completeWithDOMException(InvalidStateError, "Unexpected completion."); reject(InvalidStateError, "Unexpected completion.");
} }
m_session->finishGenerateRequest(); m_session->finishGenerateRequest();
m_resolver->resolve(); resolve();
m_resolver.clear();
}
virtual void completeWithError(WebContentDecryptionModuleException exceptionCode, unsigned long systemCode, const WebString& errorMessage) override
{
completeWithDOMException(WebCdmExceptionToExceptionCode(exceptionCode), errorMessage);
} }
// It is only valid to call this before completion.
ScriptPromise promise() { return m_resolver->promise(); }
void trace(Visitor* visitor) void trace(Visitor* visitor)
{ {
visitor->trace(m_session); visitor->trace(m_session);
ContentDecryptionModuleResult::trace(visitor); ContentDecryptionModuleResultPromise::trace(visitor);
} }
private: private:
// Reject the promise with a DOMException.
void completeWithDOMException(ExceptionCode code, const String& errorMessage)
{
m_resolver->reject(DOMException::create(code, errorMessage));
m_resolver.clear();
}
RefPtr<ScriptPromiseResolver> m_resolver;
Member<MediaKeySession> m_session; Member<MediaKeySession> m_session;
}; };
...@@ -265,27 +241,19 @@ private: ...@@ -265,27 +241,19 @@ private:
// completeWithSession() will resolve the promise with true/false, while // completeWithSession() will resolve the promise with true/false, while
// completeWithError() will reject the promise with an exception. complete() // completeWithError() will reject the promise with an exception. complete()
// is not expected to be called, and will reject the promise. // is not expected to be called, and will reject the promise.
class LoadSessionResult : public ContentDecryptionModuleResult { class LoadSessionResultPromise : public ContentDecryptionModuleResultPromise {
public: public:
LoadSessionResult(ScriptState* scriptState, MediaKeySession* session) LoadSessionResultPromise(ScriptState* scriptState, MediaKeySession* session)
: m_resolver(ScriptPromiseResolver::create(scriptState)) : ContentDecryptionModuleResultPromise(scriptState)
, m_session(session) , m_session(session)
{ {
WTF_LOG(Media, "LoadSessionResult(%p)", this);
} }
virtual ~LoadSessionResult() virtual ~LoadSessionResultPromise()
{ {
WTF_LOG(Media, "~LoadSessionResult(%p)", this);
} }
// ContentDecryptionModuleResult implementation. // ContentDecryptionModuleResult implementation.
virtual void complete() override
{
ASSERT_NOT_REACHED();
completeWithDOMException(InvalidStateError, "Unexpected completion.");
}
virtual void completeWithSession(WebContentDecryptionModuleResult::SessionStatus status) override virtual void completeWithSession(WebContentDecryptionModuleResult::SessionStatus status) override
{ {
bool result = false; bool result = false;
...@@ -300,38 +268,21 @@ public: ...@@ -300,38 +268,21 @@ public:
case WebContentDecryptionModuleResult::SessionAlreadyExists: case WebContentDecryptionModuleResult::SessionAlreadyExists:
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
completeWithDOMException(InvalidStateError, "Unexpected completion."); reject(InvalidStateError, "Unexpected completion.");
return; return;
} }
m_session->finishLoad(); m_session->finishLoad();
m_resolver->resolve(result); resolve(result);
m_resolver.clear();
}
virtual void completeWithError(WebContentDecryptionModuleException exceptionCode, unsigned long systemCode, const WebString& errorMessage) override
{
completeWithDOMException(WebCdmExceptionToExceptionCode(exceptionCode), errorMessage);
} }
// It is only valid to call this before completion.
ScriptPromise promise() { return m_resolver->promise(); }
void trace(Visitor* visitor) void trace(Visitor* visitor)
{ {
visitor->trace(m_session); visitor->trace(m_session);
ContentDecryptionModuleResult::trace(visitor); ContentDecryptionModuleResultPromise::trace(visitor);
} }
private: private:
// Reject the promise with a DOMException.
void completeWithDOMException(ExceptionCode code, const String& errorMessage)
{
m_resolver->reject(DOMException::create(code, errorMessage));
m_resolver.clear();
}
RefPtr<ScriptPromiseResolver> m_resolver;
Member<MediaKeySession> m_session; Member<MediaKeySession> m_session;
}; };
...@@ -480,7 +431,7 @@ ScriptPromise MediaKeySession::generateRequestInternal(ScriptState* scriptState, ...@@ -480,7 +431,7 @@ ScriptPromise MediaKeySession::generateRequestInternal(ScriptState* scriptState,
// (Done in constructor.) // (Done in constructor.)
// 9. Let promise be a new promise. // 9. Let promise be a new promise.
NewSessionResult* result = new NewSessionResult(scriptState, this); NewSessionResultPromise* result = new NewSessionResultPromise(scriptState, this);
ScriptPromise promise = result->promise(); ScriptPromise promise = result->promise();
// 10. Run the following steps asynchronously (documented in // 10. Run the following steps asynchronously (documented in
...@@ -536,7 +487,7 @@ ScriptPromise MediaKeySession::load(ScriptState* scriptState, const String& sess ...@@ -536,7 +487,7 @@ ScriptPromise MediaKeySession::load(ScriptState* scriptState, const String& sess
// (Done by CDM.) // (Done by CDM.)
// 7. Let promise be a new promise. // 7. Let promise be a new promise.
LoadSessionResult* result = new LoadSessionResult(scriptState, this); LoadSessionResultPromise* result = new LoadSessionResultPromise(scriptState, this);
ScriptPromise promise = result->promise(); ScriptPromise promise = result->promise();
// 8. Run the following steps asynchronously (documented in // 8. Run the following steps asynchronously (documented in
...@@ -582,7 +533,7 @@ ScriptPromise MediaKeySession::updateInternal(ScriptState* scriptState, PassRefP ...@@ -582,7 +533,7 @@ ScriptPromise MediaKeySession::updateInternal(ScriptState* scriptState, PassRefP
// (Copied in the caller.) // (Copied in the caller.)
// 3. Let promise be a new promise. // 3. Let promise be a new promise.
SimpleContentDecryptionModuleResult* result = new SimpleContentDecryptionModuleResult(scriptState); SimpleContentDecryptionModuleResultPromise* result = new SimpleContentDecryptionModuleResultPromise(scriptState);
ScriptPromise promise = result->promise(); ScriptPromise promise = result->promise();
// 4. Run the following steps asynchronously (documented in // 4. Run the following steps asynchronously (documented in
...@@ -619,7 +570,7 @@ ScriptPromise MediaKeySession::close(ScriptState* scriptState) ...@@ -619,7 +570,7 @@ ScriptPromise MediaKeySession::close(ScriptState* scriptState)
return ScriptPromise::cast(scriptState, ScriptValue()); return ScriptPromise::cast(scriptState, ScriptValue());
// 3. Let promise be a new promise. // 3. Let promise be a new promise.
SimpleContentDecryptionModuleResult* result = new SimpleContentDecryptionModuleResult(scriptState); SimpleContentDecryptionModuleResultPromise* result = new SimpleContentDecryptionModuleResultPromise(scriptState);
ScriptPromise promise = result->promise(); ScriptPromise promise = result->promise();
// 4. Run the following steps asynchronously (documented in // 4. Run the following steps asynchronously (documented in
...@@ -663,7 +614,7 @@ ScriptPromise MediaKeySession::remove(ScriptState* scriptState) ...@@ -663,7 +614,7 @@ ScriptPromise MediaKeySession::remove(ScriptState* scriptState)
} }
// 4. Let promise be a new promise. // 4. Let promise be a new promise.
SimpleContentDecryptionModuleResult* result = new SimpleContentDecryptionModuleResult(scriptState); SimpleContentDecryptionModuleResultPromise* result = new SimpleContentDecryptionModuleResultPromise(scriptState);
ScriptPromise promise = result->promise(); ScriptPromise promise = result->promise();
// 5. Run the following steps asynchronously (documented in // 5. Run the following steps asynchronously (documented in
......
...@@ -98,8 +98,8 @@ public: ...@@ -98,8 +98,8 @@ public:
private: private:
class PendingAction; class PendingAction;
friend class NewSessionResult; friend class NewSessionResultPromise;
friend class LoadSessionResult; friend class LoadSessionResultPromise;
MediaKeySession(ScriptState*, MediaKeys*, const String& sessionType); MediaKeySession(ScriptState*, MediaKeys*, const String& sessionType);
......
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
#include "core/dom/ExceptionCode.h" #include "core/dom/ExceptionCode.h"
#include "core/dom/ExecutionContext.h" #include "core/dom/ExecutionContext.h"
#include "modules/encryptedmedia/MediaKeySession.h" #include "modules/encryptedmedia/MediaKeySession.h"
#include "modules/encryptedmedia/SimpleContentDecryptionModuleResult.h" #include "modules/encryptedmedia/SimpleContentDecryptionModuleResultPromise.h"
#include "platform/ContentType.h" #include "platform/ContentType.h"
#include "platform/Logging.h" #include "platform/Logging.h"
#include "platform/MIMETypeRegistry.h" #include "platform/MIMETypeRegistry.h"
...@@ -165,7 +165,7 @@ ScriptPromise MediaKeys::setServerCertificateInternal(ScriptState* scriptState, ...@@ -165,7 +165,7 @@ ScriptPromise MediaKeys::setServerCertificateInternal(ScriptState* scriptState,
// (Done in caller.) // (Done in caller.)
// 4. Let promise be a new promise. // 4. Let promise be a new promise.
SimpleContentDecryptionModuleResult* result = new SimpleContentDecryptionModuleResult(scriptState); SimpleContentDecryptionModuleResultPromise* result = new SimpleContentDecryptionModuleResultPromise(scriptState);
ScriptPromise promise = result->promise(); ScriptPromise promise = result->promise();
// 5. Run the following steps asynchronously (documented in timerFired()). // 5. Run the following steps asynchronously (documented in timerFired()).
......
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "config.h"
#include "modules/encryptedmedia/SimpleContentDecryptionModuleResultPromise.h"
namespace blink {
SimpleContentDecryptionModuleResultPromise::SimpleContentDecryptionModuleResultPromise(ScriptState* scriptState)
: ContentDecryptionModuleResultPromise(scriptState)
{
}
SimpleContentDecryptionModuleResultPromise::~SimpleContentDecryptionModuleResultPromise()
{
}
void SimpleContentDecryptionModuleResultPromise::complete()
{
resolve();
}
} // namespace blink
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SimpleContentDecryptionModuleResultPromise_h
#define SimpleContentDecryptionModuleResultPromise_h
#include "modules/encryptedmedia/ContentDecryptionModuleResultPromise.h"
namespace blink {
// This class creates a simple ContentDecryptionModuleResultPromise where the
// implementation of complete() will resolve the promise with void. All other
// complete() methods are not expected to be called (and will reject the
// promise).
class SimpleContentDecryptionModuleResultPromise : public ContentDecryptionModuleResultPromise {
public:
explicit SimpleContentDecryptionModuleResultPromise(ScriptState*);
virtual ~SimpleContentDecryptionModuleResultPromise();
// ContentDecryptionModuleResultPromise implementation.
virtual void complete() override;
};
} // namespace blink
#endif // SimpleContentDecryptionModuleResultPromise_h
...@@ -415,6 +415,8 @@ ...@@ -415,6 +415,8 @@
'encoding/TextDecoder.h', 'encoding/TextDecoder.h',
'encoding/TextEncoder.cpp', 'encoding/TextEncoder.cpp',
'encoding/TextEncoder.h', 'encoding/TextEncoder.h',
'encryptedmedia/ContentDecryptionModuleResultPromise.cpp',
'encryptedmedia/ContentDecryptionModuleResultPromise.h',
'encryptedmedia/HTMLMediaElementEncryptedMedia.cpp', 'encryptedmedia/HTMLMediaElementEncryptedMedia.cpp',
'encryptedmedia/HTMLMediaElementEncryptedMedia.h', 'encryptedmedia/HTMLMediaElementEncryptedMedia.h',
'encryptedmedia/MediaEncryptedEvent.cpp', 'encryptedmedia/MediaEncryptedEvent.cpp',
...@@ -432,8 +434,8 @@ ...@@ -432,8 +434,8 @@
'encryptedmedia/MediaKeysController.h', 'encryptedmedia/MediaKeysController.h',
'encryptedmedia/NavigatorRequestMediaKeySystemAccess.cpp', 'encryptedmedia/NavigatorRequestMediaKeySystemAccess.cpp',
'encryptedmedia/NavigatorRequestMediaKeySystemAccess.h', 'encryptedmedia/NavigatorRequestMediaKeySystemAccess.h',
'encryptedmedia/SimpleContentDecryptionModuleResult.cpp', 'encryptedmedia/SimpleContentDecryptionModuleResultPromise.cpp',
'encryptedmedia/SimpleContentDecryptionModuleResult.h', 'encryptedmedia/SimpleContentDecryptionModuleResultPromise.h',
'filesystem/DOMFilePath.cpp', 'filesystem/DOMFilePath.cpp',
'filesystem/DOMFilePath.h', 'filesystem/DOMFilePath.h',
'filesystem/DOMFileSystem.cpp', 'filesystem/DOMFileSystem.cpp',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment