From 1fa998d8919375312d20d6d54bae955d166031c7 Mon Sep 17 00:00:00 2001 From: trav90 Date: Fri, 8 Feb 2019 10:35:58 -0600 Subject: [EME] Make WidevineAdapter compatible with CDM version 9 NOTE: this breaks compatibility with CDM version 8. --- dom/media/gmp/widevine-adapter/WidevineAdapter.cpp | 4 +- .../gmp/widevine-adapter/WidevineDecryptor.cpp | 63 +++++++++++----------- dom/media/gmp/widevine-adapter/WidevineDecryptor.h | 24 ++++----- dom/media/gmp/widevine-adapter/WidevineUtils.cpp | 2 +- dom/media/gmp/widevine-adapter/WidevineUtils.h | 6 +-- .../gmp/widevine-adapter/WidevineVideoDecoder.h | 2 +- 6 files changed, 51 insertions(+), 50 deletions(-) (limited to 'dom') diff --git a/dom/media/gmp/widevine-adapter/WidevineAdapter.cpp b/dom/media/gmp/widevine-adapter/WidevineAdapter.cpp index 74b5c38e8..fa703ab0b 100644 --- a/dom/media/gmp/widevine-adapter/WidevineAdapter.cpp +++ b/dom/media/gmp/widevine-adapter/WidevineAdapter.cpp @@ -46,7 +46,7 @@ void* GetCdmHost(int aHostInterfaceVersion, void* aUserData) Log("GetCdmHostFunc(%d, %p)", aHostInterfaceVersion, aUserData); WidevineDecryptor* decryptor = reinterpret_cast(aUserData); MOZ_ASSERT(decryptor); - return static_cast(decryptor); + return static_cast(decryptor); } #define STRINGIFY(s) _STRINGIFY(s) @@ -162,7 +162,7 @@ WidevineAdapter::Supports(int32_t aModuleVersion, { return aModuleVersion == CDM_MODULE_VERSION && aInterfaceVersion == cdm::ContentDecryptionModule::kVersion && - aHostVersion == cdm::Host_8::kVersion; + aHostVersion == cdm::Host_9::kVersion; } } // namespace mozilla diff --git a/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp b/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp index 149fa1701..e85aa2db3 100644 --- a/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp +++ b/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp @@ -301,6 +301,12 @@ WidevineDecryptor::GetCurrentWallTime() return base::Time::Now().ToDoubleT(); } +void +ChromiumCDMChild::OnResolveKeyStatusPromise(uint32_t aPromiseId, + cdm::KeyStatus aKeyStatus) { + //TODO: The callback of GetStatusForPolicy. See Mozilla bug 1404230. +} + void WidevineDecryptor::OnResolveNewSessionPromise(uint32_t aPromiseId, const char* aSessionId, @@ -332,42 +338,41 @@ WidevineDecryptor::OnResolvePromise(uint32_t aPromiseId) mCallback->ResolvePromise(aPromiseId); } -static GMPDOMException -ToGMPDOMException(cdm::Error aError) -{ - switch (aError) { - case kNotSupportedError: return kGMPNotSupportedError; - case kInvalidStateError: return kGMPInvalidStateError; - case kInvalidAccessError: - // Note: Chrome converts kInvalidAccessError to TypeError, since the - // Chromium CDM API doesn't have a type error enum value. The EME spec - // requires TypeError in some places, so we do the same conversion. - // See bug 1313202. - return kGMPTypeError; - case kQuotaExceededError: return kGMPQuotaExceededError; - case kUnknownError: return kGMPInvalidModificationError; // Note: Unique placeholder. - case kClientError: return kGMPAbortError; // Note: Unique placeholder. - case kOutputError: return kGMPSecurityError; // Note: Unique placeholder. - }; - return kGMPTimeoutError; // Note: Unique placeholder. +// Align with spec, the Exceptions used by CDM to reject promises . +// https://w3c.github.io/encrypted-media/#exceptions +cdm::Exception +ConvertCDMErrorToCDMException(cdm::Error error) { + switch (error) { + case cdm::kNotSupportedError: + return cdm::Exception::kExceptionNotSupportedError; + case cdm::kInvalidStateError: + return cdm::Exception::kExceptionInvalidStateError; + case cdm::kInvalidAccessError: + return cdm::Exception::kExceptionTypeError; + case cdm::kQuotaExceededError: + return cdm::Exception::kExceptionQuotaExceededError; + break; + } + + return cdm::Exception::kExceptionInvalidStateError; } void WidevineDecryptor::OnRejectPromise(uint32_t aPromiseId, - Error aError, - uint32_t aSystemCode, - const char* aErrorMessage, - uint32_t aErrorMessageSize) + cdm::Exception aException, + uint32_t aSystemCode, + const char* aErrorMessage, + uint32_t aErrorMessageSize) { if (!mCallback) { Log("Decryptor::OnRejectPromise(aPromiseId=%d, err=%d, sysCode=%u, msg=%s) FAIL; !mCallback", - aPromiseId, (int)aError, aSystemCode, aErrorMessage); + aPromiseId, (int)aException, aSystemCode, aErrorMessage); return; } Log("Decryptor::OnRejectPromise(aPromiseId=%d, err=%d, sysCode=%u, msg=%s)", aPromiseId, (int)aError, aSystemCode, aErrorMessage); mCallback->RejectPromise(aPromiseId, - ToGMPDOMException(aError), + ToGMPDOMException(aException), !aErrorMessageSize ? "" : aErrorMessage, aErrorMessageSize); } @@ -385,12 +390,10 @@ ToGMPMessageType(MessageType message_type) void WidevineDecryptor::OnSessionMessage(const char* aSessionId, - uint32_t aSessionIdSize, - MessageType aMessageType, - const char* aMessage, - uint32_t aMessageSize, - const char* aLegacyDestinationUrl, - uint32_t aLegacyDestinationUrlLength) + uint32_t aSessionIdSize, + cdm::MessageType aMessageType, + const char* aMessage, + uint32_t aMessageSize) { if (!mCallback) { Log("Decryptor::OnSessionMessage() FAIL; !mCallback"); diff --git a/dom/media/gmp/widevine-adapter/WidevineDecryptor.h b/dom/media/gmp/widevine-adapter/WidevineDecryptor.h index d5185192b..c1a1ebaa1 100644 --- a/dom/media/gmp/widevine-adapter/WidevineDecryptor.h +++ b/dom/media/gmp/widevine-adapter/WidevineDecryptor.h @@ -16,7 +16,7 @@ namespace mozilla { class WidevineDecryptor : public GMPDecryptor - , public cdm::Host_8 + , public cdm::Host_9 { public: @@ -69,16 +69,19 @@ public: void DecryptingComplete() override; - // cdm::Host_8 + // cdm::Host_9 implementation cdm::Buffer* Allocate(uint32_t aCapacity) override; void SetTimer(int64_t aDelayMs, void* aContext) override; cdm::Time GetCurrentWallTime() override; + // cdm::Host_9 interface + void OnResolveKeyStatusPromise(uint32_t aPromiseId, + cdm::KeyStatus aKeyStatus) override; void OnResolveNewSessionPromise(uint32_t aPromiseId, const char* aSessionId, uint32_t aSessionIdSize) override; void OnResolvePromise(uint32_t aPromiseId) override; void OnRejectPromise(uint32_t aPromiseId, - cdm::Error aError, + cdm::Exception aException, uint32_t aSystemCode, const char* aErrorMessage, uint32_t aErrorMessageSize) override; @@ -86,9 +89,7 @@ public: uint32_t aSessionIdSize, cdm::MessageType aMessageType, const char* aMessage, - uint32_t aMessageSize, - const char* aLegacyDestinationUrl, - uint32_t aLegacyDestinationUrlLength) override; + uint32_t aMessageSize) override; void OnSessionKeysChange(const char* aSessionId, uint32_t aSessionIdSize, bool aHasAdditionalUsableKey, @@ -99,12 +100,6 @@ public: cdm::Time aNewExpiryTime) override; void OnSessionClosed(const char* aSessionId, uint32_t aSessionIdSize) override; - void OnLegacySessionError(const char* aSessionId, - uint32_t aSessionId_length, - cdm::Error aError, - uint32_t aSystemCode, - const char* aErrorMessage, - uint32_t aErrorMessageLength) override; void SendPlatformChallenge(const char* aServiceId, uint32_t aServiceIdSize, const char* aChallenge, @@ -113,6 +108,9 @@ public: void QueryOutputProtectionStatus() override; void OnDeferredInitializationDone(cdm::StreamType aStreamType, cdm::Status aDecoderStatus) override; + // cdm::Host_9 interface + // NOTE: the interface has changed upstream. + void RequestStorageId() override {} cdm::FileIO* CreateFileIO(cdm::FileIOClient* aClient) override; GMPDecryptorCallback* Callback() const { return mCallback; } @@ -120,7 +118,7 @@ public: private: ~WidevineDecryptor(); RefPtr mCDM; - cdm::ContentDecryptionModule_8* CDM() { return mCDM->GetCDM(); } + cdm::ContentDecryptionModule_9* CDM() { return mCDM->GetCDM(); } GMPDecryptorCallback* mCallback; std::map mPromiseIdToNewSessionTokens; diff --git a/dom/media/gmp/widevine-adapter/WidevineUtils.cpp b/dom/media/gmp/widevine-adapter/WidevineUtils.cpp index 925dfe1a1..deb71e51a 100644 --- a/dom/media/gmp/widevine-adapter/WidevineUtils.cpp +++ b/dom/media/gmp/widevine-adapter/WidevineUtils.cpp @@ -77,7 +77,7 @@ void InitInputBuffer(const GMPEncryptedBufferMetadata* aCrypto, aInputBuffer.timestamp = aTimestamp; } -CDMWrapper::CDMWrapper(cdm::ContentDecryptionModule_8* aCDM, +CDMWrapper::CDMWrapper(cdm::ContentDecryptionModule_9* aCDM, WidevineDecryptor* aDecryptor) : mCDM(aCDM) , mDecryptor(aDecryptor) diff --git a/dom/media/gmp/widevine-adapter/WidevineUtils.h b/dom/media/gmp/widevine-adapter/WidevineUtils.h index 57c004a87..ca65ff881 100644 --- a/dom/media/gmp/widevine-adapter/WidevineUtils.h +++ b/dom/media/gmp/widevine-adapter/WidevineUtils.h @@ -48,12 +48,12 @@ class CDMWrapper { public: NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CDMWrapper) - explicit CDMWrapper(cdm::ContentDecryptionModule_8* aCDM, + explicit CDMWrapper(cdm::ContentDecryptionModule_9* aCDM, WidevineDecryptor* aDecryptor); - cdm::ContentDecryptionModule_8* GetCDM() const { return mCDM; } + cdm::ContentDecryptionModule_9* GetCDM() const { return mCDM; } private: ~CDMWrapper(); - cdm::ContentDecryptionModule_8* mCDM; + cdm::ContentDecryptionModule_9* mCDM; RefPtr mDecryptor; }; diff --git a/dom/media/gmp/widevine-adapter/WidevineVideoDecoder.h b/dom/media/gmp/widevine-adapter/WidevineVideoDecoder.h index b143f75f7..f5e63519b 100644 --- a/dom/media/gmp/widevine-adapter/WidevineVideoDecoder.h +++ b/dom/media/gmp/widevine-adapter/WidevineVideoDecoder.h @@ -45,7 +45,7 @@ private: ~WidevineVideoDecoder(); - cdm::ContentDecryptionModule_8* CDM() const { + cdm::ContentDecryptionModule_9* CDM() const { // CDM should only be accessed before 'DecodingComplete'. MOZ_ASSERT(mCDMWrapper); // CDMWrapper ensure the CDM is non-null, no need to check again. -- cgit v1.2.3 From 6310310e0ae2acb88b2f83c7fb5abb806fa64dcb Mon Sep 17 00:00:00 2001 From: trav90 Date: Fri, 8 Feb 2019 10:41:49 -0600 Subject: [EME} Hackily implement cdm::Host_9::RequestStorageId TODO: Implement this properly in the future. --- dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp | 13 +++++++++++++ dom/media/gmp/widevine-adapter/WidevineDecryptor.h | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) (limited to 'dom') diff --git a/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp b/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp index e85aa2db3..e3560d33f 100644 --- a/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp +++ b/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp @@ -541,4 +541,17 @@ WidevineDecryptor::CreateFileIO(FileIOClient* aClient) return new WidevineFileIO(aClient); } +void +WidevineDecryptor::RequestStorageId(uint32_t aVersion) +{ + Log("ChromiumCDMChild::RequestStorageId() aVersion = %u", aVersion); + if (aVersion >= 0x80000000) { + mCDM->OnStorageId(aVersion, nullptr, 0); + return; + } + + //TODO: Need to provide a menaingful buffer instead of a dummy one. + mCDM->OnStorageId(aVersion, new uint8_t[1024*1024], 1024 * 1024); +} + } // namespace mozilla diff --git a/dom/media/gmp/widevine-adapter/WidevineDecryptor.h b/dom/media/gmp/widevine-adapter/WidevineDecryptor.h index c1a1ebaa1..f291c321d 100644 --- a/dom/media/gmp/widevine-adapter/WidevineDecryptor.h +++ b/dom/media/gmp/widevine-adapter/WidevineDecryptor.h @@ -110,7 +110,7 @@ public: cdm::Status aDecoderStatus) override; // cdm::Host_9 interface // NOTE: the interface has changed upstream. - void RequestStorageId() override {} + void RequestStorageId(uint32_t aVersion) override; cdm::FileIO* CreateFileIO(cdm::FileIOClient* aClient) override; GMPDecryptorCallback* Callback() const { return mCallback; } -- cgit v1.2.3 From 34bfc1f409b4cafa65dbc4f3087c349eb1a1dec4 Mon Sep 17 00:00:00 2001 From: trav90 Date: Fri, 8 Feb 2019 12:31:48 -0600 Subject: [EME] Update content_decryption_module.h to more recent revision Adds support for cdm::ContentDecryptionModule_9 and cdm::Host_9 definitions, HDCP definitions, and 10 and 12 bit image format definitions. --- dom/media/gmp/widevine-adapter/WidevineAdapter.cpp | 6 +- dom/media/gmp/widevine-adapter/WidevineUtils.cpp | 2 +- .../widevine-adapter/content_decryption_module.h | 266 +++++++++++++-------- .../content_decryption_module_export.h | 22 ++ 4 files changed, 193 insertions(+), 103 deletions(-) create mode 100644 dom/media/gmp/widevine-adapter/content_decryption_module_export.h (limited to 'dom') diff --git a/dom/media/gmp/widevine-adapter/WidevineAdapter.cpp b/dom/media/gmp/widevine-adapter/WidevineAdapter.cpp index fa703ab0b..57d4ecec2 100644 --- a/dom/media/gmp/widevine-adapter/WidevineAdapter.cpp +++ b/dom/media/gmp/widevine-adapter/WidevineAdapter.cpp @@ -106,8 +106,8 @@ WidevineAdapter::GMPGetAPI(const char* aAPIName, WidevineDecryptor* decryptor = new WidevineDecryptor(); - auto cdm = reinterpret_cast( - create(cdm::ContentDecryptionModule::kVersion, + auto cdm = reinterpret_cast( + create(cdm::ContentDecryptionModule_9::kVersion, kEMEKeySystemWidevine.get(), kEMEKeySystemWidevine.Length(), &GetCdmHost, @@ -161,7 +161,7 @@ WidevineAdapter::Supports(int32_t aModuleVersion, int32_t aHostVersion) { return aModuleVersion == CDM_MODULE_VERSION && - aInterfaceVersion == cdm::ContentDecryptionModule::kVersion && + aInterfaceVersion == cdm::ContentDecryptionModule_9::kVersion && aHostVersion == cdm::Host_9::kVersion; } diff --git a/dom/media/gmp/widevine-adapter/WidevineUtils.cpp b/dom/media/gmp/widevine-adapter/WidevineUtils.cpp index deb71e51a..10c6c2e18 100644 --- a/dom/media/gmp/widevine-adapter/WidevineUtils.cpp +++ b/dom/media/gmp/widevine-adapter/WidevineUtils.cpp @@ -43,7 +43,7 @@ ToGMPErr(cdm::Status aStatus) case cdm::kSuccess: return GMPNoErr; case cdm::kNeedMoreData: return GMPGenericErr; case cdm::kNoKey: return GMPNoKeyErr; - case cdm::kSessionError: return GMPGenericErr; + case cdm::kInitializationError: return GMPGenericErr; case cdm::kDecryptError: return GMPCryptoErr; case cdm::kDecodeError: return GMPDecodeErr; case cdm::kDeferredInitialization: return GMPGenericErr; diff --git a/dom/media/gmp/widevine-adapter/content_decryption_module.h b/dom/media/gmp/widevine-adapter/content_decryption_module.h index 512ca9768..3f065017b 100644 --- a/dom/media/gmp/widevine-adapter/content_decryption_module.h +++ b/dom/media/gmp/widevine-adapter/content_decryption_module.h @@ -5,6 +5,8 @@ #ifndef CDM_CONTENT_DECRYPTION_MODULE_H_ #define CDM_CONTENT_DECRYPTION_MODULE_H_ +#include "content_decryption_module_export.h" + #if defined(_MSC_VER) typedef unsigned char uint8_t; typedef unsigned int uint32_t; @@ -14,25 +16,21 @@ typedef __int64 int64_t; #include #endif -// Define CDM_EXPORT so that functionality implemented by the CDM module -// can be exported to consumers. -#if defined(WIN32) - -#if defined(CDM_IMPLEMENTATION) -#define CDM_EXPORT __declspec(dllexport) -#else -#define CDM_EXPORT __declspec(dllimport) -#endif // defined(CDM_IMPLEMENTATION) - -#else // defined(WIN32) - -#if defined(CDM_IMPLEMENTATION) -#define CDM_EXPORT __attribute__((visibility("default"))) +// Define CDM_CLASS_API to export class types. We have to add visibility +// attributes to make sure virtual tables in CDM consumer and CDM implementation +// are the same. Generally, it was always a good idea, as there're no guarantees +// about that for the internal symbols, but it has only become a practical issue +// after introduction of LTO devirtualization. See more details on +// https://crbug.com/609564#c35 +#if defined(_WIN32) +#if defined(__clang__) +#define CDM_CLASS_API [[clang::lto_visibility_public]] #else -#define CDM_EXPORT +#define CDM_CLASS_API #endif - -#endif // defined(WIN32) +#else // defined(_WIN32) +#define CDM_CLASS_API __attribute__((visibility("default"))) +#endif // defined(_WIN32) // The version number must be rolled when the exported functions are updated! // If the CDM and the adapter use different versions of these functions, the @@ -48,9 +46,9 @@ typedef __int64 int64_t; #define BUILD_ENTRYPOINT_NO_EXPANSION(name, version) name##_##version extern "C" { -CDM_EXPORT void INITIALIZE_CDM_MODULE(); +CDM_API void INITIALIZE_CDM_MODULE(); -CDM_EXPORT void DeinitializeCdmModule(); +CDM_API void DeinitializeCdmModule(); // Returns a pointer to the requested CDM Host interface upon success. // Returns NULL if the requested CDM Host interface is not supported. @@ -65,30 +63,30 @@ typedef void* (*GetCdmHostFunc)(int host_interface_version, void* user_data); // |cdm_interface_version|. // Caller retains ownership of arguments and must call Destroy() on the returned // object. -CDM_EXPORT void* CreateCdmInstance( +CDM_API void* CreateCdmInstance( int cdm_interface_version, const char* key_system, uint32_t key_system_size, GetCdmHostFunc get_cdm_host_func, void* user_data); -CDM_EXPORT const char* GetCdmVersion(); +CDM_API const char* GetCdmVersion(); } namespace cdm { -class AudioFrames; -class DecryptedBlock; -class VideoFrame; +class CDM_CLASS_API AudioFrames; +class CDM_CLASS_API DecryptedBlock; +class CDM_CLASS_API VideoFrame; -class Host_7; -class Host_8; +class CDM_CLASS_API Host_8; +class CDM_CLASS_API Host_9; enum Status { kSuccess = 0, kNeedMoreData, // Decoder needs more data to produce a decoded frame/sample. - kNoKey, // The required decryption key is not available. - kSessionError, // Session management error. - kDecryptError, // Decryption failed. - kDecodeError, // Error decoding audio or video. + kNoKey, // The required decryption key is not available. + kInitializationError, // Initialization error. + kDecryptError, // Decryption failed. + kDecodeError, // Error decoding audio or video. kDeferredInitialization // Decoder is not ready for initialization. }; @@ -97,6 +95,7 @@ enum Status { // The following starts with the list of DOM4 exceptions from: // http://www.w3.org/TR/dom/#domexception // Some DOM4 exceptions are not included as they are not expected to be used. +// Should only be used on Host_8 and before. enum Error { kNotSupportedError = 9, kInvalidStateError = 11, @@ -113,8 +112,20 @@ enum Error { kOutputError = 101 }; -// Time is defined as the number of seconds since the -// Epoch (00:00:00 UTC, January 1, 1970). +// Exceptions used by the CDM to reject promises. +// https://w3c.github.io/encrypted-media/#exceptions +enum Exception { + kExceptionTypeError, + kExceptionNotSupportedError, + kExceptionInvalidStateError, + kExceptionQuotaExceededError +}; + +// Time is defined as the number of seconds since the Epoch +// (00:00:00 UTC, January 1, 1970), not including any added leap second. +// Also see Time definition in spec: https://w3c.github.io/encrypted-media/#time +// Note that Time is defined in millisecond accuracy in the spec but in second +// accuracy here. typedef double Time; // An input buffer can be split into several continuous subsamples. @@ -151,13 +162,13 @@ struct SubsampleEntry { // unencrypted. struct InputBuffer { InputBuffer() - : data(NULL), + : data(nullptr), data_size(0), - key_id(NULL), + key_id(nullptr), key_id_size(0), - iv(NULL), + iv(nullptr), iv_size(0), - subsamples(NULL), + subsamples(nullptr), num_subsamples(0), timestamp(0) {} @@ -188,7 +199,7 @@ struct AudioDecoderConfig { channel_count(0), bits_per_channel(0), samples_per_second(0), - extra_data(NULL), + extra_data(nullptr), extra_data_size(0) {} AudioCodec codec; @@ -214,10 +225,25 @@ enum AudioFormat { }; // Surface formats based on FOURCC labels, see: http://www.fourcc.org/yuv.php +// Values are chosen to be consistent with Chromium's VideoPixelFormat values. enum VideoFormat { kUnknownVideoFormat = 0, // Unknown format value. Used for error reporting. - kYv12, // 12bpp YVU planar 1x1 Y, 2x2 VU samples. - kI420 // 12bpp YVU planar 1x1 Y, 2x2 UV samples. + kYv12 = 1, // 12bpp YVU planar 1x1 Y, 2x2 VU samples. + kI420 = 2, // 12bpp YUV planar 1x1 Y, 2x2 UV samples. + + // In the following formats, each sample uses 16-bit in storage, while the + // sample value is stored in the least significant N bits where N is + // specified by the number after "P". For example, for YUV420P9, each Y, U, + // and V sample is stored in the least significant 9 bits in a 2-byte block. + kYUV420P9 = 16, + kYUV420P10 = 17, + kYUV422P9 = 18, + kYUV422P10 = 19, + kYUV444P9 = 20, + kYUV444P10 = 21, + kYUV420P12 = 22, + kYUV422P12 = 23, + kYUV444P12 = 24, }; struct Size { @@ -245,14 +271,19 @@ struct VideoDecoderConfig { kH264ProfileHigh, kH264ProfileHigh10, kH264ProfileHigh422, - kH264ProfileHigh444Predictive + kH264ProfileHigh444Predictive, + // VP9 Profiles are only passed in starting from CDM_9. + kVP9Profile0, + kVP9Profile1, + kVP9Profile2, + kVP9Profile3 }; VideoDecoderConfig() : codec(kUnknownVideoCodec), profile(kUnknownVideoCodecProfile), format(kUnknownVideoFormat), - extra_data(NULL), + extra_data(nullptr), extra_data_size(0) {} VideoCodec codec; @@ -294,7 +325,7 @@ struct PlatformChallengeResponse { // Used when passing arrays of binary data. Does not own the referenced data. struct BinaryData { - BinaryData() : data(NULL), length(0) {} + BinaryData() : data(nullptr), length(0) {} const uint8_t* data; uint32_t length; }; @@ -316,7 +347,10 @@ enum KeyStatus { // should be 0 when |status| == kUsable. struct KeyInformation { KeyInformation() - : key_id(NULL), key_id_size(0), status(kInternalError), system_code(0) {} + : key_id(nullptr), + key_id_size(0), + status(kInternalError), + system_code(0) {} const uint8_t* key_id; uint32_t key_id_size; KeyStatus status; @@ -372,6 +406,24 @@ enum MessageType { kLicenseRelease = 2 }; +enum HdcpVersion { + kHdcpVersionNone, + kHdcpVersion1_0, + kHdcpVersion1_1, + kHdcpVersion1_2, + kHdcpVersion1_3, + kHdcpVersion1_4, + kHdcpVersion2_0, + kHdcpVersion2_1, + kHdcpVersion2_2 +}; + +struct Policy { + Policy() : min_hdcp_version(kHdcpVersionNone) {} + + HdcpVersion min_hdcp_version; +}; + // FileIO interface provides a way for the CDM to store data in a file in // persistent storage. This interface aims only at providing basic read/write // capabilities and should not be used as a full fledged file IO API. @@ -381,7 +433,7 @@ enum MessageType { // Note to implementors of this interface: // Per-origin storage and the ability for users to clear it are important. // See http://www.w3.org/TR/encrypted-media/#privacy-storedinfo. -class FileIO { +class CDM_CLASS_API FileIO { public: // Opens the file with |file_name| for read and write. // FileIOClient::OnOpenComplete() will be called after the opening @@ -421,7 +473,7 @@ class FileIO { // When kError is returned, the FileIO object could be in an error state. All // following calls (other than Close()) could return kError. The CDM should // still call Close() to destroy the FileIO object. -class FileIOClient { +class CDM_CLASS_API FileIOClient { public: enum Status { kSuccess = 0, @@ -462,10 +514,20 @@ class FileIOClient { // provided in CreateCdmInstance() to allocate any Buffer that needs to // be passed back to the caller. Implementations must call Buffer::Destroy() // when a Buffer is created that will never be returned to the caller. -class ContentDecryptionModule_7 { +class CDM_CLASS_API ContentDecryptionModule_8 { public: - static const int kVersion = 7; - typedef Host_7 Host; + static const int kVersion = 8; + typedef Host_8 Host; + + // Initializes the CDM instance, providing information about permitted + // functionalities. + // If |allow_distinctive_identifier| is false, messages from the CDM, + // such as message events, must not contain a Distinctive Identifier, + // even in an encrypted form. + // If |allow_persistent_state| is false, the CDM must not attempt to + // persist state. Calls to CreateFileIO() will fail. + virtual void Initialize(bool allow_distinctive_identifier, + bool allow_persistent_state) = 0; // SetServerCertificate(), CreateSessionAndGenerateRequest(), LoadSession(), // UpdateSession(), CloseSession(), and RemoveSession() all accept a @@ -484,8 +546,7 @@ class ContentDecryptionModule_7 { // or Host::OnRejectPromise(). virtual void CreateSessionAndGenerateRequest(uint32_t promise_id, SessionType session_type, - const char* init_data_type, - uint32_t init_data_type_size, + InitDataType init_data_type, const uint8_t* init_data, uint32_t init_data_size) = 0; @@ -631,8 +692,8 @@ class ContentDecryptionModule_7 { virtual void Destroy() = 0; protected: - ContentDecryptionModule_7() {} - virtual ~ContentDecryptionModule_7() {} + ContentDecryptionModule_8() {} + virtual ~ContentDecryptionModule_8() {} }; // ContentDecryptionModule interface that all CDMs need to implement. @@ -641,10 +702,10 @@ class ContentDecryptionModule_7 { // provided in CreateCdmInstance() to allocate any Buffer that needs to // be passed back to the caller. Implementations must call Buffer::Destroy() // when a Buffer is created that will never be returned to the caller. -class ContentDecryptionModule_8 { +class CDM_CLASS_API ContentDecryptionModule_9 { public: - static const int kVersion = 8; - typedef Host_8 Host; + static const int kVersion = 9; + typedef Host_9 Host; // Initializes the CDM instance, providing information about permitted // functionalities. @@ -656,6 +717,13 @@ class ContentDecryptionModule_8 { virtual void Initialize(bool allow_distinctive_identifier, bool allow_persistent_state) = 0; + // Gets the key status if the CDM has a hypothetical key with the |policy|. + // The CDM must respond by calling either Host::OnResolveKeyStatusPromise() + // with the result key status or Host::OnRejectPromise() if an unexpected + // error happened or this method is not supported. + virtual void GetStatusForPolicy(uint32_t promise_id, + const Policy& policy) = 0; + // SetServerCertificate(), CreateSessionAndGenerateRequest(), LoadSession(), // UpdateSession(), CloseSession(), and RemoveSession() all accept a // |promise_id|, which must be passed to the completion Host method @@ -815,18 +883,23 @@ class ContentDecryptionModule_8 { uint32_t link_mask, uint32_t output_protection_mask) = 0; + // Called by the host after a call to Host::RequestStorageId(). If the storage + // ID is not available, null/zero will be provided. + virtual void OnStorageId(const uint8_t* storage_id, + uint32_t storage_id_size) = 0; + // Destroys the object in the same context as it was created. virtual void Destroy() = 0; protected: - ContentDecryptionModule_8() {} - virtual ~ContentDecryptionModule_8() {} + ContentDecryptionModule_9() {} + virtual ~ContentDecryptionModule_9() {} }; -typedef ContentDecryptionModule_8 ContentDecryptionModule; +typedef ContentDecryptionModule_9 ContentDecryptionModule; // Represents a buffer created by Allocator implementations. -class Buffer { +class CDM_CLASS_API Buffer { public: // Destroys the buffer in the same context as it was created. virtual void Destroy() = 0; @@ -845,9 +918,9 @@ class Buffer { void operator=(const Buffer&); }; -class Host_7 { +class CDM_CLASS_API Host_8 { public: - static const int kVersion = 7; + static const int kVersion = 8; // Returns a Buffer* containing non-zero members upon success, or NULL on // failure. The caller owns the Buffer* after this call. The buffer is not @@ -859,7 +932,7 @@ class Host_7 { // from now with |context|. virtual void SetTimer(int64_t delay_ms, void* context) = 0; - // Returns the current wall time in seconds. + // Returns the current wall time. virtual Time GetCurrentWallTime() = 0; // Called by the CDM when a session is created or loaded and the value for the @@ -917,8 +990,10 @@ class Host_7 { // session |session_id|. This can happen as the result of an Update() call // or some other event. If this happens as a result of a call to Update(), // it must be called before resolving the Update() promise. |new_expiry_time| - // can be 0 to represent "undefined". Size parameter should not include - // null termination. + // represents the time after which the key(s) in the session will no longer + // be usable for decryption. It can be 0 if no such time exists or if the + // license explicitly never expires. Size parameter should not include null + // termination. virtual void OnExpirationChange(const char* session_id, uint32_t session_id_size, Time new_expiry_time) = 0; @@ -978,13 +1053,13 @@ class Host_7 { virtual FileIO* CreateFileIO(FileIOClient* client) = 0; protected: - Host_7() {} - virtual ~Host_7() {} + Host_8() {} + virtual ~Host_8() {} }; -class Host_8 { +class CDM_CLASS_API Host_9 { public: - static const int kVersion = 8; + static const int kVersion = 9; // Returns a Buffer* containing non-zero members upon success, or NULL on // failure. The caller owns the Buffer* after this call. The buffer is not @@ -996,9 +1071,14 @@ class Host_8 { // from now with |context|. virtual void SetTimer(int64_t delay_ms, void* context) = 0; - // Returns the current wall time in seconds. + // Returns the current wall time. virtual Time GetCurrentWallTime() = 0; + // Called by the CDM when a key status is available in response to + // GetStatusForPolicy(). + virtual void OnResolveKeyStatusPromise(uint32_t promise_id, + KeyStatus key_status) = 0; + // Called by the CDM when a session is created or loaded and the value for the // MediaKeySession's sessionId attribute is available (|session_id|). // This must be called before OnSessionMessage() or @@ -1016,26 +1096,21 @@ class Host_8 { // Called by the CDM when an error occurs as a result of one of the // ContentDecryptionModule calls that accept a |promise_id|. - // |error| must be specified, |error_message| and |system_code| + // |exception| must be specified. |error_message| and |system_code| // are optional. |error_message_size| should not include null termination. virtual void OnRejectPromise(uint32_t promise_id, - Error error, + Exception exception, uint32_t system_code, const char* error_message, uint32_t error_message_size) = 0; // Called by the CDM when it has a message for session |session_id|. // Size parameters should not include null termination. - // |legacy_destination_url| is only for supporting the prefixed EME API and - // is ignored by unprefixed EME. It should only be non-null if |message_type| - // is kLicenseRenewal. virtual void OnSessionMessage(const char* session_id, uint32_t session_id_size, MessageType message_type, const char* message, - uint32_t message_size, - const char* legacy_destination_url, - uint32_t legacy_destination_url_length) = 0; + uint32_t message_size) = 0; // Called by the CDM when there has been a change in keys or their status for // session |session_id|. |has_additional_usable_key| should be set if a @@ -1054,8 +1129,10 @@ class Host_8 { // session |session_id|. This can happen as the result of an Update() call // or some other event. If this happens as a result of a call to Update(), // it must be called before resolving the Update() promise. |new_expiry_time| - // can be 0 to represent "undefined". Size parameter should not include - // null termination. + // represents the time after which the key(s) in the session will no longer + // be usable for decryption. It can be 0 if no such time exists or if the + // license explicitly never expires. Size parameter should not include null + // termination. virtual void OnExpirationChange(const char* session_id, uint32_t session_id_size, Time new_expiry_time) = 0; @@ -1065,21 +1142,6 @@ class Host_8 { virtual void OnSessionClosed(const char* session_id, uint32_t session_id_size) = 0; - // Called by the CDM when an error occurs in session |session_id| - // unrelated to one of the ContentDecryptionModule calls that accept a - // |promise_id|. |error| must be specified, |error_message| and - // |system_code| are optional. Length parameters should not include null - // termination. - // Note: - // - This method is only for supporting prefixed EME API. - // - This method will be ignored by unprefixed EME. All errors reported - // in this method should probably also be reported by one of other methods. - virtual void OnLegacySessionError( - const char* session_id, uint32_t session_id_length, - Error error, - uint32_t system_code, - const char* error_message, uint32_t error_message_length) = 0; - // The following are optional methods that may not be implemented on all // platforms. @@ -1114,13 +1176,19 @@ class Host_8 { // CDM can call this method multiple times to operate on different files. virtual FileIO* CreateFileIO(FileIOClient* client) = 0; + // Requests the storage ID. The ID will be returned by the host via + // ContentDecryptionModule::OnStorageId(). A storage ID is a stable, device + // specific ID used by the CDM to securely store persistent data. The CDM must + // not expose the ID outside the client device, even in encrypted form. + virtual void RequestStorageId() = 0; + protected: - Host_8() {} - virtual ~Host_8() {} + Host_9() {} + virtual ~Host_9() {} }; // Represents a decrypted block that has not been decoded. -class DecryptedBlock { +class CDM_CLASS_API DecryptedBlock { public: virtual void SetDecryptedBuffer(Buffer* buffer) = 0; virtual Buffer* DecryptedBuffer() = 0; @@ -1135,7 +1203,7 @@ class DecryptedBlock { virtual ~DecryptedBlock() {} }; -class VideoFrame { +class CDM_CLASS_API VideoFrame { public: enum VideoPlane { kYPlane = 0, @@ -1178,7 +1246,7 @@ class VideoFrame { // // |<----------------- AudioFrames ------------------>| // | audio buffer 0 | audio buffer 1 | audio buffer 2 | -class AudioFrames { +class CDM_CLASS_API AudioFrames { public: virtual void SetFrameBuffer(Buffer* buffer) = 0; virtual Buffer* FrameBuffer() = 0; diff --git a/dom/media/gmp/widevine-adapter/content_decryption_module_export.h b/dom/media/gmp/widevine-adapter/content_decryption_module_export.h new file mode 100644 index 000000000..51d485892 --- /dev/null +++ b/dom/media/gmp/widevine-adapter/content_decryption_module_export.h @@ -0,0 +1,22 @@ +// Copyright 2017 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 CDM_CONTENT_DECRYPTION_MODULE_EXPORT_H_ +#define CDM_CONTENT_DECRYPTION_MODULE_EXPORT_H_ + +// Define CDM_API so that functionality implemented by the CDM module +// can be exported to consumers. +#if defined(_WIN32) + +#if defined(CDM_IMPLEMENTATION) +#define CDM_API __declspec(dllexport) +#else +#define CDM_API __declspec(dllimport) +#endif // defined(CDM_IMPLEMENTATION) + +#else // defined(_WIN32) +#define CDM_API __attribute__((visibility("default"))) +#endif // defined(_WIN32) + +#endif // CDM_CONTENT_DECRYPTION_MODULE_EXPORT_H_ -- cgit v1.2.3 From 8279f15d49dc14ec158c6457fd266adc1bfbb12e Mon Sep 17 00:00:00 2001 From: trav90 Date: Fri, 8 Feb 2019 13:48:02 -0600 Subject: [EME] Add content_decryption_module_ext.h --- .../content_decryption_module_ext.h | 64 ++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 dom/media/gmp/widevine-adapter/content_decryption_module_ext.h (limited to 'dom') diff --git a/dom/media/gmp/widevine-adapter/content_decryption_module_ext.h b/dom/media/gmp/widevine-adapter/content_decryption_module_ext.h new file mode 100644 index 000000000..5df8344e6 --- /dev/null +++ b/dom/media/gmp/widevine-adapter/content_decryption_module_ext.h @@ -0,0 +1,64 @@ +// Copyright 2017 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 CDM_CONTENT_DECRYPTION_MODULE_EXT_H_ +#define CDM_CONTENT_DECRYPTION_MODULE_EXT_H_ + +#if defined(_WIN32) +#include +#endif + +#include "content_decryption_module_export.h" + +#if defined(_MSC_VER) +typedef unsigned int uint32_t; +#else +#include +#endif + +namespace cdm { + +#if defined(_WIN32) +typedef wchar_t FilePathCharType; +typedef HANDLE PlatformFile; +const PlatformFile kInvalidPlatformFile = INVALID_HANDLE_VALUE; +#else +typedef char FilePathCharType; +typedef int PlatformFile; +const PlatformFile kInvalidPlatformFile = -1; +#endif // defined(_WIN32) + +struct HostFile { + HostFile(const FilePathCharType* file_path, + PlatformFile file, + PlatformFile sig_file) + : file_path(file_path), file(file), sig_file(sig_file) {} + + // File that is part of the host of the CDM. + const FilePathCharType* file_path = nullptr; + PlatformFile file = kInvalidPlatformFile; + + // Signature file for |file|. + PlatformFile sig_file = kInvalidPlatformFile; +}; + +} // namespace cdm + +extern "C" { + +// Functions in this file are dynamically retrieved by their versioned function +// names. Increment the version number for any backward incompatible API +// changes. + +// Verifies CDM host. All files in |host_files| are opened in read-only mode. +// +// Returns false and closes all files if there is an immediate failure. +// Otherwise returns true as soon as possible and processes the files +// asynchronously. All files MUST be closed by the CDM after this one-time +// processing is finished. +CDM_API bool VerifyCdmHost_0(const cdm::HostFile* host_files, + uint32_t num_files); +} + +#endif // CDM_CONTENT_DECRYPTION_MODULE_EXT_H_ -- cgit v1.2.3 From e1d7634ba00b11292c742a6d8e03df111149d7c9 Mon Sep 17 00:00:00 2001 From: trav90 Date: Fri, 8 Feb 2019 13:50:27 -0600 Subject: [EME] Cherry-pick fix for content_decryption_module.h Fixes build bustage with GCC/clang. --- .../widevine-adapter/content_decryption_module.h | 39 ++++++++++++++-------- 1 file changed, 25 insertions(+), 14 deletions(-) (limited to 'dom') diff --git a/dom/media/gmp/widevine-adapter/content_decryption_module.h b/dom/media/gmp/widevine-adapter/content_decryption_module.h index 3f065017b..0539135fb 100644 --- a/dom/media/gmp/widevine-adapter/content_decryption_module.h +++ b/dom/media/gmp/widevine-adapter/content_decryption_module.h @@ -441,8 +441,9 @@ class CDM_CLASS_API FileIO { // - When the file is opened by a CDM instance, it will be classified as "in // use". In this case other CDM instances in the same domain may receive // kInUse status when trying to open it. - // - |file_name| must not contain forward slash ('/') or backslash ('\'), and - // must not start with an underscore ('_'). + // - |file_name| must only contain letters (A-Za-z), digits(0-9), or "._-". + // It must not start with an underscore ('_'), and must be at least 1 + // character and no more than 256 characters long. virtual void Open(const char* file_name, uint32_t file_name_size) = 0; // Reads the contents of the file. FileIOClient::OnReadComplete() will be @@ -799,8 +800,8 @@ class CDM_CLASS_API ContentDecryptionModule_9 { // // Returns kSuccess if the |audio_decoder_config| is supported and the CDM // audio decoder is successfully initialized. - // Returns kSessionError if |audio_decoder_config| is not supported. The CDM - // may still be able to do Decrypt(). + // Returns kInitializationError if |audio_decoder_config| is not supported. + // The CDM may still be able to do Decrypt(). // Returns kDeferredInitialization if the CDM is not ready to initialize the // decoder at this time. Must call Host::OnDeferredInitializationDone() once // initialization is complete. @@ -812,8 +813,8 @@ class CDM_CLASS_API ContentDecryptionModule_9 { // // Returns kSuccess if the |video_decoder_config| is supported and the CDM // video decoder is successfully initialized. - // Returns kSessionError if |video_decoder_config| is not supported. The CDM - // may still be able to do Decrypt(). + // Returns kInitializationError if |video_decoder_config| is not supported. + // The CDM may still be able to do Decrypt(). // Returns kDeferredInitialization if the CDM is not ready to initialize the // decoder at this time. Must call Host::OnDeferredInitializationDone() once // initialization is complete. @@ -883,9 +884,16 @@ class CDM_CLASS_API ContentDecryptionModule_9 { uint32_t link_mask, uint32_t output_protection_mask) = 0; - // Called by the host after a call to Host::RequestStorageId(). If the storage - // ID is not available, null/zero will be provided. - virtual void OnStorageId(const uint8_t* storage_id, + // Called by the host after a call to Host::RequestStorageId(). If the + // version of the storage ID requested is available, |storage_id| and + // |storage_id_size| are set appropriately. |version| will be the same as + // what was requested, unless 0 (latest) was requested, in which case + // |version| will be the actual version number for the |storage_id| returned. + // If the requested version is not available, null/zero will be provided as + // |storage_id| and |storage_id_size|, respectively, and |version| should be + // ignored. + virtual void OnStorageId(uint32_t version, + const uint8_t* storage_id, uint32_t storage_id_size) = 0; // Destroys the object in the same context as it was created. @@ -1176,11 +1184,14 @@ class CDM_CLASS_API Host_9 { // CDM can call this method multiple times to operate on different files. virtual FileIO* CreateFileIO(FileIOClient* client) = 0; - // Requests the storage ID. The ID will be returned by the host via - // ContentDecryptionModule::OnStorageId(). A storage ID is a stable, device - // specific ID used by the CDM to securely store persistent data. The CDM must - // not expose the ID outside the client device, even in encrypted form. - virtual void RequestStorageId() = 0; + // Requests a specific version of the storage ID. A storage ID is a stable, + // device specific ID used by the CDM to securely store persistent data. The + // ID will be returned by the host via ContentDecryptionModule::OnStorageId(). + // If |version| is 0, the latest version will be returned. All |version|s + // that are greater than or equal to 0x80000000 are reserved for the CDM and + // should not be supported or returned by the host. The CDM must not expose + // the ID outside the client device, even in encrypted form. + virtual void RequestStorageId(uint32_t version) = 0; protected: Host_9() {} -- cgit v1.2.3 From 3a6a37ca1b335dc97247f7facae46bc026802e03 Mon Sep 17 00:00:00 2001 From: trav90 Date: Fri, 8 Feb 2019 13:55:14 -0600 Subject: Style fixes --- dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'dom') diff --git a/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp b/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp index e3560d33f..ab62ba7ef 100644 --- a/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp +++ b/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp @@ -359,10 +359,10 @@ ConvertCDMErrorToCDMException(cdm::Error error) { void WidevineDecryptor::OnRejectPromise(uint32_t aPromiseId, - cdm::Exception aException, - uint32_t aSystemCode, - const char* aErrorMessage, - uint32_t aErrorMessageSize) + cdm::Exception aException, + uint32_t aSystemCode, + const char* aErrorMessage, + uint32_t aErrorMessageSize) { if (!mCallback) { Log("Decryptor::OnRejectPromise(aPromiseId=%d, err=%d, sysCode=%u, msg=%s) FAIL; !mCallback", @@ -390,10 +390,10 @@ ToGMPMessageType(MessageType message_type) void WidevineDecryptor::OnSessionMessage(const char* aSessionId, - uint32_t aSessionIdSize, - cdm::MessageType aMessageType, - const char* aMessage, - uint32_t aMessageSize) + uint32_t aSessionIdSize, + cdm::MessageType aMessageType, + const char* aMessage, + uint32_t aMessageSize) { if (!mCallback) { Log("Decryptor::OnSessionMessage() FAIL; !mCallback"); @@ -544,7 +544,7 @@ WidevineDecryptor::CreateFileIO(FileIOClient* aClient) void WidevineDecryptor::RequestStorageId(uint32_t aVersion) { - Log("ChromiumCDMChild::RequestStorageId() aVersion = %u", aVersion); + Log("Decryptor::RequestStorageId() aVersion = %u", aVersion); if (aVersion >= 0x80000000) { mCDM->OnStorageId(aVersion, nullptr, 0); return; -- cgit v1.2.3 From 05a51611bc15f436adac30ea7097a48bb7c7b51e Mon Sep 17 00:00:00 2001 From: trav90 Date: Fri, 8 Feb 2019 14:40:12 -0600 Subject: Build bustage fixes --- dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'dom') diff --git a/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp b/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp index ab62ba7ef..150480644 100644 --- a/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp +++ b/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp @@ -302,7 +302,7 @@ WidevineDecryptor::GetCurrentWallTime() } void -ChromiumCDMChild::OnResolveKeyStatusPromise(uint32_t aPromiseId, +WidevineDecryptor::OnResolveKeyStatusPromise(uint32_t aPromiseId, cdm::KeyStatus aKeyStatus) { //TODO: The callback of GetStatusForPolicy. See Mozilla bug 1404230. } @@ -351,6 +351,10 @@ ConvertCDMErrorToCDMException(cdm::Error error) { return cdm::Exception::kExceptionTypeError; case cdm::kQuotaExceededError: return cdm::Exception::kExceptionQuotaExceededError; + + case cdm::kUnknownError: + case cdm::kClientError: + case cdm::kOutputError: break; } @@ -370,7 +374,7 @@ WidevineDecryptor::OnRejectPromise(uint32_t aPromiseId, return; } Log("Decryptor::OnRejectPromise(aPromiseId=%d, err=%d, sysCode=%u, msg=%s)", - aPromiseId, (int)aError, aSystemCode, aErrorMessage); + aPromiseId, (int)aException, aSystemCode, aErrorMessage); mCallback->RejectPromise(aPromiseId, ToGMPDOMException(aException), !aErrorMessageSize ? "" : aErrorMessage, -- cgit v1.2.3 From cece1cb715b43fd99ec3dda926abe30181a8f5dd Mon Sep 17 00:00:00 2001 From: trav90 Date: Sat, 9 Feb 2019 07:50:35 -0600 Subject: [EME] Remove WidevineDecryptor::OnLegacySessionError Not needed for more recent CDM versions. --- .../gmp/widevine-adapter/WidevineDecryptor.cpp | 22 ---------------------- 1 file changed, 22 deletions(-) (limited to 'dom') diff --git a/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp b/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp index 150480644..f89888a72 100644 --- a/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp +++ b/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp @@ -485,28 +485,6 @@ WidevineDecryptor::OnSessionClosed(const char* aSessionId, mCallback->SessionClosed(aSessionId, aSessionIdSize); } -void -WidevineDecryptor::OnLegacySessionError(const char* aSessionId, - uint32_t aSessionIdLength, - Error aError, - uint32_t aSystemCode, - const char* aErrorMessage, - uint32_t aErrorMessageLength) -{ - if (!mCallback) { - Log("Decryptor::OnLegacySessionError(sid=%s, error=%d) FAIL; !mCallback", - aSessionId, (int)aError); - return; - } - Log("Decryptor::OnLegacySessionError(sid=%s, error=%d)", aSessionId, (int)aError); - mCallback->SessionError(aSessionId, - aSessionIdLength, - ToGMPDOMException(aError), - aSystemCode, - aErrorMessage, - aErrorMessageLength); -} - void WidevineDecryptor::SendPlatformChallenge(const char* aServiceId, uint32_t aServiceIdSize, -- cgit v1.2.3 From 487afe9f45a846daaf8aab8b0cc0022dbc92ce09 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Tue, 12 Feb 2019 11:05:16 +0100 Subject: Allow empty string on `location.search` setter. Fixes #970. --- dom/base/Location.cpp | 4 ---- 1 file changed, 4 deletions(-) (limited to 'dom') diff --git a/dom/base/Location.cpp b/dom/base/Location.cpp index 3a39a9e66..1483c32f9 100644 --- a/dom/base/Location.cpp +++ b/dom/base/Location.cpp @@ -789,10 +789,6 @@ Location::GetSearch(nsAString& aSearch) NS_IMETHODIMP Location::SetSearch(const nsAString& aSearch) { - if (aSearch.IsEmpty()) { - return NS_OK; // Ignore empty string - } - nsresult rv = SetSearchInternal(aSearch); if (NS_FAILED(rv)) { return rv; -- cgit v1.2.3 From 43d44975b1f49df640916cca5f6a0b138696da3c Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Wed, 13 Feb 2019 19:11:37 +0100 Subject: Remove WebExtension support from the platform. - Conditional code - WE APIs - WE toolkit theming --- dom/webidl/AddonEvent.webidl | 12 ------ dom/webidl/AddonManager.webidl | 91 ------------------------------------------ dom/webidl/moz.build | 6 --- 3 files changed, 109 deletions(-) delete mode 100644 dom/webidl/AddonEvent.webidl delete mode 100644 dom/webidl/AddonManager.webidl (limited to 'dom') diff --git a/dom/webidl/AddonEvent.webidl b/dom/webidl/AddonEvent.webidl deleted file mode 100644 index 235f81ec2..000000000 --- a/dom/webidl/AddonEvent.webidl +++ /dev/null @@ -1,12 +0,0 @@ -[ Func="mozilla::AddonManagerWebAPI::IsAPIEnabled", - Constructor(DOMString type, AddonEventInit eventInitDict)] -interface AddonEvent : Event { - readonly attribute DOMString id; - readonly attribute boolean needsRestart; -}; - -dictionary AddonEventInit : EventInit { - required DOMString id; - required boolean needsRestart; -}; - diff --git a/dom/webidl/AddonManager.webidl b/dom/webidl/AddonManager.webidl deleted file mode 100644 index 02c7953e6..000000000 --- a/dom/webidl/AddonManager.webidl +++ /dev/null @@ -1,91 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -/* We need a JSImplementation but cannot get one without a contract ID. - Since Addon and AddonInstall are only ever created from JS they don't need - real contract IDs. */ -[ChromeOnly, JSImplementation="dummy"] -interface Addon { - // The add-on's ID. - readonly attribute DOMString id; - // The add-on's version. - readonly attribute DOMString version; - // The add-on's type (extension, theme, etc.). - readonly attribute DOMString type; - // The add-on's name in the current locale. - readonly attribute DOMString name; - // The add-on's description in the current locale. - readonly attribute DOMString description; - // If the user has enabled this add-on, note that it still may not be running - // depending on whether enabling requires a restart or if the add-on is - // incompatible in some way. - readonly attribute boolean isEnabled; - // If the add-on is currently active in the browser. - readonly attribute boolean isActive; - // If the add-on may be uninstalled - readonly attribute boolean canUninstall; - - Promise uninstall(); - Promise setEnabled(boolean value); -}; - -[ChromeOnly, JSImplementation="dummy"] -interface AddonInstall : EventTarget { - // One of the STATE_* symbols from AddonManager.jsm - readonly attribute DOMString state; - // One of the ERROR_* symbols from AddonManager.jsm, or null - readonly attribute DOMString? error; - // How many bytes have been downloaded - readonly attribute long long progress; - // How many total bytes will need to be downloaded or -1 if unknown - readonly attribute long long maxProgress; - - Promise install(); - Promise cancel(); -}; - -dictionary addonInstallOptions { - required DOMString url; - // If a non-empty string is passed for "hash", it is used to verify the - // checksum of the downloaded XPI before installing. If is omitted or if - // it is null or empty string, no checksum verification is performed. - DOMString? hash = null; -}; - -[HeaderFile="mozilla/AddonManagerWebAPI.h", - Func="mozilla::AddonManagerWebAPI::IsAPIEnabled", - NavigatorProperty="mozAddonManager", - JSImplementation="@mozilla.org/addon-web-api/manager;1"] -interface AddonManager : EventTarget { - /** - * Gets information about an add-on - * - * @param id - * The ID of the add-on to test for. - * @return A promise. It will resolve to an Addon if the add-on is installed. - */ - Promise getAddonByID(DOMString id); - - /** - * Creates an AddonInstall object for a given URL. - * - * @param options - * Only one supported option: 'url', the URL of the addon to install. - * @return A promise that resolves to an instance of AddonInstall. - */ - Promise createInstall(optional addonInstallOptions options); - - /* Hooks for managing event listeners */ - [ChromeOnly] - void eventListenerWasAdded(DOMString type); - [ChromeOnly] - void eventListenerWasRemoved(DOMString type); -}; - -[ChromeOnly,Exposed=System,HeaderFile="mozilla/AddonManagerWebAPI.h"] -interface AddonManagerPermissions { - static boolean isHostPermitted(DOMString host); -}; - diff --git a/dom/webidl/moz.build b/dom/webidl/moz.build index 06fea2f20..aae7e479c 100644 --- a/dom/webidl/moz.build +++ b/dom/webidl/moz.build @@ -591,9 +591,6 @@ WEBIDL_FILES = [ 'XULElement.webidl', ] -if CONFIG['MOZ_WEBEXTENSIONS']: - WEBIDL_FILES += ['AddonManager.webidl'] - if CONFIG['MOZ_AUDIO_CHANNEL_MANAGER']: WEBIDL_FILES += [ 'AudioChannelManager.webidl', @@ -722,9 +719,6 @@ GENERATED_EVENTS_WEBIDL_FILES = [ 'WebGLContextEvent.webidl', ] -if CONFIG['MOZ_WEBEXTENSIONS']: - GENERATED_EVENTS_WEBIDL_FILES += ['AddonEvent.webidl'] - if CONFIG['MOZ_WEBRTC']: GENERATED_EVENTS_WEBIDL_FILES += [ 'RTCDataChannelEvent.webidl', -- cgit v1.2.3 From 91799767e1c575dce6cdb1528f1f10a1fd62e35f Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Thu, 14 Feb 2019 11:46:21 +0100 Subject: Implement origin-clean algorithm for ImageBitmap. This resolves #973. --- dom/canvas/CanvasRenderingContext2D.cpp | 17 +++-- dom/canvas/CanvasRenderingContext2D.h | 14 ++++ dom/canvas/ImageBitmap.cpp | 101 +++++++++++++++++------------ dom/canvas/ImageBitmap.h | 12 ++++ dom/canvas/ImageBitmapRenderingContext.cpp | 5 ++ dom/canvas/WebGLContext.h | 3 +- dom/canvas/WebGLTextureUpload.cpp | 22 ++++++- dom/canvas/test/test_imagebitmap.html | 23 +++++-- dom/html/HTMLCanvasElement.cpp | 2 +- dom/html/HTMLCanvasElement.h | 4 +- 10 files changed, 143 insertions(+), 60 deletions(-) (limited to 'dom') diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp index b60ab239d..a750c69b0 100644 --- a/dom/canvas/CanvasRenderingContext2D.cpp +++ b/dom/canvas/CanvasRenderingContext2D.cpp @@ -1105,6 +1105,7 @@ CanvasRenderingContext2D::CanvasRenderingContext2D(layers::LayersBackend aCompos , mIsCapturedFrameInvalid(false) , mPathTransformWillUpdate(false) , mInvalidateCount(0) + , mWriteOnly(false) // == !origin-clean { sNumLivingContexts++; @@ -2562,7 +2563,8 @@ CanvasRenderingContext2D::CreatePattern(const CanvasImageSource& aSource, // nullptr and set CORSUsed to true for passing the security check in // CanvasUtils::DoDrawImageSecurityCheck(). RefPtr pat = - new CanvasPattern(this, srcSurf, repeatMode, nullptr, false, true); + new CanvasPattern(this, srcSurf, repeatMode, nullptr, + imgBitmap.IsWriteOnly(), true); return pat.forget(); } @@ -4952,6 +4954,10 @@ CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage, aError.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return; } + + if (canvas->IsWriteOnly()) { + SetWriteOnly(); + } } else if (aImage.IsImageBitmap()) { ImageBitmap& imageBitmap = aImage.GetAsImageBitmap(); srcSurf = imageBitmap.PrepareForDrawTarget(mTarget); @@ -4960,6 +4966,10 @@ CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage, return; } + if (imageBitmap.IsWriteOnly()) { + SetWriteOnly(); + } + imgSize = gfx::IntSize(imageBitmap.Width(), imageBitmap.Height()); } else { @@ -5674,9 +5684,8 @@ CanvasRenderingContext2D::GetImageData(JSContext* aCx, double aSx, // Check only if we have a canvas element; if we were created with a docshell, // then it's special internal use. - if (mCanvasElement && mCanvasElement->IsWriteOnly() && - !nsContentUtils::IsCallerChrome()) - { + if (IsWriteOnly() || + (mCanvasElement && mCanvasElement->IsWriteOnly() && !nsContentUtils::IsCallerChrome())) { // XXX ERRMSG we need to report an error to developers here! (bug 329026) aError.Throw(NS_ERROR_DOM_SECURITY_ERR); return nullptr; diff --git a/dom/canvas/CanvasRenderingContext2D.h b/dom/canvas/CanvasRenderingContext2D.h index 848b3ee08..46758ec88 100644 --- a/dom/canvas/CanvasRenderingContext2D.h +++ b/dom/canvas/CanvasRenderingContext2D.h @@ -40,6 +40,7 @@ class SourceSurface; namespace dom { class HTMLImageElementOrSVGImageElementOrHTMLCanvasElementOrHTMLVideoElementOrImageBitmap; typedef HTMLImageElementOrSVGImageElementOrHTMLCanvasElementOrHTMLVideoElementOrImageBitmap CanvasImageSource; +class ImageBitmap; class ImageData; class StringOrCanvasGradientOrCanvasPattern; class OwningStringOrCanvasGradientOrCanvasPattern; @@ -1151,6 +1152,19 @@ protected: friend struct CanvasBidiProcessor; friend class CanvasDrawObserver; + friend class ImageBitmap; + + // For the origin-clean algorithm (mWriteOnly == !origin-clean) + // See https://html.spec.whatwg.org/multipage/imagebitmap-and-animations.html + void SetWriteOnly() { + mWriteOnly = true; + } + + bool IsWriteOnly() const { + return mWriteOnly; + } + + bool mWriteOnly; }; } // namespace dom diff --git a/dom/canvas/ImageBitmap.cpp b/dom/canvas/ImageBitmap.cpp index e45cdfc6f..6efe1b318 100644 --- a/dom/canvas/ImageBitmap.cpp +++ b/dom/canvas/ImageBitmap.cpp @@ -351,29 +351,27 @@ CheckSecurityForHTMLElements(const nsLayoutUtils::SurfaceFromElementResult& aRes */ template static already_AddRefed -GetSurfaceFromElement(nsIGlobalObject* aGlobal, HTMLElementType& aElement, ErrorResult& aRv) +GetSurfaceFromElement(nsIGlobalObject* aGlobal, HTMLElementType& aElement, + bool* aWriteOnly, ErrorResult& aRv) { nsLayoutUtils::SurfaceFromElementResult res = nsLayoutUtils::SurfaceFromElement(&aElement, nsLayoutUtils::SFE_WANT_FIRST_FRAME); - // check origin-clean - if (!CheckSecurityForHTMLElements(res)) { - aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); - return nullptr; - } - RefPtr surface = res.GetSourceSurface(); if (NS_WARN_IF(!surface)) { - aRv.Throw(NS_ERROR_NOT_AVAILABLE); + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return nullptr; } + + // Check origin-clean and pass back + *aWriteOnly = !CheckSecurityForHTMLElements(res); return surface.forget(); } /* - * The specification doesn't allow to create an ImegeBitmap from a vector image. + * The specification doesn't allow to create an ImageBitmap from a vector image. * This function is used to check if the given HTMLImageElement contains a * raster image. */ @@ -398,7 +396,7 @@ HasRasterImage(HTMLImageElement& aImageEl) } ImageBitmap::ImageBitmap(nsIGlobalObject* aGlobal, layers::Image* aData, - bool aIsPremultipliedAlpha /* = true */) + bool aWriteOnly, bool aIsPremultipliedAlpha /* = true */) : mParent(aGlobal) , mData(aData) , mSurface(nullptr) @@ -406,6 +404,7 @@ ImageBitmap::ImageBitmap(nsIGlobalObject* aGlobal, layers::Image* aData, , mPictureRect(0, 0, aData->GetSize().width, aData->GetSize().height) , mIsPremultipliedAlpha(aIsPremultipliedAlpha) , mIsCroppingAreaOutSideOfSourceImage(false) + , mWriteOnly(aWriteOnly) { MOZ_ASSERT(aData, "aData is null in ImageBitmap constructor."); } @@ -698,6 +697,7 @@ ImageBitmap::ToCloneData() const RefPtr surface = mData->GetAsSourceSurface(); result->mSurface = surface->GetDataSurface(); MOZ_ASSERT(result->mSurface); + result->mWriteOnly = mWriteOnly; return Move(result); } @@ -708,7 +708,7 @@ ImageBitmap::CreateFromCloneData(nsIGlobalObject* aGlobal, { RefPtr data = CreateImageFromSurface(aData->mSurface); - RefPtr ret = new ImageBitmap(aGlobal, data, + RefPtr ret = new ImageBitmap(aGlobal, data, aData->mWriteOnly, aData->mIsPremultipliedAlpha); ret->mIsCroppingAreaOutSideOfSourceImage = @@ -724,11 +724,8 @@ ImageBitmap::CreateFromOffscreenCanvas(nsIGlobalObject* aGlobal, OffscreenCanvas& aOffscreenCanvas, ErrorResult& aRv) { - // Check origin-clean. - if (aOffscreenCanvas.IsWriteOnly()) { - aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); - return nullptr; - } + // Check origin-clean + bool writeOnly = aOffscreenCanvas.IsWriteOnly(); nsLayoutUtils::SurfaceFromElementResult res = nsLayoutUtils::SurfaceFromOffscreenCanvas(&aOffscreenCanvas, @@ -744,7 +741,7 @@ ImageBitmap::CreateFromOffscreenCanvas(nsIGlobalObject* aGlobal, RefPtr data = CreateImageFromSurface(surface); - RefPtr ret = new ImageBitmap(aGlobal, data); + RefPtr ret = new ImageBitmap(aGlobal, data, writeOnly); return ret.forget(); } @@ -757,16 +754,19 @@ ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, HTMLImageElement& aImageEl aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return nullptr; } - + // Check if the image element is a bitmap (e.g. it's a vector graphic) or not. if (!HasRasterImage(aImageEl)) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return nullptr; } + bool writeOnly = true; + // Get the SourceSurface out from the image element and then do security // checking. - RefPtr surface = GetSurfaceFromElement(aGlobal, aImageEl, aRv); + RefPtr surface = GetSurfaceFromElement(aGlobal, aImageEl, + &writeOnly, aRv); if (NS_WARN_IF(aRv.Failed())) { return nullptr; @@ -780,7 +780,7 @@ ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, HTMLImageElement& aImageEl return nullptr; } - RefPtr ret = new ImageBitmap(aGlobal, data); + RefPtr ret = new ImageBitmap(aGlobal, data, writeOnly); // Set the picture rectangle. if (ret && aCropRect.isSome()) { @@ -812,13 +812,13 @@ ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, HTMLVideoElement& aVideoEl return nullptr; } + bool writeOnly = true; + // Check security. nsCOMPtr principal = aVideoEl.GetCurrentVideoPrincipal(); bool CORSUsed = aVideoEl.GetCORSMode() != CORS_NONE; - if (!CheckSecurityForHTMLElements(false, CORSUsed, principal)) { - aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); - return nullptr; - } + + writeOnly = !CheckSecurityForHTMLElements(false, CORSUsed, principal); // Create ImageBitmap. ImageContainer *container = aVideoEl.GetImageContainer(); @@ -834,7 +834,7 @@ ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, HTMLVideoElement& aVideoEl aRv.Throw(NS_ERROR_NOT_AVAILABLE); return nullptr; } - RefPtr ret = new ImageBitmap(aGlobal, data); + RefPtr ret = new ImageBitmap(aGlobal, data, writeOnly); // Set the picture rectangle. if (ret && aCropRect.isSome()) { @@ -856,12 +856,18 @@ ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, HTMLCanvasElement& aCanvas return nullptr; } - RefPtr surface = GetSurfaceFromElement(aGlobal, aCanvasEl, aRv); + bool writeOnly = true; + + RefPtr surface = GetSurfaceFromElement(aGlobal, aCanvasEl, &writeOnly, aRv); if (NS_WARN_IF(aRv.Failed())) { return nullptr; } + if (!writeOnly) { + writeOnly = aCanvasEl.IsWriteOnly(); + } + // Crop the source surface if needed. RefPtr croppedSurface; IntRect cropRect = aCropRect.valueOr(IntRect()); @@ -874,8 +880,7 @@ ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, HTMLCanvasElement& aCanvas aCropRect.isSome()) { // The _surface_ must be a DataSourceSurface. MOZ_ASSERT(surface->GetType() == SurfaceType::DATA, - "The snapshot SourceSurface from WebGL rendering contest is not \ - DataSourceSurface."); + "The snapshot SourceSurface from WebGL rendering contest is not DataSourceSurface."); RefPtr dataSurface = surface->GetDataSurface(); croppedSurface = CropAndCopyDataSourceSurface(dataSurface, cropRect); cropRect.MoveTo(0, 0); @@ -897,7 +902,7 @@ ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, HTMLCanvasElement& aCanvas return nullptr; } - RefPtr ret = new ImageBitmap(aGlobal, data); + RefPtr ret = new ImageBitmap(aGlobal, data, writeOnly); // Set the picture rectangle. if (ret && aCropRect.isSome()) { @@ -958,9 +963,12 @@ ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, ImageData& aImageData, return nullptr; } - // Create an ImageBimtap. + // Create an ImageBitmap. // ImageData's underlying data is not alpha-premultiplied. - RefPtr ret = new ImageBitmap(aGlobal, data, false); + RefPtr ret = new ImageBitmap(aGlobal, + data, + false /* write-only */, + false /* alpha-premult */); // The cropping information has been handled in the CreateImageFromRawData() // function. @@ -975,11 +983,8 @@ ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, ImageData& aImageData, ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, CanvasRenderingContext2D& aCanvasCtx, const Maybe& aCropRect, ErrorResult& aRv) { - // Check origin-clean. - if (aCanvasCtx.GetCanvas()->IsWriteOnly()) { - aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); - return nullptr; - } + // Check origin-clean + bool writeOnly = aCanvasCtx.GetCanvas()->IsWriteOnly() || aCanvasCtx.IsWriteOnly(); RefPtr surface = aCanvasCtx.GetSurfaceSnapshot(); @@ -1001,7 +1006,7 @@ ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, CanvasRenderingContext2D& return nullptr; } - RefPtr ret = new ImageBitmap(aGlobal, data); + RefPtr ret = new ImageBitmap(aGlobal, data, writeOnly); // Set the picture rectangle. if (ret && aCropRect.isSome()) { @@ -1024,7 +1029,10 @@ ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, ImageBitmap& aImageBitmap, } RefPtr data = aImageBitmap.mData; - RefPtr ret = new ImageBitmap(aGlobal, data, aImageBitmap.mIsPremultipliedAlpha); + RefPtr ret = new ImageBitmap(aGlobal, + data, + aImageBitmap.mWriteOnly, + aImageBitmap.mIsPremultipliedAlpha); // Set the picture rectangle. if (ret && aCropRect.isSome()) { @@ -1295,7 +1303,7 @@ private: } // Create ImageBitmap object. - RefPtr imageBitmap = new ImageBitmap(mGlobalObject, data); + RefPtr imageBitmap = new ImageBitmap(mGlobalObject, data, false /* write-only */); // Set mIsCroppingAreaOutSideOfSourceImage. imageBitmap->SetIsCroppingAreaOutSideOfSourceImage(sourceSize, originalCropRect); @@ -1391,7 +1399,7 @@ private: } // Create ImageBitmap object. - RefPtr imageBitmap = new ImageBitmap(mGlobalObject, data); + RefPtr imageBitmap = new ImageBitmap(mGlobalObject, data, false /* write-only */); // Set mIsCroppingAreaOutSideOfSourceImage. imageBitmap->SetIsCroppingAreaOutSideOfSourceImage(sourceSize, originalCropRect); @@ -1486,14 +1494,19 @@ ImageBitmap::ReadStructuredClone(JSContext* aCx, uint32_t picRectHeight_; uint32_t isPremultipliedAlpha_; uint32_t isCroppingAreaOutSideOfSourceImage_; + uint32_t writeOnly; + uint32_t dummy; if (!JS_ReadUint32Pair(aReader, &picRectX_, &picRectY_) || !JS_ReadUint32Pair(aReader, &picRectWidth_, &picRectHeight_) || !JS_ReadUint32Pair(aReader, &isPremultipliedAlpha_, - &isCroppingAreaOutSideOfSourceImage_)) { + &isCroppingAreaOutSideOfSourceImage_) || + !JS_ReadUint32Pair(aReader, &writeOnly, &dummy)) { return nullptr; } + MOZ_ASSERT(dummy == 0); + int32_t picRectX = BitwiseCast(picRectX_); int32_t picRectY = BitwiseCast(picRectY_); int32_t picRectWidth = BitwiseCast(picRectWidth_); @@ -1512,7 +1525,7 @@ ImageBitmap::ReadStructuredClone(JSContext* aCx, { RefPtr img = CreateImageFromSurface(aClonedSurfaces[aIndex]); RefPtr imageBitmap = - new ImageBitmap(aParent, img, isPremultipliedAlpha_); + new ImageBitmap(aParent, img, !!writeOnly, isPremultipliedAlpha_); imageBitmap->mIsCroppingAreaOutSideOfSourceImage = isCroppingAreaOutSideOfSourceImage_; @@ -1547,6 +1560,7 @@ ImageBitmap::WriteStructuredClone(JSStructuredCloneWriter* aWriter, const uint32_t picRectHeight = BitwiseCast(aImageBitmap->mPictureRect.height); const uint32_t isPremultipliedAlpha = aImageBitmap->mIsPremultipliedAlpha ? 1 : 0; const uint32_t isCroppingAreaOutSideOfSourceImage = aImageBitmap->mIsCroppingAreaOutSideOfSourceImage ? 1 : 0; + const uint32_t isWriteOnly = aImageBitmap->mWriteOnly ? 1 : 0; // Indexing the cloned surfaces and send the index to the receiver. uint32_t index = aClonedSurfaces.Length(); @@ -1555,7 +1569,8 @@ ImageBitmap::WriteStructuredClone(JSStructuredCloneWriter* aWriter, NS_WARN_IF(!JS_WriteUint32Pair(aWriter, picRectX, picRectY)) || NS_WARN_IF(!JS_WriteUint32Pair(aWriter, picRectWidth, picRectHeight)) || NS_WARN_IF(!JS_WriteUint32Pair(aWriter, isPremultipliedAlpha, - isCroppingAreaOutSideOfSourceImage))) { + isCroppingAreaOutSideOfSourceImage)) || + NS_WARN_IF(!JS_WriteUint32Pair(aWriter, isWriteOnly, 0))) { return false; } diff --git a/dom/canvas/ImageBitmap.h b/dom/canvas/ImageBitmap.h index 2119c6bda..25084b6ac 100644 --- a/dom/canvas/ImageBitmap.h +++ b/dom/canvas/ImageBitmap.h @@ -65,6 +65,7 @@ struct ImageBitmapCloneData final gfx::IntRect mPictureRect; bool mIsPremultipliedAlpha; bool mIsCroppingAreaOutSideOfSourceImage; + bool mWriteOnly; }; /* @@ -161,6 +162,10 @@ public: template friend class MapDataIntoBufferSource; + bool IsWriteOnly() const { + return mWriteOnly; + } + // Mozilla Extensions ImageBitmapFormat FindOptimalFormat(const Optional>& aPossibleFormats, @@ -197,6 +202,7 @@ protected: * CreateInternal(from ImageData) method. */ ImageBitmap(nsIGlobalObject* aGlobal, layers::Image* aData, + bool aWriteOnly, bool aIsPremultipliedAlpha = true); virtual ~ImageBitmap(); @@ -280,6 +286,12 @@ protected: */ bool mIsCroppingAreaOutSideOfSourceImage; + /* + * Write-Only flag is set to true if this image has been generated from a + * cross-origin source. This is the opposite of what is called 'origin-clean' + * in the spec. + */ + bool mWriteOnly; }; } // namespace dom diff --git a/dom/canvas/ImageBitmapRenderingContext.cpp b/dom/canvas/ImageBitmapRenderingContext.cpp index 8f5074554..ad313906a 100644 --- a/dom/canvas/ImageBitmapRenderingContext.cpp +++ b/dom/canvas/ImageBitmapRenderingContext.cpp @@ -63,6 +63,11 @@ ImageBitmapRenderingContext::TransferFromImageBitmap(ImageBitmap& aImageBitmap) if (!mImage) { return; } + + // Check if ImageBitmap is tainted, and if so flag the canvas tainted too. + if (aImageBitmap.IsWriteOnly() && mCanvasElement) { + mCanvasElement->SetWriteOnly(); + } Redraw(gfxRect(0, 0, mWidth, mHeight)); } diff --git a/dom/canvas/WebGLContext.h b/dom/canvas/WebGLContext.h index 3ec307b00..8a20237ff 100644 --- a/dom/canvas/WebGLContext.h +++ b/dom/canvas/WebGLContext.h @@ -275,8 +275,9 @@ struct TexImageSourceAdapter final : public TexImageSource mPboOffset = pboOffset; } - TexImageSourceAdapter(const dom::ImageBitmap* imageBitmap, ErrorResult*) { + TexImageSourceAdapter(const dom::ImageBitmap* imageBitmap, ErrorResult* out_error) { mImageBitmap = imageBitmap; + mOut_error = out_error; } TexImageSourceAdapter(const dom::ImageData* imageData, ErrorResult*) { diff --git a/dom/canvas/WebGLTextureUpload.cpp b/dom/canvas/WebGLTextureUpload.cpp index 612d5889d..3839b5d5e 100644 --- a/dom/canvas/WebGLTextureUpload.cpp +++ b/dom/canvas/WebGLTextureUpload.cpp @@ -12,6 +12,7 @@ #include "GLBlitHelper.h" #include "GLContext.h" #include "mozilla/gfx/2D.h" +#include "mozilla/dom/HTMLCanvasElement.h" #include "mozilla/dom/HTMLVideoElement.h" #include "mozilla/dom/ImageBitmap.h" #include "mozilla/dom/ImageData.h" @@ -214,9 +215,18 @@ FromPboOffset(WebGLContext* webgl, const char* funcName, TexImageTarget target, static UniquePtr FromImageBitmap(WebGLContext* webgl, const char* funcName, TexImageTarget target, uint32_t width, uint32_t height, uint32_t depth, - const dom::ImageBitmap& imageBitmap) + const dom::ImageBitmap& imageBitmap, ErrorResult* aRv) { + if (imageBitmap.IsWriteOnly()) { + aRv->Throw(NS_ERROR_DOM_SECURITY_ERR); + return nullptr; + } + UniquePtr cloneData = Move(imageBitmap.ToCloneData()); + if (!cloneData) { + return nullptr; + } + const RefPtr surf = cloneData->mSurface; //// @@ -293,6 +303,14 @@ WebGLContext::FromDomElem(const char* funcName, TexImageTarget target, uint32_t uint32_t height, uint32_t depth, const dom::Element& elem, ErrorResult* const out_error) { + if (elem.IsHTMLElement(nsGkAtoms::canvas)) { + const dom::HTMLCanvasElement* canvas = static_cast(&elem); + if (canvas->IsWriteOnly()) { + out_error->Throw(NS_ERROR_DOM_SECURITY_ERR); + return nullptr; + } + } + uint32_t flags = nsLayoutUtils::SFE_WANT_IMAGE_SURFACE | nsLayoutUtils::SFE_USE_ELEMENT_SIZE_IF_VECTOR; @@ -412,7 +430,7 @@ WebGLContext::From(const char* funcName, TexImageTarget target, GLsizei rawWidth if (src.mImageBitmap) { return FromImageBitmap(this, funcName, target, width, height, depth, - *(src.mImageBitmap)); + *(src.mImageBitmap), src.mOut_error); } if (src.mImageData) { diff --git a/dom/canvas/test/test_imagebitmap.html b/dom/canvas/test/test_imagebitmap.html index b3d3c08ad..3b74970ac 100644 --- a/dom/canvas/test/test_imagebitmap.html +++ b/dom/canvas/test/test_imagebitmap.html @@ -270,13 +270,22 @@ function testSecurityErrors() { } function checkPromiseFailedWithSecurityError(p) { - return p.then( function(reason) { ok(false, "Did not get SecurityError with unclean source. ImageBitmap was created successfully."); }, - function(reason) { if (reason == "SecurityError: The operation is insecure.") { - ok(true, reason); - } - else { - ok(false, "Did not get SecurityError with unclean source. Error Message: " + reason); - }}); + return p.then(imageBitmap => { + ok(!!imageBitmap, "ImageBitmaps are always created"); + const context = document.createElement("canvas").getContext("2d"); + context.drawImage(imageBitmap, 0, 0); + try { + context.getImageData(0, 0, 1, 1); + ok(false, "Did not get SecurityError with unclean source. ImageBitmap was created successfully."); + } catch (ex) { + if (ex == "SecurityError: The operation is insecure.") { + ok(true, ex); + } + else { + ok(false, "Did not get SecurityError with unclean source. Error Message: " + ex); + } + } + }); } return Promise.all([ diff --git a/dom/html/HTMLCanvasElement.cpp b/dom/html/HTMLCanvasElement.cpp index 527135a80..a01795d9e 100644 --- a/dom/html/HTMLCanvasElement.cpp +++ b/dom/html/HTMLCanvasElement.cpp @@ -1000,7 +1000,7 @@ HTMLCanvasElement::GetSize() } bool -HTMLCanvasElement::IsWriteOnly() +HTMLCanvasElement::IsWriteOnly() const { return mWriteOnly; } diff --git a/dom/html/HTMLCanvasElement.h b/dom/html/HTMLCanvasElement.h index 746fab198..e77db6ff1 100644 --- a/dom/html/HTMLCanvasElement.h +++ b/dom/html/HTMLCanvasElement.h @@ -224,9 +224,9 @@ public: nsIntSize GetSize(); /** - * Determine whether the canvas is write-only. + * Determine whether the canvas is write-only (tainted). */ - bool IsWriteOnly(); + bool IsWriteOnly() const; /** * Force the canvas to be write-only. -- cgit v1.2.3 From b1e78d1db168584a9fbef8f30cb76ca826323b4f Mon Sep 17 00:00:00 2001 From: JustOff Date: Tue, 19 Feb 2019 21:15:35 +0200 Subject: Preserve newlines in textarea placeholders --- dom/html/nsTextEditorState.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'dom') diff --git a/dom/html/nsTextEditorState.cpp b/dom/html/nsTextEditorState.cpp index 0b4cb1920..25be6016c 100644 --- a/dom/html/nsTextEditorState.cpp +++ b/dom/html/nsTextEditorState.cpp @@ -2255,7 +2255,11 @@ nsTextEditorState::UpdatePlaceholderText(bool aNotify) nsCOMPtr content = do_QueryInterface(mTextCtrlElement); content->GetAttr(kNameSpaceID_None, nsGkAtoms::placeholder, placeholderValue); - nsContentUtils::RemoveNewlines(placeholderValue); + if (mTextCtrlElement->IsTextArea()) { //