Text tracks should be treated differently according to their kind
authoreric.carlson@apple.com <eric.carlson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 15 Dec 2011 19:18:54 +0000 (19:18 +0000)
committereric.carlson@apple.com <eric.carlson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 15 Dec 2011 19:18:54 +0000 (19:18 +0000)
https://bugs.webkit.org/show_bug.cgi?id=72547

Reviewed by Sam Weinig.

Source/WebCore:

Tests: media/track/track-default-attribute.html
       media/track/track-mode-not-changed-by-new-track.html
       media/track/track-mode-triggers-loading.html

* html/HTMLAudioElement.cpp:
(WebCore::HTMLAudioElement::HTMLAudioElement): Add "createdByParser" parameter.
(WebCore::HTMLAudioElement::create): Ditto.
(WebCore::HTMLAudioElement::createForJSConstructor): Deal with constructor change.
* html/HTMLAudioElement.h:

* html/HTMLMediaElement.cpp:
(WebCore::HTMLMediaElement::HTMLMediaElement): Add "createdByParser" parameter. Initialize m_parsingInProgress.
(WebCore::HTMLMediaElement::finishParsingChildren): Clear m_parsingInProgress. Schedule track
    loading if necessary.
(WebCore::HTMLMediaElement::loadTimerFired): Call configureTextTracks not call scheduleLoad,
    it just schedules the load timer again.
(WebCore::HTMLMediaElement::prepareForLoad): Add all non-disabled track elements to a vector
    so we can prevent the media element's readyState from reaching HAVE_METADATA until the
    tracks are ready.
(WebCore::HTMLMediaElement::textTracksAreReady): New. Return false unless all tracks that were
    not disabled when loading started have loaded or failed.
(WebCore::HTMLMediaElement::textTrackReadyStateChanged): Call setReadyState when a track is
    stops loading.
(WebCore::HTMLMediaElement::textTrackModeChanged): Trigger <track> loading when the mode
    changes to hidden or showing for the first time.
(WebCore::HTMLMediaElement::setReadyState): Do not advance to HAVE_METADATA or higher while
    track elements are loading.
(WebCore::HTMLMediaElement::addTrack): Removed.
(WebCore::HTMLMediaElement::showingTrackWithSameKind): New.
(WebCore::HTMLMediaElement::trackWasAdded):
(WebCore::HTMLMediaElement::trackWillBeRemoved): Flag a track as unconfigured so it will be
    reconfigured if it is added to another element.
(WebCore::HTMLMediaElement::userIsInterestedInThisLanguage): New.
(WebCore::HTMLMediaElement::userIsInterestedInThisTrack): New. Consider user preferences.
(WebCore::HTMLMediaElement::configureTextTrack): New. Configure a track as per the user's preferences.
(WebCore::HTMLMediaElement::configureTextTracks): New. Configure all track elements.
* html/HTMLMediaElement.h:
* html/HTMLMediaElement.h:

* html/HTMLTagNames.in: Add constructorNeedsCreatedByParser to audio and video.

* html/HTMLTrackElement.cpp:
(WebCore::HTMLTrackElement::HTMLTrackElement): Initialize m_hasBeenConfigured.
* html/HTMLTrackElement.h:
(WebCore::HTMLTrackElement::hasBeenConfigured):
(WebCore::HTMLTrackElement::setHasBeenConfigured):

* html/HTMLVideoElement.cpp:
(WebCore::HTMLVideoElement::HTMLVideoElement): Add "createdByParser" parameter.
(WebCore::HTMLVideoElement::create): Ditto.
* html/HTMLVideoElement.h:

* html/TextTrack.cpp:
(WebCore::TextTrack::TextTrack): Initialize m_mode to DISABLED, not HIDDEN. Initialize m_showingByDefault.
(WebCore::TextTrack::setMode): Clear the "showing by default" flag when a track's mode is
    explicitly set to SHOWING.
(WebCore::TextTrack::mode): Return SHOWING whenever the "showing by default" flag is set.
* html/TextTrack.h:
(WebCore::TextTrack::showingByDefault):
(WebCore::TextTrack::setShowingByDefault):

* html/TextTrackCue.cpp:
(WebCore::TextTrackCue::isActive): Return false if a cue has no track, or if its track is disabled.
(WebCore::TextTrackCue::setIsActive): Don't enable a cue if it has no track, or if its track
    is disabled.

LayoutTests:

* media/track/captions-webvtt/metadata.vtt: Added.
* media/track/track-default-attribute-expected.txt: Added.
* media/track/track-default-attribute.html: Added.
* media/track/track-mode-not-changed-by-new-track-expected.txt: Added.
* media/track/track-mode-not-changed-by-new-track.html: Added.
* media/track/track-mode-triggers-loading-expected.txt: Added.
* media/track/track-mode-triggers-loading.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@102968 268f45cc-cd09-0410-ab3c-d52691b4dbfc

21 files changed:
LayoutTests/ChangeLog
LayoutTests/media/track/captions-webvtt/metadata.vtt [new file with mode: 0644]
LayoutTests/media/track/track-default-attribute-expected.txt [new file with mode: 0644]
LayoutTests/media/track/track-default-attribute.html [new file with mode: 0644]
LayoutTests/media/track/track-mode-not-changed-by-new-track-expected.txt [new file with mode: 0644]
LayoutTests/media/track/track-mode-not-changed-by-new-track.html [new file with mode: 0644]
LayoutTests/media/track/track-mode-triggers-loading-expected.txt [new file with mode: 0644]
LayoutTests/media/track/track-mode-triggers-loading.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/html/HTMLAudioElement.cpp
Source/WebCore/html/HTMLAudioElement.h
Source/WebCore/html/HTMLMediaElement.cpp
Source/WebCore/html/HTMLMediaElement.h
Source/WebCore/html/HTMLTagNames.in
Source/WebCore/html/HTMLTrackElement.cpp
Source/WebCore/html/HTMLTrackElement.h
Source/WebCore/html/HTMLVideoElement.cpp
Source/WebCore/html/HTMLVideoElement.h
Source/WebCore/html/TextTrack.cpp
Source/WebCore/html/TextTrack.h
Source/WebCore/html/TextTrackCue.cpp

index 89b7066..a577f1b 100644 (file)
@@ -1,3 +1,18 @@
+2011-12-15  Eric Carlson  <eric.carlson@apple.com>
+
+        Text tracks should be treated differently according to their kind
+        https://bugs.webkit.org/show_bug.cgi?id=72547
+
+        Reviewed by Sam Weinig.
+
+        * media/track/captions-webvtt/metadata.vtt: Added.
+        * media/track/track-default-attribute-expected.txt: Added.
+        * media/track/track-default-attribute.html: Added.
+        * media/track/track-mode-not-changed-by-new-track-expected.txt: Added.
+        * media/track/track-mode-not-changed-by-new-track.html: Added.
+        * media/track/track-mode-triggers-loading-expected.txt: Added.
+        * media/track/track-mode-triggers-loading.html: Added.
+
 2011-12-15  Kenneth Russell  <kbr@google.com>
 
         Unreviewed Chromium test expectations update; add suppression.
