Bug 1471165 - P1. Simulate required MediaCapabilities members in optional dictionary. r=bz

Summary:
In order to allow for optional dictionaries with required members
See https://github.com/heycam/webidl/issues/76 for more information.

Reviewers: bzbarsky

Tags: #secure-revision

Bug #: 1471165

Differential Revision: https://phabricator.services.mozilla.com/D1833
This commit is contained in:
Jean-Yves Avenard 2018-06-29 17:15:00 +02:00
Родитель cab83f1874
Коммит 138b0b299d
3 изменённых файлов: 128 добавлений и 28 удалений

Просмотреть файл

@ -262,10 +262,16 @@ MakeMediaExtendedMIMEType(const nsAString& aType)
Maybe<MediaExtendedMIMEType> Maybe<MediaExtendedMIMEType>
MakeMediaExtendedMIMEType(const dom::VideoConfiguration& aConfig) MakeMediaExtendedMIMEType(const dom::VideoConfiguration& aConfig)
{ {
if (aConfig.mContentType.IsEmpty()) { MOZ_ASSERT(aConfig.mContentType.WasPassed() &&
aConfig.mFramerate.WasPassed() &&
aConfig.mWidth.WasPassed() &&
aConfig.mHeight.WasPassed() &&
aConfig.mBitrate.WasPassed(),
"All dictionary members must be present");
if (aConfig.mContentType.Value().IsEmpty()) {
return Nothing(); return Nothing();
} }
nsContentTypeParser parser(aConfig.mContentType); nsContentTypeParser parser(aConfig.mContentType.Value());
nsAutoString mime; nsAutoString mime;
nsresult rv = parser.GetType(mime); nsresult rv = parser.GetType(mime);
if (!NS_SUCCEEDED(rv) || mime.IsEmpty()) { if (!NS_SUCCEEDED(rv) || mime.IsEmpty()) {
@ -282,28 +288,30 @@ MakeMediaExtendedMIMEType(const dom::VideoConfiguration& aConfig)
bool haveCodecs = NS_SUCCEEDED(rv); bool haveCodecs = NS_SUCCEEDED(rv);
auto framerate = auto framerate =
MediaExtendedMIMEType::ComputeFractionalString(aConfig.mFramerate); MediaExtendedMIMEType::ComputeFractionalString(aConfig.mFramerate.Value());
if (!framerate) { if (!framerate) {
return Nothing(); return Nothing();
} }
return Some(MediaExtendedMIMEType(NS_ConvertUTF16toUTF8(aConfig.mContentType), return Some(
mime8, MediaExtendedMIMEType(NS_ConvertUTF16toUTF8(aConfig.mContentType.Value()),
haveCodecs, mime8,
codecs, haveCodecs,
aConfig.mWidth, codecs,
aConfig.mHeight, aConfig.mWidth.Value(),
framerate.ref(), aConfig.mHeight.Value(),
aConfig.mBitrate)); framerate.ref(),
aConfig.mBitrate.Value()));
} }
Maybe<MediaExtendedMIMEType> Maybe<MediaExtendedMIMEType>
MakeMediaExtendedMIMEType(const dom::AudioConfiguration& aConfig) MakeMediaExtendedMIMEType(const dom::AudioConfiguration& aConfig)
{ {
if (aConfig.mContentType.IsEmpty()) { if (!aConfig.mContentType.WasPassed() ||
aConfig.mContentType.Value().IsEmpty()) {
return Nothing(); return Nothing();
} }
nsContentTypeParser parser(aConfig.mContentType); nsContentTypeParser parser(aConfig.mContentType.Value());
nsAutoString mime; nsAutoString mime;
nsresult rv = parser.GetType(mime); nsresult rv = parser.GetType(mime);
if (!NS_SUCCEEDED(rv) || mime.IsEmpty()) { if (!NS_SUCCEEDED(rv) || mime.IsEmpty()) {
@ -335,7 +343,7 @@ MakeMediaExtendedMIMEType(const dom::AudioConfiguration& aConfig)
} }
return Some(MediaExtendedMIMEType( return Some(MediaExtendedMIMEType(
NS_ConvertUTF16toUTF8(aConfig.mContentType), NS_ConvertUTF16toUTF8(aConfig.mContentType.Value()),
mime8, mime8,
haveCodecs, haveCodecs,
codecs, codecs,

Просмотреть файл

@ -32,6 +32,54 @@ MediaCapabilities::MediaCapabilities(nsIGlobalObject* aParent)
{ {
} }
static void
ThrowWithMemberName(ErrorResult& aRv,
const char* aCategory,
const char* aMember)
{
auto str = nsPrintfCString("'%s' member of %s", aMember, aCategory);
aRv.ThrowTypeError<MSG_MISSING_REQUIRED_DICTIONARY_MEMBER>(
NS_ConvertUTF8toUTF16(str));
}
static void
CheckVideoConfigurationSanity(const VideoConfiguration& aConfig,
const char* aCategory,
ErrorResult& aRv)
{
if (!aConfig.mContentType.WasPassed()) {
ThrowWithMemberName(aRv, "contentType", aCategory);
return;
}
if (!aConfig.mWidth.WasPassed()) {
ThrowWithMemberName(aRv, "width", aCategory);
return;
}
if (!aConfig.mHeight.WasPassed()) {
ThrowWithMemberName(aRv, "height", aCategory);
return;
}
if (!aConfig.mBitrate.WasPassed()) {
ThrowWithMemberName(aRv, "bitrate", aCategory);
return;
}
if (!aConfig.mFramerate.WasPassed()) {
ThrowWithMemberName(aRv, "framerate", aCategory);
return;
}
}
static void
CheckAudioConfigurationSanity(const AudioConfiguration& aConfig,
const char* aCategory,
ErrorResult& aRv)
{
if (!aConfig.mContentType.WasPassed()) {
ThrowWithMemberName(aRv, "contentType", aCategory);
return;
}
}
already_AddRefed<Promise> already_AddRefed<Promise>
MediaCapabilities::DecodingInfo( MediaCapabilities::DecodingInfo(
const MediaDecodingConfiguration& aConfiguration, const MediaDecodingConfiguration& aConfiguration,
@ -52,6 +100,25 @@ MediaCapabilities::DecodingInfo(
return nullptr; return nullptr;
} }
// Here we will throw rather than rejecting a promise in order to simulate
// optional dictionaries with required members (see bug 1368949)
if (aConfiguration.mVideo.IsAnyMemberPresent()) {
// Check that all VideoConfiguration required members are present.
CheckVideoConfigurationSanity(
aConfiguration.mVideo, "MediaDecodingConfiguration", aRv);
if (aRv.Failed()) {
return nullptr;
}
}
if (aConfiguration.mAudio.IsAnyMemberPresent()) {
// Check that all AudioConfiguration required members are present.
CheckAudioConfigurationSanity(
aConfiguration.mAudio, "MediaDecodingConfiguration", aRv);
if (aRv.Failed()) {
return nullptr;
}
}
bool supported = true; bool supported = true;
Maybe<MediaContainerType> videoContainer; Maybe<MediaContainerType> videoContainer;
Maybe<MediaContainerType> audioContainer; Maybe<MediaContainerType> audioContainer;
@ -68,8 +135,8 @@ MediaCapabilities::DecodingInfo(
// We have a video configuration and it is valid. Check if it is supported. // We have a video configuration and it is valid. Check if it is supported.
supported &= supported &=
aConfiguration.mType == MediaDecodingType::File aConfiguration.mType == MediaDecodingType::File
? CheckTypeForFile(aConfiguration.mVideo.mContentType) ? CheckTypeForFile(aConfiguration.mVideo.mContentType.Value())
: CheckTypeForMediaSource(aConfiguration.mVideo.mContentType); : CheckTypeForMediaSource(aConfiguration.mVideo.mContentType.Value());
} }
if (aConfiguration.mAudio.IsAnyMemberPresent()) { if (aConfiguration.mAudio.IsAnyMemberPresent()) {
audioContainer = CheckAudioConfiguration(aConfiguration.mAudio); audioContainer = CheckAudioConfiguration(aConfiguration.mAudio);
@ -80,8 +147,8 @@ MediaCapabilities::DecodingInfo(
// We have an audio configuration and it is valid. Check if it is supported. // We have an audio configuration and it is valid. Check if it is supported.
supported &= supported &=
aConfiguration.mType == MediaDecodingType::File aConfiguration.mType == MediaDecodingType::File
? CheckTypeForFile(aConfiguration.mAudio.mContentType) ? CheckTypeForFile(aConfiguration.mAudio.mContentType.Value())
: CheckTypeForMediaSource(aConfiguration.mAudio.mContentType); : CheckTypeForMediaSource(aConfiguration.mAudio.mContentType.Value());
} }
if (!supported) { if (!supported) {
@ -323,6 +390,25 @@ MediaCapabilities::EncodingInfo(
return nullptr; return nullptr;
} }
// Here we will throw rather than rejecting a promise in order to simulate
// optional dictionaries with required members (see bug 1368949)
if (aConfiguration.mVideo.IsAnyMemberPresent()) {
// Check that all VideoConfiguration required members are present.
CheckVideoConfigurationSanity(
aConfiguration.mVideo, "MediaDecodingConfiguration", aRv);
if (aRv.Failed()) {
return nullptr;
}
}
if (aConfiguration.mAudio.IsAnyMemberPresent()) {
// Check that all AudioConfiguration required members are present.
CheckAudioConfigurationSanity(
aConfiguration.mAudio, "MediaDecodingConfiguration", aRv);
if (aRv.Failed()) {
return nullptr;
}
}
bool supported = true; bool supported = true;
// If configuration.video is present and is not a valid video configuration, // If configuration.video is present and is not a valid video configuration,
@ -333,7 +419,8 @@ MediaCapabilities::EncodingInfo(
return nullptr; return nullptr;
} }
// We have a video configuration and it is valid. Check if it is supported. // We have a video configuration and it is valid. Check if it is supported.
supported &= CheckTypeForEncoder(aConfiguration.mVideo.mContentType); supported &=
CheckTypeForEncoder(aConfiguration.mVideo.mContentType.Value());
} }
if (aConfiguration.mAudio.IsAnyMemberPresent()) { if (aConfiguration.mAudio.IsAnyMemberPresent()) {
if (!CheckAudioConfiguration(aConfiguration.mAudio)) { if (!CheckAudioConfiguration(aConfiguration.mAudio)) {
@ -341,7 +428,8 @@ MediaCapabilities::EncodingInfo(
return nullptr; return nullptr;
} }
// We have an audio configuration and it is valid. Check if it is supported. // We have an audio configuration and it is valid. Check if it is supported.
supported &= CheckTypeForEncoder(aConfiguration.mAudio.mContentType); supported &=
CheckTypeForEncoder(aConfiguration.mAudio.mContentType.Value());
} }
auto info = MakeUnique<MediaCapabilitiesInfo>(supported, supported, false); auto info = MakeUnique<MediaCapabilitiesInfo>(supported, supported, false);

Просмотреть файл

@ -32,16 +32,22 @@ enum MediaEncodingType {
"transmission" "transmission"
}; };
// all members are specified as required in the spec.
// We enforce that requirement in the MediaCapabilities code instead
// See https://github.com/heycam/webidl/issues/76
dictionary VideoConfiguration { dictionary VideoConfiguration {
required DOMString contentType; DOMString contentType;
required unsigned long width; unsigned long width;
required unsigned long height; unsigned long height;
required unsigned long long bitrate; unsigned long long bitrate;
required DOMString framerate; DOMString framerate;
}; };
// contentType member is specified as required in the spec.
// We enforce that requirement in the MediaCapabilities code instead
// See https://github.com/heycam/webidl/issues/76
dictionary AudioConfiguration { dictionary AudioConfiguration {
required DOMString contentType; DOMString contentType;
DOMString channels; DOMString channels;
unsigned long long bitrate; unsigned long long bitrate;
unsigned long samplerate; unsigned long samplerate;
@ -57,8 +63,6 @@ interface MediaCapabilitiesInfo {
[Exposed=(Window, Worker), Func="mozilla::dom::MediaCapabilities::Enabled"] [Exposed=(Window, Worker), Func="mozilla::dom::MediaCapabilities::Enabled"]
interface MediaCapabilities { interface MediaCapabilities {
// As per https://github.com/WICG/media-capabilities/issues/91 we mark the
// methods as always returning a new object.
[NewObject] [NewObject]
Promise<MediaCapabilitiesInfo> decodingInfo(MediaDecodingConfiguration configuration); Promise<MediaCapabilitiesInfo> decodingInfo(MediaDecodingConfiguration configuration);
[NewObject] [NewObject]