author | Chris Pearce <cpearce@mozilla.com> |
Tue, 28 Oct 2014 13:21:12 +1300 | |
changeset 213053 | 971beced9390898a5cad30a5b963d4565435f1f6 |
parent 213052 | 396575d789e430d815fd2ab1126c165db19d2629 |
child 213054 | 8839a3db64216f6ee1853649ee47d1c53a4d4a77 |
push id | 27738 |
push user | cbook@mozilla.com |
push date | Thu, 30 Oct 2014 13:46:07 +0000 |
treeherder | mozilla-central@1aa1b23d799e [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | roc |
bugs | 1071482 |
milestone | 36.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/dom/html/HTMLMediaElement.cpp +++ b/dom/html/HTMLMediaElement.cpp @@ -1782,17 +1782,21 @@ NS_IMETHODIMP HTMLMediaElement::SetMuted already_AddRefed<DOMMediaStream> HTMLMediaElement::CaptureStreamInternal(bool aFinishWhenEnded) { nsIDOMWindow* window = OwnerDoc()->GetInnerWindow(); if (!window) { return nullptr; } - +#ifdef MOZ_EME + if (ContainsRestrictedContent()) { + return nullptr; + } +#endif OutputMediaStream* out = mOutputStreams.AppendElement(); #ifdef DEBUG // Estimate hints based on the type of the media element // under the preference media.capturestream_hints for the // debug builds only. This allows WebRTC Peer Connection // to behave appropriately when media streams generated // via mozCaptureStream*() are added to the Peer Connection. // This functionality is planned to be used as part of Audio @@ -3987,20 +3991,31 @@ NS_IMETHODIMP HTMLMediaElement::CanPlayC #ifdef MOZ_EME MediaKeys* HTMLMediaElement::GetMediaKeys() const { return mMediaKeys; } +bool +HTMLMediaElement::ContainsRestrictedContent() +{ + return GetMediaKeys() != nullptr; +} + already_AddRefed<Promise> HTMLMediaElement::SetMediaKeys(mozilla::dom::MediaKeys* aMediaKeys, ErrorResult& aRv) { + if (MozAudioCaptured()) { + aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); + return nullptr; + } + nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(OwnerDoc()->GetInnerWindow()); if (!global) { aRv.Throw(NS_ERROR_UNEXPECTED); return nullptr; } nsRefPtr<Promise> promise = Promise::Create(global, aRv); if (aRv.Failed()) { @@ -4025,16 +4040,18 @@ HTMLMediaElement::SetMediaKeys(mozilla:: if (NS_FAILED(mMediaKeys->Bind(this))) { promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR); mMediaKeys = nullptr; return promise.forget(); } if (mDecoder) { mDecoder->SetCDMProxy(mMediaKeys->GetCDMProxy()); } + // Update the same-origin status. + NotifyDecoderPrincipalChanged(); } promise->MaybeResolve(JS::UndefinedHandleValue); return promise.forget(); } MediaWaitingFor HTMLMediaElement::WaitingFor() const {
--- a/dom/html/HTMLMediaElement.h +++ b/dom/html/HTMLMediaElement.h @@ -545,16 +545,17 @@ public: bool IsEventAttributeName(nsIAtom* aName) MOZ_OVERRIDE; // Returns the principal of the "top level" document; the origin displayed // in the URL bar of the browser window. already_AddRefed<nsIPrincipal> GetTopLevelPrincipal(); + bool ContainsRestrictedContent(); #endif // MOZ_EME bool MozAutoplayEnabled() const { return mAutoplayEnabled; } already_AddRefed<DOMMediaStream> MozCaptureStream(ErrorResult& aRv);
--- a/dom/media/test/eme.js +++ b/dom/media/test/eme.js @@ -145,16 +145,20 @@ function LoadTest(test, elem) resolve(); }); } function SetupEME(test, token, params) { var v = document.createElement("video"); + var onSetKeysFail = (params && params.onSetKeysFail) + ? params.onSetKeysFail + : bail(token + " Failed to set MediaKeys on <video> element"); + v.addEventListener("encrypted", function(ev) { info(token + " got encrypted event"); MediaKeys.create(KEYSYSTEM_TYPE).then(function(mediaKeys) { info(token + " created MediaKeys object ok"); mediaKeys.sessions = []; return v.setMediaKeys(mediaKeys); }, bail("failed to create MediaKeys object")).then(function() { info(token + " set MediaKeys on <video> element ok"); @@ -162,13 +166,13 @@ function SetupEME(test, token, params) var session = v.mediaKeys.createSession(test.sessionType); if (params && params.onsessioncreated) { params.onsessioncreated(session); } session.addEventListener("message", UpdateSessionFunc(test)); session.generateRequest(ev.initDataType, ev.initData).then(function() { }, bail(token + " Failed to initialise MediaKeySession")); - }, bail(token + " Failed to set MediaKeys on <video> element")); + }, onSetKeysFail); }); return v; }
--- a/dom/media/test/mochitest.ini +++ b/dom/media/test/mochitest.ini @@ -356,18 +356,22 @@ skip-if = (toolkit == 'android' && proce [test_contentDuration7.html] [test_controls.html] [test_currentTime.html] [test_decode_error.html] [test_decoder_disable.html] [test_defaultMuted.html] [test_delay_load.html] skip-if = buildapp == 'b2g' && toolkit != 'gonk' # bug 1082984 +[test_eme_canvas_blocked.html] +skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # bug 1043403, bug 1057908 [test_eme_playback.html] skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # bug 1043403, bug 1057908 +[test_eme_stream_capture_blocked.html] +skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # bug 1043403, bug 1057908 [test_error_in_video_document.html] skip-if = toolkit == 'android' || (os == 'win' && !debug) || (os == 'mac' && !debug) # bug 608634 [test_error_on_404.html] [test_fastSeek.html] skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439 [test_fastSeek-forwards.html] [test_imagecapture.html] [test_info_leak.html]
new file mode 100644 --- /dev/null +++ b/dom/media/test/test_eme_canvas_blocked.html @@ -0,0 +1,67 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test Encrypted Media Extensions</title> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> + <script type="text/javascript" src="manifest.js"></script> + <script type="text/javascript" src="eme.js"></script> +</head> +<body> +<pre id="test"> +<script class="testbody" type="text/javascript"> +var manager = new MediaTestManager; + +function startTest(test, token) +{ + manager.started(token); + + var sessions = []; + + var v = SetupEME(test, token); + v.preload = "auto"; // Required due to "canplay" not firing for MSE unless we do this. + + v.addEventListener("canplay", function(ev) { + var video = ev.target; + var canvas = document.createElement("canvas"); + canvas.width = video.videoWidth; + canvas.height = video.videoHeight; + document.body.appendChild(canvas); + var ctx = canvas.getContext("2d"); + var threwError = false; + try { + ctx.drawImage(video, 0, 0); + } catch (ex) { + threwError = true; + } + ok(threwError, token + " - Should throw an error when trying to draw EME video to canvas."); + manager.finished(token); + }); + + v.addEventListener("error", bail(token + " got error event")); + + LoadTest(test, v); +} + +function beginTest() { + manager.runTests(gEMETests, startTest); +} + +var prefs = [ + [ "media.mediasource.enabled", true ], + [ "media.mediasource.ignore_codecs", true ], +]; + +if (/Linux/.test(navigator.userAgent) || + !document.createElement('video').canPlayType("video/mp4")) { + // XXX remove once we have mp4 PlatformDecoderModules on all platforms. + prefs.push([ "media.fragmented-mp4.exposed", true ]); + prefs.push([ "media.fragmented-mp4.use-blank-decoder", true ]); +} + +SimpleTest.waitForExplicitFinish(); +SpecialPowers.pushPrefEnv({ "set" : prefs }, beginTest); +</script> +</pre> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/dom/media/test/test_eme_stream_capture_blocked.html @@ -0,0 +1,102 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test Encrypted Media Extensions</title> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> + <script type="text/javascript" src="manifest.js"></script> + <script type="text/javascript" src="eme.js"></script> +</head> +<body> +<pre id="test"> +<script class="testbody" type="text/javascript"> +var manager = new MediaTestManager; + +function startTest(test, token) +{ + // Three cases: + // 1. setting MediaKeys on an element captured by MediaElementSource should fail, and + // 2. creating a MediaElementSource on a media element with a MediaKeys should fail, and + // 3. capturing a media element with mozCaptureStream that has a MediaKeys should fail. + + // Case 1. setting MediaKeys on an element captured by MediaElementSource should fail. + var case1token = token + "_case1"; + var setKeysFailed = function() { + ok(true, case1token + " setMediaKeys failed as expected."); + manager.finished(case1token); + }; + var v1 = SetupEME(test, case1token, { onSetKeysFail: setKeysFailed }); + var context = new AudioContext(); + var node = context.createMediaElementSource(v1); + v1.preload = "auto"; // Required due to "canplay" not firing for MSE unless we do this. + v1.addEventListener("error", bail(case1token + " got error event")); + v1.addEventListener("canplay", function(ev) { + ok(false, case1token + " should never reach canplay, as setMediaKeys should fail"); + }); + manager.started(case1token); + LoadTest(test, v1); + + + // Case 2. creating a MediaElementSource on a media element with a MediaKeys should fail. + var case2token = token + "_case2"; + var v2 = SetupEME(test, case2token); + v2.preload = "auto"; // Required due to "canplay" not firing for MSE unless we do this. + v2.addEventListener("error", bail(case2token + " got error event")); + v2.addEventListener("canplay", function(ev) { + ok(true, case2token + " should reach canplay"); + var threw = false; + try { + var context = new AudioContext(); + var node = context.createMediaElementSource(v2); + } catch (e) { + threw = true; + } + ok(threw, "Should throw an error creating a MediaElementSource on an EME video."); + manager.finished(case2token); + }); + manager.started(case2token); + LoadTest(test, v2); + + + // Case 3. capturing a media element with mozCaptureStream that has a MediaKeys should fail. + var case3token = token + "_case3"; + var v3 = SetupEME(test, case3token); + v3.preload = "auto"; // Required due to "canplay" not firing for MSE unless we do this. + v3.addEventListener("error", bail(case3token + " got error event")); + v3.addEventListener("canplay", function(ev) { + ok(true, case3token + " should reach canplay"); + var threw = false; + try { + var stream = v3.mozCaptureStreamUntilEnded(); + } catch (e) { + threw = true; + } + ok(threw, "Should throw an error calling mozCaptureStreamUntilEnded an EME video."); + manager.finished(case3token); + }); + manager.started(case3token); + LoadTest(test, v3); +} + +function beginTest() { + manager.runTests(gEMETests, startTest); +} + +var prefs = [ + [ "media.mediasource.enabled", true ], + [ "media.mediasource.ignore_codecs", true ], +]; + +if (/Linux/.test(navigator.userAgent) || + !document.createElement('video').canPlayType("video/mp4")) { + // XXX remove once we have mp4 PlatformDecoderModules on all platforms. + prefs.push([ "media.fragmented-mp4.exposed", true ]); + prefs.push([ "media.fragmented-mp4.use-blank-decoder", true ]); +} + +SimpleTest.waitForExplicitFinish(); +SpecialPowers.pushPrefEnv({ "set" : prefs }, beginTest); +</script> +</pre> +</body> +</html>
--- a/dom/media/webaudio/AudioContext.cpp +++ b/dom/media/webaudio/AudioContext.cpp @@ -280,16 +280,22 @@ AudioContext::CreateAnalyser() already_AddRefed<MediaElementAudioSourceNode> AudioContext::CreateMediaElementSource(HTMLMediaElement& aMediaElement, ErrorResult& aRv) { if (mIsOffline) { aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); return nullptr; } +#ifdef MOZ_EME + if (aMediaElement.ContainsRestrictedContent()) { + aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); + return nullptr; + } +#endif nsRefPtr<DOMMediaStream> stream = aMediaElement.MozCaptureStream(aRv); if (aRv.Failed()) { return nullptr; } nsRefPtr<MediaElementAudioSourceNode> mediaElementAudioSourceNode = new MediaElementAudioSourceNode(this, stream); return mediaElementAudioSourceNode.forget(); }
--- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -6102,16 +6102,22 @@ nsLayoutUtils::SurfaceFromElementResult nsLayoutUtils::SurfaceFromElement(HTMLVideoElement* aElement, uint32_t aSurfaceFlags, DrawTarget* aTarget) { SurfaceFromElementResult result; NS_WARN_IF_FALSE((aSurfaceFlags & SFE_PREFER_NO_PREMULTIPLY_ALPHA) == 0, "We can't support non-premultiplied alpha for video!"); +#ifdef MOZ_EME + if (aElement->ContainsRestrictedContent()) { + return result; + } +#endif + uint16_t readyState; if (NS_SUCCEEDED(aElement->GetReadyState(&readyState)) && (readyState == nsIDOMHTMLMediaElement::HAVE_NOTHING || readyState == nsIDOMHTMLMediaElement::HAVE_METADATA)) { result.mIsStillLoading = true; return result; }