diff --git a/LayoutTests/media/track/captions-webvtt/metadata.vtt b/LayoutTests/media/track/captions-webvtt/metadata.vtt
new file mode 100644 (file)
index 0000000..4759463
--- /dev/null
@@ -0,0 +1,38 @@
+WEBVTT
+
+00:00:00.000 --> 00:00:01.000
+Lorem ipsum dolor sit amet, 
+
+00:00:02.000 --> 00:00:03.000
+consectetuer adipiscing elit, 
+
+00:00:04.000 --> 00:00:05.000
+sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. 
+
+00:00:06.000 --> 00:00:07.000
+Ut wisi enim ad minim veniam, 
+
+00:00:08.000 --> 00:00:09.000
+quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. 
+
+00:00:10.000 --> 00:00:11.000
+Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, 
+
+00:00:12.000 --> 00:00:13.000
+vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio
+
+00:00:14.000 --> 00:00:15.000
+dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.
+
+00:00:16.000 --> 00:00:17.000
+Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id
+
+00:00:18.000 --> 00:00:19.000
+quod mazim placerat facer possim assum. 
+
+00:00:20.000 --> 00:00:21.000
+Typi non habent claritatem insitam;
+
+00:00:22.000 --> 00:00:23.000
+est usus legentis in iis qui facit eorum claritatem.
+
diff --git a/LayoutTests/media/track/track-default-attribute-expected.txt b/LayoutTests/media/track/track-default-attribute-expected.txt
new file mode 100644 (file)
index 0000000..662b0b5
--- /dev/null
@@ -0,0 +1,8 @@
+Tests that a track with the 'default' attribute loads automatically.
+
+EVENT(load)
+EXPECTED (event.target.readyState == '2') OK
+EXPECTED (event.target.id == 'default') OK
+
+END OF TEST
+
diff --git a/LayoutTests/media/track/track-default-attribute.html b/LayoutTests/media/track/track-default-attribute.html
new file mode 100644 (file)
index 0000000..40fadaf
--- /dev/null
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <script src=../media-file.js></script>
+        <script src=../video-test.js></script>
+        <script>
+
+            var timer = null;
+
+            function trackLoaded()
+            {
+                consoleWrite("EVENT(load)");
+                testExpected("event.target.readyState", HTMLTrackElement.LOADED);
+                testExpected("event.target.id", "default");
+                consoleWrite("");
+
+                // End the test after a brief pause so we allow other tracks to load if they will.
+                if (timer)
+                    clearTimeout(timer);
+                timer = setTimeout(function() { endTest() }, 200);
+            }
+
+        </script>
+    </head>
+    <body>
+        <p>Tests that a track with the 'default' attribute loads automatically.</p>
+        <video>
+            <track kind="captions" src="captions-webvtt/tc005-default-styles.vtt" onload="trackLoaded()">
+            <track kind="captions" src="captions-webvtt/tc005-metadata-area.vtt" onload="trackLoaded()">
+            <track default kind="captions" src="captions-webvtt/tc004-webvtt-file.vtt" onload="trackLoaded()" id="default" >
+        </video>
+    </body>
+</html>
diff --git a/LayoutTests/media/track/track-mode-not-changed-by-new-track-expected.txt b/LayoutTests/media/track/track-mode-not-changed-by-new-track-expected.txt
new file mode 100644 (file)
index 0000000..84c4922
--- /dev/null
@@ -0,0 +1,38 @@
+Tests that a track appended after the initial track configuration does not change other tracks.
+
+
+EVENT(load) -- <body>
+EXPECTED (track1.readyState == '0') OK
+EXPECTED (track1.track.mode == '0') OK
+
+EVENT(canplaythrough) -- <video>
+**check initial metadata track state
+EXPECTED (track1.readyState == '0') OK
+EXPECTED (track1.track.mode == '0') OK
+EXPECTED (track1.track.cues == 'null') OK
+RUN(track1.track.mode = TextTrack.HIDDEN)
+
+EVENT(load) -- <track kind='metadata' >
+**check metadata track state
+EXPECTED (track1.readyState == '2') OK
+EXPECTED (track1.track.mode == '1') OK
+EXPECTED (track1.track.cues.length == '12') OK
+EXPECTED (track1.track.cues[11].startTime == '22') OK
+**add a caption track, configured to load automatically
+RUN(track2 = document.createElement('track'))
+RUN(track2.setAttribute('kind', 'captions'))
+RUN(track2.setAttribute('default', 'default'))
+RUN(track2.setAttribute('onload', 'captionsTrackLoaded()'))
+RUN(track2.setAttribute('src', 'captions-webvtt/tc004-webvtt-file.vtt'))
+RUN(video.appendChild(track2))
+
+EVENT(load) -- <track kind='captions' >
+**check that metadata track state has not changed
+EXPECTED (track1.readyState == '2') OK
+EXPECTED (track1.track.mode == '1') OK
+**and that the captions track state is correct
+EXPECTED (track2.readyState == '2') OK
+EXPECTED (track2.track.mode == '2') OK
+
+END OF TEST
+
diff --git a/LayoutTests/media/track/track-mode-not-changed-by-new-track.html b/LayoutTests/media/track/track-mode-not-changed-by-new-track.html
new file mode 100644 (file)
index 0000000..40e9bb8
--- /dev/null
@@ -0,0 +1,75 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+        <script src=../media-file.js></script>
+        <script src=../video-test.js></script>
+        <script>
+
+            function captionsTrackLoaded()
+            {
+                consoleWrite("EVENT(load) -- &lt;track kind='captions' &gt;");
+                consoleWrite("<i>**check that metadata track state has not changed<" + "/i>");
+                testExpected("track1.readyState", HTMLTrackElement.LOADED);
+                testExpected("track1.track.mode", TextTrack.HIDDEN);
+                consoleWrite("<i>**and that the captions track state is correct<" + "/i>");
+                testExpected("track2.readyState", HTMLTrackElement.LOADED);
+                testExpected("track2.track.mode", TextTrack.SHOWING);
+                consoleWrite("");
+                endTest();
+            }
+
+            function metadataTrackLoaded()
+            {
+                consoleWrite("EVENT(load) -- &lt;track kind='metadata' &gt;");
+                consoleWrite("<i>**check metadata track state<" + "/i>");
+                testExpected("track1.readyState", HTMLTrackElement.LOADED);
+                testExpected("track1.track.mode", TextTrack.HIDDEN);
+                testExpected("track1.track.cues.length", 12);
+                testExpected("track1.track.cues[11].startTime", 22);
+
+                consoleWrite("<i>**add a caption track, configured to load automatically<" + "/i>");
+                run("track2 = document.createElement('track')");
+                run("track2.setAttribute('kind', 'captions')");
+                run("track2.setAttribute('default', 'default')");
+                run("track2.setAttribute('onload', 'captionsTrackLoaded()')");
+                run("track2.setAttribute('src', 'captions-webvtt/tc004-webvtt-file.vtt')");
+                run("video.appendChild(track2)");
+
+                consoleWrite("");
+            }
+
+            function canplaythrough()
+            {
+                consoleWrite("EVENT(canplaythrough) -- &lt;video&gt;");
+                consoleWrite("<i>**check initial metadata track state<" + "/i>");
+                testExpected("track1.readyState", HTMLTrackElement.NONE);
+                testExpected("track1.track.mode", TextTrack.DISABLED);
+                testExpected("track1.track.cues", null);
+                run("track1.track.mode = TextTrack.HIDDEN");
+                consoleWrite("");
+            }
+
+            function start()
+            {
+                consoleWrite("<br>EVENT(load) -- &lt;body&gt;");
+                findMediaElement();
+
+                track1 = document.querySelectorAll('track')[0]; 
+                testExpected("track1.readyState", HTMLTrackElement.NONE);
+                testExpected("track1.track.mode", TextTrack.DISABLED);
+
+                video.src = findMediaFile("video", "../content/test");
+                consoleWrite("");
+            }
+        </script>
+    </head>
+
+    <body onload="start()">
+        <p>Tests that a track appended after the initial track configuration does not change other tracks.</p>
+        <video oncanplaythrough="canplaythrough()" > 
+            <track kind="metadata" src="captions-webvtt/metadata.vtt" onload="metadataTrackLoaded()">
+        </video>
+    </body>
+</html>
diff --git a/LayoutTests/media/track/track-mode-triggers-loading-expected.txt b/LayoutTests/media/track/track-mode-triggers-loading-expected.txt
new file mode 100644 (file)
index 0000000..195f946
--- /dev/null
@@ -0,0 +1,24 @@
+Tests that a 'metadata' track does not load automatically, but does load when the mode is changed.
+
+
+EVENT(load) -- <body>
+**check initial metadata track state
+EXPECTED (track.readyState == '0') OK
+EXPECTED (video.textTracks[0].mode == '0') OK
+
+EVENT(canplaythrough) -- <video>
+**change metadata track mode so it loads
+EXPECTED (track.readyState == '0') OK
+EXPECTED (video.textTracks[0].mode == '0') OK
+EXPECTED (video.textTracks[0].cues == 'null') OK
+RUN(video.textTracks[0].mode = TextTrack.HIDDEN)
+
+EVENT(load) -- <track>
+**check metadata track state
+EXPECTED (track.readyState == '2') OK
+EXPECTED (track.track.mode == '1') OK
+EXPECTED (video.textTracks[0].cues.length == '12') OK
+EXPECTED (video.textTracks[0].cues[11].startTime == '22') OK
+
+END OF TEST
+
diff --git a/LayoutTests/media/track/track-mode-triggers-loading.html b/LayoutTests/media/track/track-mode-triggers-loading.html
new file mode 100644 (file)
index 0000000..94e116c
--- /dev/null
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+        <script src=../media-file.js></script>
+        <script src=../video-test.js></script>
+        <script>
+
+            function trackLoaded()
+            {
+                consoleWrite("EVENT(load) -- &lt;track&gt;");
+                consoleWrite("<i>**check metadata track state<" + "/i>");
+                testExpected("track.readyState", HTMLTrackElement.LOADED);
+                testExpected("track.track.mode", TextTrack.HIDDEN);
+                testExpected("video.textTracks[0].cues.length", 12);
+                testExpected("video.textTracks[0].cues[11].startTime", 22);
+                consoleWrite("");
+                endTest();
+            }
+
+            function canplaythrough()
+            {
+                consoleWrite("EVENT(canplaythrough) -- &lt;video&gt;");
+                consoleWrite("<i>**change metadata track mode so it loads<" + "/i>");
+                testExpected("track.readyState", HTMLTrackElement.NONE);
+                testExpected("video.textTracks[0].mode", TextTrack.DISABLED);
+                testExpected("video.textTracks[0].cues", null);
+                run("video.textTracks[0].mode = TextTrack.HIDDEN");
+                consoleWrite("");
+            }
+
+            function start()
+            {
+                consoleWrite("<br>EVENT(load) -- &lt;body&gt;");
+                findMediaElement();
+
+                consoleWrite("<i>**check initial metadata track state<" + "/i>");
+                track = document.querySelectorAll('track')[0]; 
+                testExpected("track.readyState", HTMLTrackElement.NONE);
+                testExpected("video.textTracks[0].mode", TextTrack.DISABLED);
+
+                video.src = findMediaFile("video", "../content/test");
+                consoleWrite("");
+            }
+        </script>
+    </head>
+
+    <body onload="start()">
+        <p>Tests that a 'metadata' track does not load automatically, but does load when the mode is changed.</p>
+        <video oncanplaythrough="canplaythrough()" > 
+            <track kind="metadata" src="captions-webvtt/metadata.vtt" onload="trackLoaded()">
+        </video>
+    </body>
+</html>
index 8db0204..4aa2ba7 100644 (file)
@@ -1,3 +1,76 @@
+2011-12-15  Eric Carlson  <eric.carlson@apple.com>
+
+        Text tracks should be treated differently according to their kind
+        https://bugs.webkit.org/show_bug.cgi?id=72547
+
+        Reviewed by Sam Weinig.
+
+        Tests: media/track/track-default-attribute.html
+               media/track/track-mode-not-changed-by-new-track.html
+               media/track/track-mode-triggers-loading.html
+
+        * html/HTMLAudioElement.cpp:
+        (WebCore::HTMLAudioElement::HTMLAudioElement): Add "createdByParser" parameter.
+        (WebCore::HTMLAudioElement::create): Ditto.
+        (WebCore::HTMLAudioElement::createForJSConstructor): Deal with constructor change.
+        * html/HTMLAudioElement.h:
+
+        * html/HTMLMediaElement.cpp:
+        (WebCore::HTMLMediaElement::HTMLMediaElement): Add "createdByParser" parameter. Initialize m_parsingInProgress.
+        (WebCore::HTMLMediaElement::finishParsingChildren): Clear m_parsingInProgress. Schedule track
+            loading if necessary.
+        (WebCore::HTMLMediaElement::loadTimerFired): Call configureTextTracks not call scheduleLoad, 
+            it just schedules the load timer again.
+        (WebCore::HTMLMediaElement::prepareForLoad): Add all non-disabled track elements to a vector
+            so we can prevent the media element's readyState from reaching HAVE_METADATA until the
+            tracks are ready.
+        (WebCore::HTMLMediaElement::textTracksAreReady): New. Return false unless all tracks that were
+            not disabled when loading started have loaded or failed.
+        (WebCore::HTMLMediaElement::textTrackReadyStateChanged): Call setReadyState when a track is
+            stops loading.
+        (WebCore::HTMLMediaElement::textTrackModeChanged): Trigger <track> loading when the mode
+            changes to hidden or showing for the first time.
+        (WebCore::HTMLMediaElement::setReadyState): Do not advance to HAVE_METADATA or higher while
+            track elements are loading.
+        (WebCore::HTMLMediaElement::addTrack): Removed.
+        (WebCore::HTMLMediaElement::showingTrackWithSameKind): New.
+        (WebCore::HTMLMediaElement::trackWasAdded):
+        (WebCore::HTMLMediaElement::trackWillBeRemoved): Flag a track as unconfigured so it will be
+            reconfigured if it is added to another element.
+        (WebCore::HTMLMediaElement::userIsInterestedInThisLanguage): New.
+        (WebCore::HTMLMediaElement::userIsInterestedInThisTrack): New. Consider user preferences.
+        (WebCore::HTMLMediaElement::configureTextTrack): New. Configure a track as per the user's preferences.
+        (WebCore::HTMLMediaElement::configureTextTracks): New. Configure all track elements.
+        * html/HTMLMediaElement.h:
+        * html/HTMLMediaElement.h:
+
+        * html/HTMLTagNames.in: Add constructorNeedsCreatedByParser to audio and video.
+
+        * html/HTMLTrackElement.cpp:
+        (WebCore::HTMLTrackElement::HTMLTrackElement): Initialize m_hasBeenConfigured.
+        * html/HTMLTrackElement.h:
+        (WebCore::HTMLTrackElement::hasBeenConfigured):
+        (WebCore::HTMLTrackElement::setHasBeenConfigured):
+
+        * html/HTMLVideoElement.cpp:
+        (WebCore::HTMLVideoElement::HTMLVideoElement): Add "createdByParser" parameter.
+        (WebCore::HTMLVideoElement::create): Ditto.
+        * html/HTMLVideoElement.h:
+
+        * html/TextTrack.cpp:
+        (WebCore::TextTrack::TextTrack): Initialize m_mode to DISABLED, not HIDDEN. Initialize m_showingByDefault.
+        (WebCore::TextTrack::setMode): Clear the "showing by default" flag when a track's mode is
+            explicitly set to SHOWING.
+        (WebCore::TextTrack::mode): Return SHOWING whenever the "showing by default" flag is set.
+        * html/TextTrack.h:
+        (WebCore::TextTrack::showingByDefault):
+        (WebCore::TextTrack::setShowingByDefault):
+
+        * html/TextTrackCue.cpp:
+        (WebCore::TextTrackCue::isActive): Return false if a cue has no track, or if its track is disabled.
+        (WebCore::TextTrackCue::setIsActive): Don't enable a cue if it has no track, or if its track
+            is disabled.
+
 2011-12-15  Brady Eidson  <beidson@apple.com>
 
         Unreviewed, rolling out r102829.
