WebKit Bugzilla
Attachment 370114 Details for
Bug 197959
: Allow sequential playback of media files when initial playback started with a user gesture
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-197959-20190517064840.patch (text/plain), 20.92 KB, created by
Eric Carlson
on 2019-05-17 06:48:41 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Eric Carlson
Created:
2019-05-17 06:48:41 PDT
Size:
20.92 KB
patch
obsolete
>Subversion Revision: 245235 >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index 0702237834a7edb1da138c7d8322d90ae5c4130e..b7898cbbb172206715ed6b22d66ee1a998ac899f 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,48 @@ >+2019-05-16 Eric Carlson <eric.carlson@apple.com> >+ >+ Allow sequential playback of media files when initial playback started with a user gesture >+ https://bugs.webkit.org/show_bug.cgi?id=197959 >+ <rdar://problem/50655207> >+ >+ Reviewed by Youenn Fablet. >+ >+ Test: media/playlist-inherits-user-gesture.html >+ >+ * dom/Document.cpp: >+ (WebCore::Document::processingUserGestureForMedia const): Return true if it is within >+ one second of the last HTMLMediaElement 'ended' event. >+ * dom/Document.h: >+ (WebCore::Document::mediaFinishedPlaying): >+ >+ * html/HTMLMediaElement.cpp: >+ (WebCore::HTMLMediaElement::parseAttribute): removeBehaviorsRestrictionsAfterFirstUserGesture -> >+ removeBehaviorRestrictionsAfterFirstUserGesture. >+ (WebCore::HTMLMediaElement::load): Ditto. Don't call removeBehaviorsRestrictionsAfterFirstUserGesture, >+ it will be done in prepareForLoad. >+ (WebCore::HTMLMediaElement::prepareForLoad): removeBehaviorsRestrictionsAfterFirstUserGesture -> >+ removeBehaviorRestrictionsAfterFirstUserGesture. >+ (WebCore::HTMLMediaElement::audioTrackEnabledChanged): Ditto. >+ (WebCore::HTMLMediaElement::play): Ditto. >+ (WebCore::HTMLMediaElement::pause): Ditto. >+ (WebCore::HTMLMediaElement::setVolume): Ditto. >+ (WebCore::HTMLMediaElement::setMuted): Ditto. >+ (WebCore::HTMLMediaElement::webkitShowPlaybackTargetPicker): Ditto. >+ (WebCore::HTMLMediaElement::dispatchEvent): Call document().mediaFinishedPlaying() >+ when dispatching the 'ended' event. >+ (WebCore::HTMLMediaElement::removeBehaviorRestrictionsAfterFirstUserGesture): Rename. Set >+ m_removedBehaviorRestrictionsAfterFirstUserGesture. >+ (WebCore::HTMLMediaElement::removeBehaviorsRestrictionsAfterFirstUserGesture): Deleted. >+ * html/HTMLMediaElement.h: >+ >+ * html/HTMLVideoElement.cpp: >+ (WebCore:HTMLVideoElement::nativeImageForCurrentTime): Convert to runtime logging. >+ (WebCore:HTMLVideoElement::webkitEnterFullscreen): Ditto. >+ (WebCore:HTMLVideoElement::webkitSetPresentationMode): Ditto. >+ (WebCore:HTMLVideoElement::fullscreenModeChanged): Ditto. >+ >+ * html/MediaElementSession.cpp: >+ (WebCore::MediaElementSession::removeBehaviorRestriction): Update log message. >+ > 2019-05-13 Darin Adler <darin@apple.com> > > WHLSLPrepare.cpp always recompiles, even if nothing was changed >diff --git a/Source/WebCore/dom/Document.cpp b/Source/WebCore/dom/Document.cpp >index a2fbd8fdc8a6cec210aee04cbafb9eca45e80f49..a729754b742c5d12f00dba5bdd6ab1946987b92b 100644 >--- a/Source/WebCore/dom/Document.cpp >+++ b/Source/WebCore/dom/Document.cpp >@@ -328,6 +328,7 @@ using namespace WTF::Unicode; > > static const unsigned cMaxWriteRecursionDepth = 21; > bool Document::hasEverCreatedAnAXObjectCache = false; >+static const Seconds maxIntervalForUserGestureForwardingAfterMediaFinishesPlaying { 1_s }; > > // DOM Level 2 says (letters added): > // >@@ -6576,6 +6577,9 @@ bool Document::processingUserGestureForMedia() const > if (UserGestureIndicator::processingUserGestureForMedia()) > return true; > >+ if (m_userActivatedMediaFinishedPlayingTimestamp + maxIntervalForUserGestureForwardingAfterMediaFinishesPlaying >= MonotonicTime::now()) >+ return true; >+ > if (settings().mediaUserGestureInheritsFromDocument()) > return topDocument().hasHadUserInteraction(); > >diff --git a/Source/WebCore/dom/Document.h b/Source/WebCore/dom/Document.h >index 135ef0b6cd8ce5515ce471eac2023ffa8e48757b..37e11b856980d42689aad271afa5e52de574affe 100644 >--- a/Source/WebCore/dom/Document.h >+++ b/Source/WebCore/dom/Document.h >@@ -1220,6 +1220,7 @@ public: > bool hasHadUserInteraction() const { return static_cast<bool>(m_lastHandledUserGestureTimestamp); } > void updateLastHandledUserGestureTimestamp(MonotonicTime); > bool processingUserGestureForMedia() const; >+ void userActivatedMediaFinishedPlaying() { m_userActivatedMediaFinishedPlayingTimestamp = MonotonicTime::now(); } > > void setUserDidInteractWithPage(bool userDidInteractWithPage) { ASSERT(&topDocument() == this); m_userDidInteractWithPage = userDidInteractWithPage; } > bool userDidInteractWithPage() const { ASSERT(&topDocument() == this); return m_userDidInteractWithPage; } >@@ -1834,6 +1835,7 @@ private: > std::unique_ptr<EventTargetSet> m_wheelEventTargets; > > MonotonicTime m_lastHandledUserGestureTimestamp; >+ MonotonicTime m_userActivatedMediaFinishedPlayingTimestamp; > > void clearScriptedAnimationController(); > RefPtr<ScriptedAnimationController> m_scriptedAnimationController; >diff --git a/Source/WebCore/html/HTMLMediaElement.cpp b/Source/WebCore/html/HTMLMediaElement.cpp >index 6d87bddeeaa33eafbd75ffe67c8e759ceb3852cf..216e937236d980cfa08e49285ecb30779c44aedf 100644 >--- a/Source/WebCore/html/HTMLMediaElement.cpp >+++ b/Source/WebCore/html/HTMLMediaElement.cpp >@@ -839,7 +839,7 @@ void HTMLMediaElement::parseAttribute(const QualifiedName& name, const AtomicStr > setMediaGroup(value); > else if (name == autoplayAttr) { > if (processingUserGestureForMedia()) >- removeBehaviorsRestrictionsAfterFirstUserGesture(); >+ removeBehaviorRestrictionsAfterFirstUserGesture(); > } else if (name == titleAttr) { > if (m_mediaSession) > m_mediaSession->clientCharacteristicsChanged(); >@@ -1178,9 +1178,6 @@ void HTMLMediaElement::load() > > INFO_LOG(LOGIDENTIFIER); > >- if (processingUserGestureForMedia()) >- removeBehaviorsRestrictionsAfterFirstUserGesture(); >- > prepareForLoad(); > m_resourceSelectionTaskQueue.enqueueTask([this] { > prepareToPlay(); >@@ -1193,7 +1190,10 @@ void HTMLMediaElement::prepareForLoad() > // The Media Element Load Algorithm > // 12 February 2017 > >- INFO_LOG(LOGIDENTIFIER); >+ ALWAYS_LOG(LOGIDENTIFIER, "gesture = ", processingUserGestureForMedia()); >+ >+ if (processingUserGestureForMedia()) >+ removeBehaviorRestrictionsAfterFirstUserGesture(); > > // 1 - Abort any already-running instance of the resource selection algorithm for this element. > // Perform the cleanup required for the resource load algorithm to run. >@@ -1951,7 +1951,7 @@ void HTMLMediaElement::audioTrackEnabledChanged(AudioTrack& track) > if (m_audioTracks && m_audioTracks->contains(track)) > m_audioTracks->scheduleChangeEvent(); > if (processingUserGestureForMedia()) >- removeBehaviorsRestrictionsAfterFirstUserGesture(MediaElementSession::AllRestrictions & ~MediaElementSession::RequireUserGestureToControlControlsManager); >+ removeBehaviorRestrictionsAfterFirstUserGesture(MediaElementSession::AllRestrictions & ~MediaElementSession::RequireUserGestureToControlControlsManager); > } > > void HTMLMediaElement::textTrackModeChanged(TextTrack& track) >@@ -3515,7 +3515,7 @@ void HTMLMediaElement::play(DOMPromiseDeferred<void>&& promise) > } > > if (processingUserGestureForMedia()) >- removeBehaviorsRestrictionsAfterFirstUserGesture(); >+ removeBehaviorRestrictionsAfterFirstUserGesture(); > > m_pendingPlayPromises.append(WTFMove(promise)); > playInternal(); >@@ -3532,7 +3532,7 @@ void HTMLMediaElement::play() > return; > } > if (processingUserGestureForMedia()) >- removeBehaviorsRestrictionsAfterFirstUserGesture(); >+ removeBehaviorRestrictionsAfterFirstUserGesture(); > > playInternal(); > } >@@ -3633,7 +3633,7 @@ void HTMLMediaElement::pause() > return; > > if (processingUserGestureForMedia()) >- removeBehaviorsRestrictionsAfterFirstUserGesture(MediaElementSession::RequireUserGestureToControlControlsManager); >+ removeBehaviorRestrictionsAfterFirstUserGesture(MediaElementSession::RequireUserGestureToControlControlsManager); > > pauseInternal(); > } >@@ -3744,7 +3744,7 @@ ExceptionOr<void> HTMLMediaElement::setVolume(double volume) > > #if !PLATFORM(IOS_FAMILY) > if (volume && processingUserGestureForMedia()) >- removeBehaviorsRestrictionsAfterFirstUserGesture(MediaElementSession::AllRestrictions & ~MediaElementSession::RequireUserGestureToControlControlsManager); >+ removeBehaviorRestrictionsAfterFirstUserGesture(MediaElementSession::AllRestrictions & ~MediaElementSession::RequireUserGestureToControlControlsManager); > > m_volume = volume; > m_volumeInitialized = true; >@@ -3783,7 +3783,7 @@ void HTMLMediaElement::setMuted(bool muted) > bool mutedStateChanged = m_muted != muted; > if (mutedStateChanged || !m_explicitlyMuted) { > if (processingUserGestureForMedia()) { >- removeBehaviorsRestrictionsAfterFirstUserGesture(MediaElementSession::AllRestrictions & ~MediaElementSession::RequireUserGestureToControlControlsManager); >+ removeBehaviorRestrictionsAfterFirstUserGesture(MediaElementSession::AllRestrictions & ~MediaElementSession::RequireUserGestureToControlControlsManager); > > if (hasAudio() && muted) > userDidInterfereWithAutoplay(); >@@ -5878,7 +5878,7 @@ void HTMLMediaElement::webkitShowPlaybackTargetPicker() > { > ALWAYS_LOG(LOGIDENTIFIER); > if (processingUserGestureForMedia()) >- removeBehaviorsRestrictionsAfterFirstUserGesture(); >+ removeBehaviorRestrictionsAfterFirstUserGesture(); > m_mediaSession->showPlaybackTargetPicker(); > } > >@@ -5917,6 +5917,9 @@ void HTMLMediaElement::dispatchEvent(Event& event) > { > DEBUG_LOG(LOGIDENTIFIER, event.type()); > >+ if (m_removedBehaviorRestrictionsAfterFirstUserGesture && event.type() == eventNames().endedEvent) >+ document().userActivatedMediaFinishedPlaying(); >+ > HTMLElement::dispatchEvent(event); > } > >@@ -7207,7 +7210,7 @@ void HTMLMediaElement::requestInstallMissingPlugins(const String& details, const > } > #endif > >-void HTMLMediaElement::removeBehaviorsRestrictionsAfterFirstUserGesture(MediaElementSession::BehaviorRestrictions mask) >+void HTMLMediaElement::removeBehaviorRestrictionsAfterFirstUserGesture(MediaElementSession::BehaviorRestrictions mask) > { > MediaElementSession::BehaviorRestrictions restrictionsToRemove = mask & > (MediaElementSession::RequireUserGestureForLoad >@@ -7222,6 +7225,8 @@ void HTMLMediaElement::removeBehaviorsRestrictionsAfterFirstUserGesture(MediaEle > | MediaElementSession::InvisibleAutoplayNotPermitted > | MediaElementSession::RequireUserGestureToControlControlsManager); > >+ m_removedBehaviorRestrictionsAfterFirstUserGesture = true; >+ > m_mediaSession->removeBehaviorRestriction(restrictionsToRemove); > document().topDocument().noteUserInteractionWithMediaElement(); > } >diff --git a/Source/WebCore/html/HTMLMediaElement.h b/Source/WebCore/html/HTMLMediaElement.h >index a09162633e4c6213fdb9867d71b82f1c60ac80e7..c15dc2412203aa477e5cb4fe5d7feaa4f5bf6501 100644 >--- a/Source/WebCore/html/HTMLMediaElement.h >+++ b/Source/WebCore/html/HTMLMediaElement.h >@@ -562,6 +562,7 @@ public: > #if !RELEASE_LOG_DISABLED > const Logger& logger() const final { return *m_logger.get(); } > const void* logIdentifier() const final { return m_logIdentifier; } >+ const char* logClassName() const final { return "HTMLMediaElement"; } > WTFLogChannel& logChannel() const final; > #endif > >@@ -851,7 +852,7 @@ private: > > void changeNetworkStateFromLoadingToIdle(); > >- void removeBehaviorsRestrictionsAfterFirstUserGesture(MediaElementSession::BehaviorRestrictions mask = MediaElementSession::AllRestrictions); >+ void removeBehaviorRestrictionsAfterFirstUserGesture(MediaElementSession::BehaviorRestrictions mask = MediaElementSession::AllRestrictions); > > void updateMediaController(); > bool isBlocked() const; >@@ -942,8 +943,6 @@ private: > void setInActiveDocument(bool); > > #if !RELEASE_LOG_DISABLED >- const char* logClassName() const final { return "HTMLMediaElement"; } >- > const void* mediaPlayerLogIdentifier() final { return logIdentifier(); } > const Logger& mediaPlayerLogger() final { return logger(); } > #endif >@@ -1201,6 +1200,7 @@ private: > > bool m_isPlayingToWirelessTarget { false }; > bool m_playingOnSecondScreen { false }; >+ bool m_removedBehaviorRestrictionsAfterFirstUserGesture { false }; > }; > > String convertEnumerationToString(HTMLMediaElement::AutoplayEventPlaybackState); >diff --git a/Source/WebCore/html/HTMLVideoElement.cpp b/Source/WebCore/html/HTMLVideoElement.cpp >index f47d4678de46493dc67b7aa9d1c5a7221c385832..a6f2f835bb7b55aeeaf4c084ddc7a8fe91943c12 100644 >--- a/Source/WebCore/html/HTMLVideoElement.cpp >+++ b/Source/WebCore/html/HTMLVideoElement.cpp >@@ -318,7 +318,7 @@ NativeImagePtr HTMLVideoElement::nativeImageForCurrentTime() > > ExceptionOr<void> HTMLVideoElement::webkitEnterFullscreen() > { >- LOG(Media, "HTMLVideoElement::webkitEnterFullscreen(%p)", this); >+ ALWAYS_LOG(LOGIDENTIFIER); > if (isFullscreen()) > return { }; > >@@ -333,7 +333,7 @@ ExceptionOr<void> HTMLVideoElement::webkitEnterFullscreen() > > void HTMLVideoElement::webkitExitFullscreen() > { >- LOG(Media, "HTMLVideoElement::webkitExitFullscreen(%p)", this); >+ ALWAYS_LOG(LOGIDENTIFIER); > if (isFullscreen()) > exitFullscreen(); > } >@@ -443,7 +443,7 @@ static inline HTMLMediaElementEnums::VideoFullscreenMode toFullscreenMode(HTMLVi > > void HTMLVideoElement::webkitSetPresentationMode(VideoPresentationMode mode) > { >- LOG(Media, "HTMLVideoElement::webkitSetPresentationMode(%p) - %d", this, mode); >+ ALWAYS_LOG(LOGIDENTIFIER, mode); > setFullscreenMode(toFullscreenMode(mode)); > } > >@@ -483,7 +483,7 @@ auto HTMLVideoElement::webkitPresentationMode() const -> VideoPresentationMode > void HTMLVideoElement::fullscreenModeChanged(VideoFullscreenMode mode) > { > if (mode != fullscreenMode()) { >- LOG(Media, "HTMLVideoElement::fullscreenModeChanged(%p) - mode changed from %i to %i", this, fullscreenMode(), mode); >+ ALWAYS_LOG(LOGIDENTIFIER, "changed from ", fullscreenMode(), ", to ", mode); > scheduleEvent(eventNames().webkitpresentationmodechangedEvent); > } > >diff --git a/Source/WebCore/html/MediaElementSession.cpp b/Source/WebCore/html/MediaElementSession.cpp >index d987c64876aeabffe7a2b65ac1fbedc0e87e50f4..e14cd572d0203ba99ce2f8f760bba0735900049c 100644 >--- a/Source/WebCore/html/MediaElementSession.cpp >+++ b/Source/WebCore/html/MediaElementSession.cpp >@@ -242,7 +242,7 @@ void MediaElementSession::removeBehaviorRestriction(BehaviorRestrictions restric > if (!(m_restrictions & restriction)) > return; > >- INFO_LOG(LOGIDENTIFIER, "removing ", restrictionNames(m_restrictions & restriction)); >+ INFO_LOG(LOGIDENTIFIER, "removed ", restrictionNames(m_restrictions & restriction)); > m_restrictions &= ~restriction; > } > >diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog >index eb098ea3ddf305b4d74b74b80a01750ea4e1a863..bfa1d440a9e669e865ef21d075fa807b3bb25351 100644 >--- a/LayoutTests/ChangeLog >+++ b/LayoutTests/ChangeLog >@@ -1,3 +1,16 @@ >+2019-05-16 Eric Carlson <eric.carlson@apple.com> >+ >+ Allow sequential playback of media files when initial playback started with a user gesture >+ https://bugs.webkit.org/show_bug.cgi?id=197959 >+ <rdar://problem/50655207> >+ >+ Reviewed by Youenn Fablet. >+ >+ * media/media-fullscreen.js: Insert a pause between tests to clear the user gesture >+ used in the first test. >+ * media/playlist-inherits-user-gesture-expected.txt: Added. >+ * media/playlist-inherits-user-gesture.html: Added. >+ > 2019-05-13 Sihui Liu <sihui_liu@apple.com> > > [ Mojave Debug ] REGRESSION (r242975) Layout Test imported/w3c/IndexedDB-private-browsing/idbobjectstore_createIndex7-event_order.html is a flaky failure >diff --git a/LayoutTests/media/media-fullscreen.js b/LayoutTests/media/media-fullscreen.js >index 5e1d2916d4f79e23032e190b9c9368304e0ad613..d339ca02b6badf32da8cc648103596141718d89c 100644 >--- a/LayoutTests/media/media-fullscreen.js >+++ b/LayoutTests/media/media-fullscreen.js >@@ -14,7 +14,10 @@ function buttonClickHandler() > else { > if (movie.type == 'video') > testDOMException("mediaElement.webkitEnterFullScreen()", "DOMException.INVALID_STATE_ERR"); >- openNextMovie(); >+ >+ // A user gesture will transfer across setTimeout for 1 second, so pause to let that >+ // expire before opening the next movie. >+ setTimeout(openNextMovie, 1010); > } > } > >@@ -62,7 +65,6 @@ function canplaythrough() > var movie = movieInfo.movies[movieInfo.current]; > > consoleWrite("* event handler NOT triggered by a user gesture"); >- > if (movie.type == 'video') { > testExpected("mediaElement.webkitSupportsFullscreen", movie.supportsFS); > if (mediaElement.webkitSupportsPresentationMode) >@@ -80,10 +82,7 @@ function canplaythrough() > testDOMException("mediaElement.webkitEnterFullScreen()", "DOMException.INVALID_STATE_ERR"); > > // Click on the button >- if (window.testRunner) >- setTimeout(clickEnterFullscreenButton, 10); >- else >- openNextMovie(); >+ runWithKeyDown(clickEnterFullscreenButton); > } > > function openNextMovie() >diff --git a/LayoutTests/media/playlist-inherits-user-gesture-expected.txt b/LayoutTests/media/playlist-inherits-user-gesture-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..a4015d43657b2362e87510b3e81fd007c4cecf40 >--- /dev/null >+++ b/LayoutTests/media/playlist-inherits-user-gesture-expected.txt >@@ -0,0 +1,27 @@ >+** Start first video with user gesture. >+RUN(window.internals.settings.setVideoPlaybackRequiresUserGesture(true);) >+RUN(video1 = document.createElement("video")) >+RUN(video1.src = findMediaFile("video", "content/test")) >+RUN(document.body.appendChild(video1)) >+EXPECTED (window.internals.pageMediaState().includes('HasUserInteractedWithMediaElement') == 'false') OK >+RUN(video1.play()) >+EXPECTED (window.internals.pageMediaState().includes('HasUserInteractedWithMediaElement') == 'true') OK >+EVENT(playing) >+RUN(video1.currentTime = video1.duration - 0.2) >+EVENT(ended) >+ >+** Start second video without user gesture but within inheritance window, should succeed. >+RUN(video2 = document.createElement("video")) >+RUN(video2.src = findMediaFile("video", "content/test")) >+RUN(document.body.appendChild(video2)) >+Promise resolved OK >+RUN(video2.currentTime = video2.duration - 0.2) >+EVENT(ended) >+ >+** Start third video without user gesture but after inheritance window, should fail. >+RUN(video3 = document.createElement("video")) >+RUN(video3.src = findMediaFile("video", "content/test")) >+RUN(document.body.appendChild(video3)) >+Promise rejected correctly OK >+END OF TEST >+ >diff --git a/LayoutTests/media/playlist-inherits-user-gesture.html b/LayoutTests/media/playlist-inherits-user-gesture.html >new file mode 100644 >index 0000000000000000000000000000000000000000..810cc3f706425be4caf86d2877dc8f25c5117eea >--- /dev/null >+++ b/LayoutTests/media/playlist-inherits-user-gesture.html >@@ -0,0 +1,54 @@ >+<!DOCTYPE html> >+<html> >+<head> >+ <title>playlist-inherits-user-gesture</title> >+ <script src=media-file.js></script> >+ <script src=video-test.js></script> >+ <script> >+ async function runTest() { >+ consoleWrite("** Start first video with user gesture.") >+ if (window.internals) >+ run('window.internals.settings.setVideoPlaybackRequiresUserGesture(true);'); >+ run('video1 = document.createElement("video")'); >+ run('video1.src = findMediaFile("video", "content/test")'); >+ video1.controls = 1; >+ run('document.body.appendChild(video1)'); >+ >+ if (window.internals) >+ testExpected("window.internals.pageMediaState().includes('HasUserInteractedWithMediaElement')", false); >+ runWithKeyDown(() => { >+ run('video1.play()'); >+ }); >+ if (window.internals) >+ testExpected("window.internals.pageMediaState().includes('HasUserInteractedWithMediaElement')", true) >+ >+ await waitFor(video1, 'playing'); >+ run('video1.currentTime = video1.duration - 0.2'); >+ await waitFor(video1, 'ended'); >+ >+ consoleWrite("<br>** Start second video without user gesture but within inheritance window, should succeed.") >+ run('video2 = document.createElement("video")'); >+ run('video2.src = findMediaFile("video", "content/test")'); >+ video2.controls = 1; >+ run('document.body.appendChild(video2)'); >+ >+ await shouldResolve(video2.play()); >+ run('video2.currentTime = video2.duration - 0.2'); >+ await waitFor(video2, 'ended'); >+ >+ consoleWrite("<br>** Start third video without user gesture but after inheritance window, should fail.") >+ await sleepFor(1200); >+ run('video3 = document.createElement("video")'); >+ run('video3.src = findMediaFile("video", "content/test")'); >+ video3.controls = 1; >+ run('document.body.appendChild(video3)'); >+ >+ await shouldReject(video3.play()); >+ >+ endTest(); >+ } >+ </script> >+</head> >+<body onload="runTest()"> >+</body> >+</html>
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 197959
:
370061
|
370072
|
370074
|
370075
| 370114