index 1a34484..e3dcf47 100644 (file)
@@ -35,20 +35,20 @@ namespace WebCore {
 
 using namespace HTMLNames;
 
-HTMLAudioElement::HTMLAudioElement(const QualifiedName& tagName, Document* document)
-    : HTMLMediaElement(tagName, document)
+HTMLAudioElement::HTMLAudioElement(const QualifiedName& tagName, Document* document, bool createdByParser)
+    : HTMLMediaElement(tagName, document, createdByParser)
 {
     ASSERT(hasTagName(audioTag));
 }
 
-PassRefPtr<HTMLAudioElement> HTMLAudioElement::create(const QualifiedName& tagName, Document* document)
+PassRefPtr<HTMLAudioElement> HTMLAudioElement::create(const QualifiedName& tagName, Document* document, bool createdByParser)
 {
-    return adoptRef(new HTMLAudioElement(tagName, document));
+    return adoptRef(new HTMLAudioElement(tagName, document, createdByParser));
 }
 
 PassRefPtr<HTMLAudioElement> HTMLAudioElement::createForJSConstructor(Document* document, const String& src)
 {
-    RefPtr<HTMLAudioElement> audio = adoptRef(new HTMLAudioElement(audioTag, document));
+    RefPtr<HTMLAudioElement> audio = adoptRef(new HTMLAudioElement(audioTag, document, false));
     audio->setPreload("auto");
     if (!src.isNull()) {
         audio->setSrc(src);
index d96f2ff..cfa276c 100644 (file)
@@ -37,7 +37,7 @@ class Document;
 
 class HTMLAudioElement : public HTMLMediaElement {
 public:
-    static PassRefPtr<HTMLAudioElement> create(const QualifiedName&, Document*);
+    static PassRefPtr<HTMLAudioElement> create(const QualifiedName&, Document*, bool);
     static PassRefPtr<HTMLAudioElement> createForJSConstructor(Document*, const String& src);
 
     virtual bool hasPendingActivity() const { return isPlaying() || HTMLMediaElement::hasPendingActivity(); }
@@ -45,7 +45,7 @@ public:
     virtual bool isActiveNode() const { return true; }
 
 private:
-    HTMLAudioElement(const QualifiedName&, Document*);
+    HTMLAudioElement(const QualifiedName&, Document*, bool);
 
     virtual bool isVideo() const { return false; }
 };
index 1509f11..4451cba 100644 (file)
@@ -169,7 +169,7 @@ static void removeElementFromDocumentMap(HTMLMediaElement* element, Document* do
         map.add(document, set);
 }
 
-HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document* document)
+HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document* document, bool createdByParser)
     : HTMLElement(tagName, document)
     , ActiveDOMObject(document, this)
     , m_loadTimer(this, &HTMLMediaElement::loadTimerFired)
@@ -228,12 +228,14 @@ HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document* docum
     , m_loadInitiatedByUserGesture(false)
     , m_completelyLoaded(false)
     , m_havePreparedToPlay(false)
-#if ENABLE(WEB_AUDIO)
-    , m_audioSourceNode(0)
-#endif
+    , m_parsingInProgress(createdByParser)
 #if ENABLE(VIDEO_TRACK)
+    , m_tracksAreReady(true)
     , m_textTracks(0)
 #endif
+#if ENABLE(WEB_AUDIO)
+    , m_audioSourceNode(0)
+#endif
 {
     LOG(Media, "HTMLMediaElement::HTMLMediaElement");
     document->registerForDocumentActivationCallbacks(this);
@@ -398,6 +400,29 @@ void HTMLMediaElement::parseMappedAttribute(Attribute* attr)
         HTMLElement::parseMappedAttribute(attr);
 }
 
+void HTMLMediaElement::finishParsingChildren()
+{
+    HTMLElement::finishParsingChildren();
+    m_parsingInProgress = false;
+
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+    document()->updateStyleIfNeeded();
+    createMediaPlayerProxy();
+#endif
+    
+#if ENABLE(VIDEO_TRACK)
+    if (!RuntimeEnabledFeatures::webkitVideoTrackEnabled())
+        return;
+    
+    for (Node* node = firstChild(); node; node = node->nextSibling()) {
+        if (node->hasTagName(trackTag)) {
+            scheduleLoad(TextTrackResource);
+            break;
+        }
+    }
+#endif
+}
+
 bool HTMLMediaElement::rendererIsNeeded(const NodeRenderingContext& context)
 {
 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
@@ -543,7 +568,7 @@ void HTMLMediaElement::loadTimerFired(Timer<HTMLMediaElement>*)
 
 #if ENABLE(VIDEO_TRACK)
     if (m_pendingLoadFlags & TextTrackResource)
-        scheduleLoad(TextTrackResource);
+        configureTextTracks();
 #endif
 
     m_pendingLoadFlags = 0;
@@ -682,6 +707,19 @@ void HTMLMediaElement::prepareForLoad()
     // event may have already fired by then.
     setShouldDelayLoadEvent(true);
 
+#if ENABLE(VIDEO_TRACK)
+    // HTMLMediaElement::textTracksAreReady will need "... the text tracks whose mode was not in the
+    // disabled state when the element's resource selection algorithm last started".
+    m_textTracksWhenResourceSelectionBegan.clear();
+    if (m_textTracks) {
+        for (unsigned i = 0; i < m_textTracks->length(); ++i) {
+            TextTrack* track = m_textTracks->item(i);
+            if (track->mode() != TextTrack::DISABLED)
+                m_textTracksWhenResourceSelectionBegan.append(track);
+        }
+    }
+#endif
+
     configureMediaControls();
 }
 
@@ -925,14 +963,52 @@ void HTMLMediaElement::updateActiveTextTrackCues(float movieTime)
     // during a monotonic time increase.
 }
 
-void HTMLMediaElement::textTrackReadyStateChanged(TextTrack*)
+bool HTMLMediaElement::textTracksAreReady() const
 {
-    // FIXME(62885): Implement.
+    // The text tracks of a media element are ready if all the text tracks whose mode was not 
+    // in the disabled state when the element's resource selection algorithm last started now
+    // have a text track readiness state of loaded or failed to load.
+    for (unsigned i = 0; i < m_textTracksWhenResourceSelectionBegan.size(); ++i) {
+        if (m_textTracksWhenResourceSelectionBegan[i]->readinessState() == TextTrack::Loading)
+            return false;
+    }
+
+    return true;
 }
 
-void HTMLMediaElement::textTrackModeChanged(TextTrack*)
+void HTMLMediaElement::textTrackReadyStateChanged(TextTrack* track)
 {
-    // FIXME(62885): Implement.
+    if (m_player && m_textTracksWhenResourceSelectionBegan.contains(track)) {
+        if (track->readinessState() != TextTrack::Loading)
+            setReadyState(m_player->readyState());
+    }
+}
+
+void HTMLMediaElement::textTrackModeChanged(TextTrack* track)
+{
+    // 4.8.10.12.3 Sourcing out-of-band text tracks
+    // ... when a text track corresponding to a track element is created with text track
+    // mode set to disabled and subsequently changes its text track mode to hidden, showing,
+    // or showing by default for the first time, the user agent must immediately and synchronously
+    // run the following algorithm ...
+    
+    if (track->trackType() != TextTrack::TrackElement)
+        return;
+    
+    HTMLTrackElement* trackElement;
+    for (Node* node = firstChild(); node; node = node->nextSibling()) {
+        if (!node->hasTagName(trackTag))
+            continue;
+        trackElement = static_cast<HTMLTrackElement*>(node);
+        if (trackElement->track() != track)
+            continue;
+
+        // Mark this track as "configured" so configureTextTrack won't change the mode again.
+        trackElement->setHasBeenConfigured(true);
+        if (track->mode() != TextTrack::DISABLED && trackElement->readyState() == HTMLTrackElement::NONE)
+            trackElement->scheduleLoad();
+        break;
+    }
 }
 
 void HTMLMediaElement::textTrackKindChanged(TextTrack*)
@@ -1217,8 +1293,18 @@ void HTMLMediaElement::setReadyState(MediaPlayer::ReadyState state)
     ReadyState oldState = m_readyState;
     m_readyState = static_cast<ReadyState>(state);
 
+#if ENABLE(VIDEO_TRACK)
+    bool tracksAreReady = textTracksAreReady();
+
+    if (m_readyState == oldState && m_tracksAreReady == tracksAreReady)
+        return;
+
+    m_tracksAreReady = tracksAreReady;
+#else
     if (m_readyState == oldState)
         return;
+    bool tracksAreReady = true;
+#endif
     
     if (oldState > m_readyStateMaximum)
         m_readyStateMaximum = oldState;
@@ -1242,7 +1328,7 @@ void HTMLMediaElement::setReadyState(MediaPlayer::ReadyState state)
         }
     }
 
-    if (m_readyState >= HAVE_METADATA && oldState < HAVE_METADATA) {
+    if (m_readyState >= HAVE_METADATA && oldState < HAVE_METADATA && tracksAreReady) {
         scheduleEvent(eventNames().durationchangeEvent);
         scheduleEvent(eventNames().loadedmetadataEvent);
         if (hasMediaControls())
@@ -1253,7 +1339,7 @@ void HTMLMediaElement::setReadyState(MediaPlayer::ReadyState state)
 
     bool shouldUpdateDisplayState = false;
 
-    if (m_readyState >= HAVE_CURRENT_DATA && oldState < HAVE_CURRENT_DATA && !m_haveFiredLoadedData) {
+    if (m_readyState >= HAVE_CURRENT_DATA && oldState < HAVE_CURRENT_DATA && !m_haveFiredLoadedData && tracksAreReady) {
         m_haveFiredLoadedData = true;
         shouldUpdateDisplayState = true;
         scheduleEvent(eventNames().loadeddataEvent);
@@ -1261,14 +1347,14 @@ void HTMLMediaElement::setReadyState(MediaPlayer::ReadyState state)
     }
 
     bool isPotentiallyPlaying = potentiallyPlaying();
-    if (m_readyState == HAVE_FUTURE_DATA && oldState <= HAVE_CURRENT_DATA) {
+    if (m_readyState == HAVE_FUTURE_DATA && oldState <= HAVE_CURRENT_DATA && tracksAreReady) {
         scheduleEvent(eventNames().canplayEvent);
         if (isPotentiallyPlaying)
             scheduleEvent(eventNames().playingEvent);
         shouldUpdateDisplayState = true;
     }
 
-    if (m_readyState == HAVE_ENOUGH_DATA && oldState < HAVE_ENOUGH_DATA) {
+    if (m_readyState == HAVE_ENOUGH_DATA && oldState < HAVE_ENOUGH_DATA && tracksAreReady) {
         if (oldState <= HAVE_CURRENT_DATA)
             scheduleEvent(eventNames().canplayEvent);
 
@@ -2102,58 +2188,11 @@ PassRefPtr<TextTrack> HTMLMediaElement::addTrack(const String& kind, const Strin
     // loaded state, its text track mode to the text track hidden mode, and its text track list of cues to an empty list.
     
     // 6. Add the new text track to the media element's list of text tracks.
-    addTextTrack(textTrack);
+    textTracks()->append(textTrack);
 
     return textTrack.release();
 }
 
-void HTMLMediaElement::addTextTrack(PassRefPtr<TextTrack> track)
-{
-    textTracks()->append(track);
-    configureTextTracks();
-}
-
-void HTMLMediaElement::configureTextTracks()
-{
-    if (!RuntimeEnabledFeatures::webkitVideoTrackEnabled())
-        return;
-
-    // 4.8.10.12.3 Sourcing out-of-band text tracks
-    
-    // When a text track corresponding to a track element is added to a media element's list of text tracks,
-    // the user agent must set the text track mode appropriately, as determined by the following conditions:
-    
-    // * If the text track kind is subtitles or captions and the user has indicated an interest in having a
-    // track with this text track kind, text track language, and text track label enabled, and there is no
-    // other text track in the media element's list of text tracks with a text track kind of either subtitles
-    // or captions whose text track mode is showing
-    // * If the text track kind is descriptions and the user has indicated an interest in having text 
-    // descriptions with this text track language and text track label enabled, and there is no other text 
-    // track in the media element's list of text tracks with a text track kind of descriptions whose text 
-    // track mode is showing
-    //    Let the text track mode be showing.
-    //    If there is a text track in the media element's list of text tracks whose text track mode is showing 
-    //    by default, the user agent must furthermore change that text track's text track mode to hidden.
-    
-    // * If the text track kind is chapters and the text track language is one that the user agent has reason
-    // to believe is appropriate for the user, and there is no other text track in the media element's list of
-    // text tracks with a text track kind of chapters whose text track mode is showing
-    //    Let the text track mode be showing.
-    
-    // * If the track element has a default attribute specified, and there is no other text track in the media
-    // element's list of text tracks whose text track mode is showing or showing by default
-    //    Let the text track mode be showing by default.
-    
-    // Otherwise
-    //    Let the text track mode be disabled.
-    
-    // FIXME(71123): Until the above logic has been implemented, just tell all text tracks to load.
-    for (Node* node = firstChild(); node; node = node->nextSibling()) {
-        if (node->hasTagName(trackTag))
-            static_cast<HTMLTrackElement*>(node)->scheduleLoad();
-    }
-}
-
 TextTrackList* HTMLMediaElement::textTracks() 
 {
     if (!RuntimeEnabledFeatures::webkitVideoTrackEnabled())
@@ -2165,18 +2204,31 @@ TextTrackList* HTMLMediaElement::textTracks()
     return m_textTracks.get();
 }
 
+HTMLTrackElement* HTMLMediaElement::showingTrackWithSameKind(HTMLTrackElement* trackElement) const
+{
+    HTMLTrackElement* showingTrack = 0;
+    
+    for (Node* node = firstChild(); node; node = node->nextSibling()) {
+        if (trackElement == node)
+            continue;
+        if (!node->hasTagName(trackTag))
+            continue;
+
+        showingTrack = static_cast<HTMLTrackElement*>(node);
+        if (showingTrack->kind() == trackElement->kind() && showingTrack->track()->mode() == TextTrack::SHOWING)
+            return showingTrack;
+    }
+    
+    return 0;
+}
+
 void HTMLMediaElement::trackWasAdded(HTMLTrackElement* trackElement)
 {
+    ASSERT(trackElement->hasTagName(trackTag));
+
     if (!RuntimeEnabledFeatures::webkitVideoTrackEnabled())
         return;
 
-#if !LOG_DISABLED
-    if (trackElement->hasTagName(trackTag)) {
-        KURL url = trackElement->getNonEmptyURLAttribute(srcAttr);
-        LOG(Media, "HTMLMediaElement::trackWasAdded - 'src' is %s", urlForLogging(url).utf8().data());
-    }
-#endif
-
     // 4.8.10.12.3 Sourcing out-of-band text tracks
     // When a track element's parent element changes and the new parent is a media element, 
     // then the user agent must add the track element's corresponding text track to the 
@@ -2184,12 +2236,19 @@ void HTMLMediaElement::trackWasAdded(HTMLTrackElement* trackElement)
     RefPtr<TextTrack> textTrack = trackElement->track();
     if (!textTrack)
         return;
-    addTextTrack(textTrack);    
-    scheduleLoad(TextTrackResource);
+    
+    textTracks()->append(textTrack);
+    
+    // Do not schedule the track loading until parsing finishes so we don't start before all tracks
+    // in the markup have been added.
+    if (!m_parsingInProgress)
+        scheduleLoad(TextTrackResource);
 }
+
 void HTMLMediaElement::trackWillBeRemoved(HTMLTrackElement* trackElement)
 {
+    ASSERT(trackElement->hasTagName(trackTag));
+
     if (!RuntimeEnabledFeatures::webkitVideoTrackEnabled())
         return;
 
@@ -2200,6 +2259,8 @@ void HTMLMediaElement::trackWillBeRemoved(HTMLTrackElement* trackElement)
     }
 #endif
 
+    trackElement->setHasBeenConfigured(false);
+
     RefPtr<TextTrack> textTrack = trackElement->track();
     if (!textTrack)
         return;
@@ -2209,7 +2270,142 @@ void HTMLMediaElement::trackWillBeRemoved(HTMLTrackElement* trackElement)
     // then the user agent must remove the track element's corresponding text track from the 
     // media element's list of text tracks.
     m_textTracks->remove(textTrack.get());
+    size_t index = m_textTracksWhenResourceSelectionBegan.find(textTrack.get());
+    if (index != notFound)
+        m_textTracksWhenResourceSelectionBegan.remove(index);
+}
+
+bool HTMLMediaElement::userIsInterestedInThisLanguage(const String&) const
+{
+    // FIXME: check the user's language preference - bugs.webkit.org/show_bug.cgi?id=74121
+    return true;
+}
+
+bool HTMLMediaElement::userIsInterestedInThisTrack(HTMLTrackElement* trackElement) const
+{
+    RefPtr<TextTrack> textTrack = trackElement->track();
+    if (!textTrack)
+        return false;
+
+    String kind = textTrack->kind();
+    if (!TextTrack::isValidKindKeyword(kind))
+        return false;
+
+    // If ... the user has indicated an interest in having a track with this text track kind, text track language, ... 
+    Settings* settings = document()->settings();
+
+    if (kind == TextTrack::subtitlesKeyword() || kind == TextTrack::captionsKeyword()) {
+        if (!settings)
+            return false;
+        if (kind == TextTrack::subtitlesKeyword() && !settings->shouldDisplaySubtitles())
+            return false;
+        if (kind == TextTrack::captionsKeyword() && !settings->shouldDisplayCaptions())
+            return false;
+        return userIsInterestedInThisLanguage(trackElement->srclang());
+    }
+
+    if (kind == TextTrack::descriptionsKeyword()) {
+        if (!settings || !settings->shouldDisplayTextDescriptions())
+            return false;
+        return userIsInterestedInThisLanguage(trackElement->srclang());
+    }
+    
+    return false;
 }
+
+void HTMLMediaElement::configureTextTrack(HTMLTrackElement* trackElement)
+{
+#if !LOG_DISABLED
+    if (trackElement->hasTagName(trackTag)) {
+        KURL url = trackElement->getNonEmptyURLAttribute(srcAttr);
+        LOG(Media, "HTMLMediaElement::configureTextTrack - 'src' is %s", urlForLogging(url).utf8().data());
+    }
+#endif
+
+    // 4.8.10.12.3 Sourcing out-of-band text tracks
+    
+    // When a text track corresponding to a track element is added to a media element's list of text tracks,
+    // the user agent must set the text track mode appropriately, as determined by the following conditions:
+    RefPtr<TextTrack> textTrack = trackElement->track();
+    if (!textTrack)
+        return;
+    
+    TextTrack::Mode mode = TextTrack::HIDDEN;
+    HTMLTrackElement* trackElementCurrentlyShowing = showingTrackWithSameKind(trackElement);
+    String kind = textTrack->kind();
+    bool hideDefaultTrack = false;
+
+    if (userIsInterestedInThisTrack(trackElement)) {
+        if (kind == TextTrack::subtitlesKeyword() || kind == TextTrack::captionsKeyword()) {
+            // * If the text track kind is subtitles or captions and the user has indicated an interest in having a
+            // track with this text track kind, text track language, and text track label enabled, and there is no
+            // other text track in the media element's list of text tracks with a text track kind of either subtitles
+            // or captions whose text track mode is showing
+            hideDefaultTrack = trackElementCurrentlyShowing && trackElementCurrentlyShowing->track()->showingByDefault();
+            if (!trackElementCurrentlyShowing || hideDefaultTrack) {
+                //    Let the text track mode be showing.
+                //    If there is a text track in the media element's list of text tracks whose text track mode is showing 
+                //    by default, the user agent must furthermore change that text track's text track mode to hidden.
+                mode = TextTrack::SHOWING;
+            }
+        } else if (kind == TextTrack::descriptionsKeyword()) {
+            // * If the text track kind is descriptions and the user has indicated an interest in having text 
+            // descriptions with this text track language and text track label enabled, and there is no other text 
+            // track in the media element's list of text tracks with a text track kind of descriptions whose text 
+            // track mode is showing
+            hideDefaultTrack = trackElementCurrentlyShowing && trackElementCurrentlyShowing->track()->showingByDefault();
+            if (!trackElementCurrentlyShowing || hideDefaultTrack) {
+                //    Let the text track mode be showing.
+                //    If there is a text track in the media element's list of text tracks whose text track mode is showing 
+                //    by default, the user agent must furthermore change that text track's text track mode to hidden.
+                mode = TextTrack::SHOWING;
+            }
+        } else if (kind == TextTrack::chaptersKeyword()) {
+            // * If the text track kind is chapters and the text track language is one that the user agent has reason
+            // to believe is appropriate for the user, and there is no other text track in the media element's list of
+            // text tracks with a text track kind of chapters whose text track mode is showing
+            //    Let the text track mode be showing.
+            if (!trackElementCurrentlyShowing)
+                mode = TextTrack::SHOWING;
+        }
+    } else if (!trackElementCurrentlyShowing && trackElement->isDefault()) {
+        // * If the track element has a default attribute specified, and there is no other text track in the media
+        // element's list of text tracks whose text track mode is showing or showing by default
+        //    Let the text track mode be showing by default.
+        mode = TextTrack::SHOWING;
+        textTrack->setShowingByDefault(false);
+    } else {
+        // Otherwise
+        //    Let the text track mode be disabled.
+        mode = TextTrack::DISABLED;
+    }
+
+    ExceptionCode unusedException;
+    if (hideDefaultTrack) {
+        trackElementCurrentlyShowing->track()->setMode(TextTrack::HIDDEN, unusedException);
+        trackElementCurrentlyShowing->track()->setShowingByDefault(false);
+    }
+
+    textTrack->setMode(mode, unusedException);
+}
+void HTMLMediaElement::configureTextTracks()
+{
+    for (Node* node = firstChild(); node; node = node->nextSibling()) {
+        if (!node->hasTagName(trackTag))
+            continue;
+        HTMLTrackElement* trackElement = static_cast<HTMLTrackElement*>(node);
+        
+        // Only call configureTextTrack once per track so that adding another track after
+        // the initial configuration doesn't reconfigure every track, only those that should
+        // be changed by the new addition. For example all metadata tracks are disabled by 
+        // default, and we don't want a track that has been enabled by script to be disabled
+        // automatically when a new track element is added later.
+        if (!trackElement->hasBeenConfigured())
+            configureTextTrack(trackElement);
+    }
+}
+
 #endif
 
 bool HTMLMediaElement::havePotentialSourceChild()
@@ -3002,13 +3198,6 @@ void HTMLMediaElement::getPluginProxyParams(KURL& url, Vector<String>& names, Ve
     }
 }
 
-void HTMLMediaElement::finishParsingChildren()
-{
-    HTMLElement::finishParsingChildren();
-    document()->updateStyleIfNeeded();
-    createMediaPlayerProxy();
-}
-
 void HTMLMediaElement::createMediaPlayerProxy()
 {
     ensureMediaPlayer();
index 4b3698b..7d3fabd 100644 (file)
@@ -197,10 +197,12 @@ public:
 
     TextTrackList* textTracks();
 
-    void addTextTrack(PassRefPtr<TextTrack>);
-
     virtual void trackWasAdded(HTMLTrackElement*);
     virtual void trackWillBeRemoved(HTMLTrackElement*);
+    
+    void configureTextTrack(HTMLTrackElement*);
+    void configureTextTracks();
+    bool textTracksAreReady() const;
 
     // TextTrackClient
     virtual void textTrackReadyStateChanged(TextTrack*);
@@ -218,7 +220,6 @@ public:
     void deliverNotification(MediaPlayerProxyNotificationType notification);
     void setMediaPlayerProxy(WebMediaPlayerProxy* proxy);
     void getPluginProxyParams(KURL& url, Vector<String>& names, Vector<String>& values);
-    virtual void finishParsingChildren();
     void createMediaPlayerProxy();
     void updateWidget(PluginCreationOption);
 #endif
@@ -266,10 +267,11 @@ public:
     void setController(PassRefPtr<MediaController>);
 
 protected:
-    HTMLMediaElement(const QualifiedName&, Document*);
+    HTMLMediaElement(const QualifiedName&, Document*, bool);
     virtual ~HTMLMediaElement();
 
     virtual void parseMappedAttribute(Attribute*);
+    virtual void finishParsingChildren();
     virtual bool isURLAttribute(Attribute*) const;
     virtual void attach();
 
@@ -388,8 +390,10 @@ private:
     void mediaLoadingFailed(MediaPlayer::NetworkState);
 
 #if ENABLE(VIDEO_TRACK)
-    void configureTextTracks();
     void updateActiveTextTrackCues(float);
+    bool userIsInterestedInThisLanguage(const String&) const;
+    bool userIsInterestedInThisTrack(HTMLTrackElement*) const;
+    HTMLTrackElement* showingTrackWithSameKind(HTMLTrackElement*) const;
 #endif
 
     // These "internal" functions do not check user gesture restrictions.
@@ -541,22 +545,25 @@ private:
     bool m_loadInitiatedByUserGesture : 1;
     bool m_completelyLoaded : 1;
     bool m_havePreparedToPlay : 1;
-
-#if ENABLE(WEB_AUDIO)
-    // This is a weak reference, since m_audioSourceNode holds a reference to us.
-    // The value is set just after the MediaElementAudioSourceNode is created.
-    // The value is cleared in MediaElementAudioSourceNode::~MediaElementAudioSourceNode().
-    MediaElementAudioSourceNode* m_audioSourceNode;
-#endif
+    bool m_parsingInProgress : 1;
 
 #if ENABLE(VIDEO_TRACK)
+    bool m_tracksAreReady : 1;
     RefPtr<TextTrackList> m_textTracks;
+    Vector<RefPtr<TextTrack> > m_textTracksWhenResourceSelectionBegan;
     
     typedef PODIntervalTree <double, TextTrackCue*> CueIntervalTree;
     CueIntervalTree m_cueTree;
     Vector<CueIntervalTree::IntervalType> m_currentlyVisibleCues;
 #endif
 
+#if ENABLE(WEB_AUDIO)
+    // This is a weak reference, since m_audioSourceNode holds a reference to us.
+    // The value is set just after the MediaElementAudioSourceNode is created.
+    // The value is cleared in MediaElementAudioSourceNode::~MediaElementAudioSourceNode().
+    MediaElementAudioSourceNode* m_audioSourceNode;
+#endif
+
     String m_mediaGroup;
     friend class MediaController;
     RefPtr<MediaController> m_mediaController;
index baa805a..f1c30a0 100644 (file)
@@ -11,7 +11,7 @@ applet
 area
 article interfaceName=HTMLElement
 aside interfaceName=HTMLElement
-audio wrapperOnlyIfMediaIsAvailable, conditional=VIDEO
+audio wrapperOnlyIfMediaIsAvailable, conditional=VIDEO, constructorNeedsCreatedByParser
 b interfaceName=HTMLElement
 base
 basefont interfaceName=HTMLBaseFontElement
@@ -129,7 +129,7 @@ tt interfaceName=HTMLElement
 u interfaceName=HTMLElement
 ul interfaceName=HTMLUListElement
 var interfaceName=HTMLElement
-video wrapperOnlyIfMediaIsAvailable, conditional=VIDEO
+video wrapperOnlyIfMediaIsAvailable, conditional=VIDEO, constructorNeedsCreatedByParser
 wbr interfaceName=HTMLElement
 xmp interfaceName=HTMLPreElement
 noscript interfaceName=HTMLElement
index d1ccf76..13a77a8 100644 (file)
@@ -55,6 +55,7 @@ static String urlForLogging(const KURL& url)
     
 inline HTMLTrackElement::HTMLTrackElement(const QualifiedName& tagName, Document* document)
     : HTMLElement(tagName, document)
+    , m_hasBeenConfigured(false)
 {
     LOG(Media, "HTMLTrackElement::HTMLTrackElement - %p", this);
     ASSERT(hasTagName(trackTag));
index b289fc4..86d2aec 100644 (file)
@@ -68,6 +68,9 @@ public:
 
     const AtomicString& mediaElementCrossOriginAttribute() const;
 
+    bool hasBeenConfigured() const { return m_hasBeenConfigured; }
+    void setHasBeenConfigured(bool flag) { m_hasBeenConfigured = flag; }
+
 private:
     HTMLTrackElement(const QualifiedName&, Document*);
     virtual ~HTMLTrackElement();
@@ -98,6 +101,7 @@ private:
     virtual bool canLoadUrl(const KURL&);
 
     RefPtr<LoadableTextTrack> m_track;
+    bool m_hasBeenConfigured;
 };
 
 }
index 3107d15..3dec562 100644 (file)
@@ -46,15 +46,15 @@ namespace WebCore {
 
 using namespace HTMLNames;
 
-inline HTMLVideoElement::HTMLVideoElement(const QualifiedName& tagName, Document* document)
-    : HTMLMediaElement(tagName, document)
+inline HTMLVideoElement::HTMLVideoElement(const QualifiedName& tagName, Document* document, bool createdByParser)
+    : HTMLMediaElement(tagName, document, createdByParser)
 {
     ASSERT(hasTagName(videoTag));
 }
 
-PassRefPtr<HTMLVideoElement> HTMLVideoElement::create(const QualifiedName& tagName, Document* document)
+PassRefPtr<HTMLVideoElement> HTMLVideoElement::create(const QualifiedName& tagName, Document* document, bool createdByParser)
 {
-    return adoptRef(new HTMLVideoElement(tagName, document));
+    return adoptRef(new HTMLVideoElement(tagName, document, createdByParser));
 }
 
 bool HTMLVideoElement::rendererIsNeeded(const NodeRenderingContext& context) 
index 82d0659..4918032 100644 (file)
@@ -36,7 +36,7 @@ class HTMLImageLoader;
 
 class HTMLVideoElement : public HTMLMediaElement {
 public:
-    static PassRefPtr<HTMLVideoElement> create(const QualifiedName&, Document*);
+    static PassRefPtr<HTMLVideoElement> create(const QualifiedName&, Document*, bool);
 
     unsigned width() const;
     unsigned height() const;
@@ -67,7 +67,7 @@ public:
     bool shouldDisplayPosterImage() const { return displayMode() == Poster || displayMode() == PosterWaitingForVideo; }
 
 private:
-    HTMLVideoElement(const QualifiedName&, Document*);
+    HTMLVideoElement(const QualifiedName&, Document*, bool);
 
     virtual bool rendererIsNeeded(const NodeRenderingContext&);
 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
index acbe53c..164fe33 100644 (file)
@@ -77,10 +77,11 @@ TextTrack::TextTrack(ScriptExecutionContext* context, TextTrackClient* client, c
     , m_mediaElement(0)
     , m_label(label)
     , m_language(language)
-    , m_mode(TextTrack::HIDDEN)
+    , m_mode(TextTrack::DISABLED)
     , m_client(client)
     , m_trackType(type)
     , m_readinessState(NotLoaded)
+    , m_showingByDefault(false)
 {
     setKind(kind);
 }
@@ -125,12 +126,31 @@ void TextTrack::setMode(unsigned short mode, ExceptionCode& ec)
 {
     // 4.8.10.12.5 On setting the mode, if the new value is not either 0, 1, or 2,
     // the user agent must throw an INVALID_ACCESS_ERR exception.
-    if (mode == TextTrack::DISABLED || mode == TextTrack::HIDDEN || mode == TextTrack::SHOWING) {
-        m_mode = static_cast<Mode>(mode);
-        if (m_client)
-            m_client->textTrackModeChanged(this);
-    } else
+    if (mode > TextTrack::SHOWING) {
         ec = INVALID_ACCESS_ERR;
+        return;
+    }
+
+    if (m_mode == static_cast<Mode>(mode))
+        return;
+
+    // If the new value is 2
+    //  ... Note: If the mode had been showing by default, this will change it to showing, 
+    // even though the value of mode would appear not to change.
+    m_mode = static_cast<Mode>(mode);
+    if (m_mode == TextTrack::SHOWING)
+        setShowingByDefault(false);
+
+    if (m_client)
+        m_client->textTrackModeChanged(this);
+}
+
+TextTrack::Mode TextTrack::mode() const
+{
+    // The text track "showing" and "showing by default" modes return SHOWING (numeric value 2)
+    if (m_showingByDefault)
+        return SHOWING;
+    return m_mode;
 }
 
 TextTrackCueList* TextTrack::cues()
index 533e3ba..9d69d59 100644 (file)
@@ -80,9 +80,12 @@ public:
     void setLanguage(const String& language) { m_language = language; }
 
     enum Mode { DISABLED = 0, HIDDEN = 1, SHOWING = 2 };
-    Mode mode() const { return m_mode; }
+    Mode mode() const;
     void setMode(unsigned short, ExceptionCode&);
 
+    bool showingByDefault() const { return m_showingByDefault; }
+    void setShowingByDefault(bool showing) { m_showingByDefault = showing; }
+
     enum ReadinessState { NotLoaded = 0, Loading = 1, Loaded = 2, FailedToLoad = 3 };
     ReadinessState readinessState() const { return m_readinessState; }
     void setReadinessState(ReadinessState state) { m_readinessState = state; }
@@ -116,6 +119,7 @@ private:
     TextTrackClient* m_client;
     TextTrackType m_trackType;
     ReadinessState m_readinessState;
+    bool m_showingByDefault;
 };
 
 } // namespace WebCore
index c57909b..55519e5 100644 (file)
@@ -139,13 +139,17 @@ void TextTrackCue::setCueHTML(PassRefPtr<DocumentFragment> fragment)
 
 bool TextTrackCue::isActive()
 {
-    return m_isActive;
+    return m_isActive && track() && track()->mode() != TextTrack::DISABLED;
 }
 
 void TextTrackCue::setIsActive(bool active)
 {
     m_isActive = active;
 
+    // When a TextTrack's mode is disabled: No cues are active, no events are fired ...
+    if (!track() || track()->mode() == TextTrack::DISABLED)
+        return;
+
     ExceptionCode ec = 0;
     if (active)
         dispatchEvent(Event::create(eventNames().enterEvent, false, false), ec);