Implement addCue and removeCue in TextTrack
authoreric.carlson@apple.com <eric.carlson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 26 Nov 2011 04:28:39 +0000 (04:28 +0000)
committereric.carlson@apple.com <eric.carlson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 26 Nov 2011 04:28:39 +0000 (04:28 +0000)
https://bugs.webkit.org/show_bug.cgi?id=72554

Reviewed by Darin Adler.

Source/WebCore:

Test: media/track/track-add-remove-cue.html

* html/HTMLTrackElement.cpp:
(WebCore::HTMLTrackElement::ensureTrack): Go ahead and allocate a Track even if the feature
    is disabled, it just won't load anything.
(WebCore::HTMLTrackElement::scheduleLoad): Early return if the featue is disabled.
(WebCore::HTMLTrackElement::canLoadUrl): Ditto.

* html/LoadableTextTrack.cpp:
(WebCore::LoadableTextTrack::newCuesAvailable): Add new cues one at a time because
    cues->add(Vector<TextTrackCue*>&) is gone.

* html/TextTrack.cpp:
(WebCore::TextTrack::addCue): Implement.
(WebCore::TextTrack::removeCue): Ditto.
* html/TextTrack.h:

(WebCore::TextTrackCue::TextTrackCue): Initialize every member variable.
(WebCore::TextTrackCue::track): m_track is now a RefPtr.
(WebCore::TextTrackCue::setTrack): Ditto.
* html/TextTrackCue.h:

* html/TextTrackCueList.cpp:
(WebCore::TextTrackCueList::add): Don't ignore out of order cues, the spec text is not
    a conformance requirement. Return bool to indicate success or failure.
(WebCore::TextTrackCueList::remove): Return bool to indicate success or failure.
* html/TextTrackCueList.h:

* loader/TextTrackLoader.cpp:
(WebCore::TextTrackLoader::notifyFinished): Don't change m_state once it is set to Failed.

LayoutTests:

* media/track/track-add-remove-cue-expected.txt: Added.
* media/track/track-add-remove-cue.html: Added.
* media/track/track-webvtt-tc012-out-of-order-expected.txt: Removed.
* media/track/track-webvtt-tc012-out-of-order.html: Removed.

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

15 files changed:
LayoutTests/ChangeLog
LayoutTests/media/track/track-add-remove-cue-expected.txt [new file with mode: 0644]
LayoutTests/media/track/track-add-remove-cue.html [new file with mode: 0644]
LayoutTests/media/track/track-webvtt-tc012-out-of-order-expected.txt [deleted file]
LayoutTests/media/track/track-webvtt-tc012-out-of-order.html [deleted file]
Source/WebCore/ChangeLog
Source/WebCore/html/HTMLTrackElement.cpp
Source/WebCore/html/LoadableTextTrack.cpp
Source/WebCore/html/TextTrack.cpp
Source/WebCore/html/TextTrack.h
Source/WebCore/html/TextTrackCue.cpp
Source/WebCore/html/TextTrackCue.h
Source/WebCore/html/TextTrackCueList.cpp
Source/WebCore/html/TextTrackCueList.h
Source/WebCore/loader/TextTrackLoader.cpp

index 9dd6a74..7040d87 100644 (file)
@@ -1,3 +1,15 @@
+2011-11-25  Eric Carlson  <eric.carlson@apple.com>
+
+        Implement addCue and removeCue in TextTrack
+        https://bugs.webkit.org/show_bug.cgi?id=72554
+
+        Reviewed by Darin Adler.
+
+        * media/track/track-add-remove-cue-expected.txt: Added.
+        * media/track/track-add-remove-cue.html: Added.
+        * media/track/track-webvtt-tc012-out-of-order-expected.txt: Removed.
+        * media/track/track-webvtt-tc012-out-of-order.html: Removed.
+
 2011-11-25  Kentaro Hara  <haraken@chromium.org>
 
         Implement the WebGLContextEvent constructor
diff --git a/LayoutTests/media/track/track-add-remove-cue-expected.txt b/LayoutTests/media/track/track-add-remove-cue-expected.txt
new file mode 100644 (file)
index 0000000..884e70f
--- /dev/null
@@ -0,0 +1,49 @@
+Tests TextTrackCue's addCue and removeCue
+
+
+*** Test cues loaded from the file.
+EXPECTED (cues.length == '4') OK
+EXPECTED (cues.getCueById('1').startTime == '0') OK
+EXPECTED (cues[1].startTime == '31') OK
+EXPECTED (cues[2].startTime == '61') OK
+EXPECTED (cues.getCueById('4').startTime == '121') OK
+EXPECTED (cues.getCueById('junk') == 'undefined') OK
+
+*** Create a new cue, check values
+RUN(textCue = new TextTrackCue('sausage-cue', 33, 3.4, 'Sausage?'))
+EXPECTED (textCue.track == 'null') OK
+EXPECTED (textCue.id == 'sausage-cue') OK
+EXPECTED (textCue.startTime == '33') OK
+EXPECTED (textCue.endTime == '3.4') OK
+EXPECTED (textCue.pauseOnExit == 'false') OK
+EXPECTED (textCue.direction == 'horizontal') OK
+EXPECTED (textCue.snapToLines == 'true') OK
+EXPECTED (textCue.linePosition == '-1') OK
+EXPECTED (textCue.textPosition == '50') OK
+EXPECTED (textCue.size == '100') OK
+EXPECTED (textCue.alignment == 'middle') OK
+
+*** Add the new cue to a track, make sure it is inserted correctly.
+RUN(testTrack.track.addCue(textCue))
+EXPECTED (textCue.track == '[object TextTrack]') OK
+EXPECTED (cues[1].startTime == '31') OK
+EXPECTED (cues[2].startTime == '33') OK
+EXPECTED (cues[3].startTime == '61') OK
+
+*** Remove a cue created with addCue().
+RUN(testTrack.track.removeCue(textCue))
+EXPECTED (textCue.track == 'null') OK
+EXPECTED (cues[1].startTime == '31') OK
+EXPECTED (cues[2].startTime == '61') OK
+
+*** Remove a cue added from the WebVTT file.
+RUN(textCue = cues[2])
+RUN(testTrack.track.removeCue(textCue))
+EXPECTED (textCue.track == 'null') OK
+EXPECTED (cues[1].startTime == '31') OK
+EXPECTED (cues[2].startTime == '121') OK
+
+*** Try to remove the cue again.
+TEST(testTrack.track.removeCue(textCue)) THROWS(DOMException.INVALID_STATE_ERR) OK
+END OF TEST
+
diff --git a/LayoutTests/media/track/track-add-remove-cue.html b/LayoutTests/media/track/track-add-remove-cue.html
new file mode 100644 (file)
index 0000000..c615c91
--- /dev/null
@@ -0,0 +1,73 @@
+<!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>           
+
+            var cues;
+
+            function trackLoaded()
+            {
+                var testTrack = document.getElementById('testTrack');
+                cues = testTrack.track.cues;
+
+                consoleWrite("<br>*** Test cues loaded from the file.");
+                testExpected("cues.length", 4);
+                testExpected("cues.getCueById('1').startTime", 0);
+                testExpected("cues[1].startTime", 31);
+                testExpected("cues[2].startTime", 61);
+                testExpected("cues.getCueById('4').startTime", 121);
+                testExpected("cues.getCueById('junk')", undefined);
+
+                consoleWrite("<br>*** Create a new cue, check values");
+                run("textCue = new TextTrackCue('sausage-cue', 33, 3.4, 'Sausage?')");
+                testExpected("textCue.track", null);
+                testExpected("textCue.id", "sausage-cue");
+                testExpected("textCue.startTime", 33);
+                testExpected("textCue.endTime", 3.4);
+                testExpected("textCue.pauseOnExit", false);
+                testExpected("textCue.direction", "horizontal");
+                testExpected("textCue.snapToLines", true);
+                testExpected("textCue.linePosition", -1);
+                testExpected("textCue.textPosition", 50);
+                testExpected("textCue.size", 100);
+                testExpected("textCue.alignment", "middle");
+
+                consoleWrite("<br>*** Add the new cue to a track, make sure it is inserted correctly.");
+                run("testTrack.track.addCue(textCue)");
+                testExpected("textCue.track", testTrack.track);
+                testExpected("cues[1].startTime", 31);
+                testExpected("cues[2].startTime", 33);
+                testExpected("cues[3].startTime", 61);
+
+                consoleWrite("<br>*** Remove a cue created with addCue().");
+                run("testTrack.track.removeCue(textCue)");
+                testExpected("textCue.track", null);
+                testExpected("cues[1].startTime", 31);
+                testExpected("cues[2].startTime", 61);
+
+                consoleWrite("<br>*** Remove a cue added from the WebVTT file.");
+                run("textCue = cues[2]");
+                run("testTrack.track.removeCue(textCue)");
+                testExpected("textCue.track", null);
+                testExpected("cues[1].startTime", 31);
+                testExpected("cues[2].startTime", 121);
+
+                consoleWrite("<br>*** Try to remove the cue again.");
+                testException("testTrack.track.removeCue(textCue)", "DOMException.INVALID_STATE_ERR");
+
+                endTest();
+            }
+
+        </script>
+    </head>
+    <body>
+        <p>Tests TextTrackCue's addCue and removeCue</p>
+        <video>
+            <track id="testTrack" src="captions-webvtt/tc013-settings.vtt" kind="captions" onload="trackLoaded()">
+        </video>
+    </body>
+</html>
diff --git a/LayoutTests/media/track/track-webvtt-tc012-out-of-order-expected.txt b/LayoutTests/media/track/track-webvtt-tc012-out-of-order-expected.txt
deleted file mode 100644 (file)
index a253cc5..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Tests that cues that are temporally out of order are ignored.
-
-
-*** Testing text track 0
-EXPECTED (cues.length == '2') OK
-END OF TEST
-
diff --git a/LayoutTests/media/track/track-webvtt-tc012-out-of-order.html b/LayoutTests/media/track/track-webvtt-tc012-out-of-order.html
deleted file mode 100644 (file)
index b1453a2..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-<!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()
-            {
-                findMediaElement();
-                var expected = 
-                {
-                    length : 2,
-                    tests:
-                    [],
-                };
-                testCues(0, expected);
-                
-                endTest();
-            }
-
-        </script>
-    </head>
-    <body>
-    <p>Tests that cues that are temporally out of order are ignored.</p>
-        <video>
-            <track src="captions-webvtt/tc012-out-of-order.vtt" onload="trackLoaded()">
-        </video>
-    </body>
-</html>
\ No newline at end of file
index 005bc0b..4f5818c 100644 (file)
@@ -1,3 +1,41 @@
+2011-11-25  Eric Carlson  <eric.carlson@apple.com>
+
+        Implement addCue and removeCue in TextTrack
+        https://bugs.webkit.org/show_bug.cgi?id=72554
+
+        Reviewed by Darin Adler.
+
+        Test: media/track/track-add-remove-cue.html
+
+        * html/HTMLTrackElement.cpp:
+        (WebCore::HTMLTrackElement::ensureTrack): Go ahead and allocate a Track even if the feature 
+            is disabled, it just won't load anything.
+        (WebCore::HTMLTrackElement::scheduleLoad): Early return if the featue is disabled.
+        (WebCore::HTMLTrackElement::canLoadUrl): Ditto.
+
+        * html/LoadableTextTrack.cpp:
+        (WebCore::LoadableTextTrack::newCuesAvailable): Add new cues one at a time because 
+            cues->add(Vector<TextTrackCue*>&) is gone.
+
+        * html/TextTrack.cpp:
+        (WebCore::TextTrack::addCue): Implement.
+        (WebCore::TextTrack::removeCue): Ditto.
+        * html/TextTrack.h:
+
+        (WebCore::TextTrackCue::TextTrackCue): Initialize every member variable.
+        (WebCore::TextTrackCue::track): m_track is now a RefPtr.
+        (WebCore::TextTrackCue::setTrack): Ditto.
+        * html/TextTrackCue.h:
+
+        * html/TextTrackCueList.cpp:
+        (WebCore::TextTrackCueList::add): Don't ignore out of order cues, the spec text is not 
+            a conformance requirement. Return bool to indicate success or failure.
+        (WebCore::TextTrackCueList::remove): Return bool to indicate success or failure.
+        * html/TextTrackCueList.h:
+
+        * loader/TextTrackLoader.cpp:
+        (WebCore::TextTrackLoader::notifyFinished): Don't change m_state once it is set to Failed.
+
 2011-11-25  Kentaro Hara  <haraken@chromium.org>
 
         Refactoring CodeGenerator*.pm for bug 72138
index d9171a3..138b120 100644 (file)
@@ -158,9 +158,6 @@ void HTMLTrackElement::setIsDefault(bool isDefault)
 
 LoadableTextTrack* HTMLTrackElement::ensureTrack()
 {
-    if (!RuntimeEnabledFeatures::webkitVideoTrackEnabled())
-        return 0;
-
     if (!m_track) {
         // The kind attribute is an enumerated attribute, limited only to know values. It defaults to 'subtitles' if missing or invalid.
         String kind = getAttribute(kindAttr);
@@ -183,6 +180,9 @@ bool HTMLTrackElement::isURLAttribute(Attribute* attribute) const
 
 void HTMLTrackElement::scheduleLoad()
 {
+    if (!RuntimeEnabledFeatures::webkitVideoTrackEnabled())
+        return;
+
     if (!mediaElement())
         return;
 
@@ -194,6 +194,9 @@ void HTMLTrackElement::scheduleLoad()
 
 bool HTMLTrackElement::canLoadUrl(LoadableTextTrack*, const KURL& url)
 {
+    if (!RuntimeEnabledFeatures::webkitVideoTrackEnabled())
+        return false;
+
     HTMLMediaElement* parent = mediaElement();
     if (!parent)
         return false;
index 87ec56b..5953dcc 100644 (file)
@@ -85,12 +85,13 @@ void LoadableTextTrack::newCuesAvailable(TextTrackLoader* loader)
     Vector<RefPtr<TextTrackCue> > newCues;
     m_loader->getNewCues(newCues);
 
-    for (size_t i = 0; i < newCues.size(); ++i)
-        newCues[i]->setTrack(this);
-
     if (!m_cues)
         m_cues = TextTrackCueList::create();    
-    m_cues->add(newCues);
+
+    for (size_t i = 0; i < newCues.size(); ++i) {
+        newCues[i]->setTrack(this);
+        m_cues->add(newCues[i]);
+    }
 
     if (client())
         client()->textTrackAddCues(this, m_cues.get());
index 8d10bd7..d982fc1 100644 (file)
@@ -166,25 +166,69 @@ TextTrackCueList* TextTrack::activeCues() const
     return 0;
 }
 
-void TextTrack::addCue(PassRefPtr<TextTrackCue>, ExceptionCode&)
+void TextTrack::addCue(PassRefPtr<TextTrackCue> prpCue, ExceptionCode& ec)
 {
-    // FIXME(62890): Implement.
+    if (!prpCue)
+        return;
+
+    RefPtr<TextTrackCue> cue = prpCue;
+
+    // 4.8.10.12.4 Text track API
+
+    // The addCue(cue) method of TextTrack objects, when invoked, must run the following steps:
+
+    // 1. If the given cue is already associated with a text track other than 
+    // the method's TextTrack object's text track, then throw an InvalidStateError
+    // exception and abort these steps.
+    TextTrack* cueTrack = cue->track();
+    if (cueTrack && cueTrack != this) {
+        ec = INVALID_STATE_ERR;
+        return;
+    }
+
+    // 2. Associate cue with the method's TextTrack object's text track, if it is 
+    // not currently associated with a text track.
+    cue->setTrack(this);
+
+    // 3. If the given cue is already listed in the method's TextTrack object's text
+    // track's text track list of cues, then throw an InvalidStateError exception.
+    // 4. Add cue to the method's TextTrack object's text track's text track list of cues.
+    if (!m_cues->add(cue)) {
+        ec = INVALID_STATE_ERR;
+        return;
+    }
     
+    if (m_client)
+        m_client->textTrackAddCue(this, cue.get());
 }
 
-void TextTrack::removeCue(PassRefPtr<TextTrackCue>, ExceptionCode&)
+void TextTrack::removeCue(TextTrackCue* cue, ExceptionCode& ec)
 {
-    // FIXME(62890): Implement.
-}
+    if (!cue)
+        return;
 
-void TextTrack::newCuesLoaded()
-{
-    // FIXME(62890): Implement.
-}
+    // 4.8.10.12.4 Text track API
 
-void TextTrack::fetchNewestCues(Vector<TextTrackCue*>&)
-{
-    // FIXME(62890): Implement.
+    // The removeCue(cue) method of TextTrack objects, when invoked, must run the following steps:
+
+    // 1. If the given cue is not associated with the method's TextTrack 
+    // object's text track, then throw an InvalidStateError exception.
+    if (cue->track() != this) {
+        ec = INVALID_STATE_ERR;
+        return;
+    }
+    
+    // 2. If the given cue is not currently listed in the method's TextTrack 
+    // object's text track's text track list of cues, then throw a NotFoundError exception.
+    // 3. Remove cue from the method's TextTrack object's text track's text track list of cues.
+    if (!m_cues->remove(cue)) {
+        ec = INVALID_STATE_ERR;
+        return;
+    }
+
+    cue->setTrack(0);
+    if (m_client)
+        m_client->textTrackRemoveCue(this, cue);
 }
 
 void TextTrack::fireCueChangeEvent()
index 733660e..99845d1 100644 (file)
@@ -93,10 +93,7 @@ public:
     TextTrackClient* client() { return m_client; }
 
     void addCue(PassRefPtr<TextTrackCue>, ExceptionCode&);
-    void removeCue(PassRefPtr<TextTrackCue>, ExceptionCode&);
-    
-    void newCuesLoaded();
-    void fetchNewestCues(Vector<TextTrackCue*>&);
+    void removeCue(TextTrackCue*, ExceptionCode&);
     
     virtual void fireCueChangeEvent();
     DEFINE_ATTRIBUTE_EVENT_LISTENER(cuechange);
index c0fb075..c57909b 100644 (file)
@@ -47,15 +47,15 @@ TextTrackCue::TextTrackCue(ScriptExecutionContext* context, const String& id, do
     , m_startTime(start)
     , m_endTime(end)
     , m_content(content)
-    , m_pauseOnExit(pauseOnExit)
     , m_writingDirection(Horizontal)
-    , m_snapToLines(true)
     , m_linePosition(-1)
     , m_textPosition(50)
     , m_cueSize(100)
     , m_cueAlignment(Middle)
-    , m_isActive(false)
     , m_scriptExecutionContext(context)
+    , m_isActive(false)
+    , m_pauseOnExit(pauseOnExit)
+    , m_snapToLines(true)
 {
     parseSettings(settings);
 }
@@ -66,10 +66,10 @@ TextTrackCue::~TextTrackCue()
 
 TextTrack* TextTrackCue::track() const
 {
-    return m_track;
+    return m_track.get();
 }
 
-void TextTrackCue::setTrack(TextTrack* track)
+void TextTrackCue::setTrack(PassRefPtr<TextTrack>track)
 {
     m_track = track;
 }
index a647ce6..9480afa 100644 (file)
@@ -57,7 +57,7 @@ public:
     virtual ~TextTrackCue();
 
     TextTrack* track() const;
-    void setTrack(TextTrack*);
+    void setTrack(PassRefPtr<TextTrack>);
 
     String id() const;
     double startTime() const;
@@ -100,25 +100,24 @@ private:
     virtual void refEventTarget() { ref(); }
     virtual void derefEventTarget() { deref(); }
     
-    TextTrack* m_track;
-    
     String m_id;
     double m_startTime;
     double m_endTime;
     String m_content;
-    bool m_pauseOnExit;
     Direction m_writingDirection;
-    bool m_snapToLines;
     int m_linePosition;
     int m_textPosition;
     int m_cueSize;
     Alignment m_cueAlignment;
     RefPtr<DocumentFragment> m_documentFragment;
+    RefPtr<TextTrack> m_track;
 
-    bool m_isActive;
-    
     EventTargetData m_eventTargetData;
     ScriptExecutionContext* m_scriptExecutionContext;
+
+    bool m_isActive;
+    bool m_pauseOnExit;
+    bool m_snapToLines;
 };
 
 } // namespace WebCore
index 2ef6f3c..34b71ca 100644 (file)
@@ -70,52 +70,43 @@ TextTrackCueList* TextTrackCueList::activeCues()
     return m_activeCues.get();
 }
 
-void TextTrackCueList::add(const Vector<RefPtr<TextTrackCue> >& newCues)
+bool TextTrackCueList::add(PassRefPtr<TextTrackCue> cue)
 {
-    for (size_t i = 0; i < newCues.size(); ++i)
-        add(newCues[i]);
+    return add(cue, 0, m_list.size());
 }
 
-void TextTrackCueList::add(PassRefPtr<TextTrackCue> cue)
-{
-    // WebVTT cue timings
-    // 1. The time represented by this WebVTT timestamp must be greater than or equal
-    // to the start time offsets of all previous cues in the file.
-    // http://www.whatwg.org/specs/web-apps/current-work/#webvtt-cue-timings
-    // Note: because this requirement is specific to WebVTT, we may want to check first
-    // whether the cues in this list came from a WebVTT file.
-    if (!m_list.isEmpty() && cue->startTime() < m_list.last()->startTime())
-        return;
-    add(cue, 0, m_list.size());
-}
-
-void TextTrackCueList::add(PassRefPtr<TextTrackCue> cue, size_t start, size_t end)
+bool TextTrackCueList::add(PassRefPtr<TextTrackCue> prpCue, size_t start, size_t end)
 {
     ASSERT(start <= m_list.size());
     ASSERT(end <= m_list.size());
 
     // Maintain text track cue order:
     // http://www.whatwg.org/specs/web-apps/current-work/#text-track-cue-order
-    RefPtr<TextTrackCue> newCue = cue;
+    RefPtr<TextTrackCue> cue = prpCue;
     if (start == end) {
-       m_list.insert(start, newCue);
-       return;
+        if (!m_list.isEmpty() && (m_list[start - 1].get() == cue.get()))
+            return false;
+
+       m_list.insert(start, cue);
+       return true;
     }
 
     size_t index = (start + end) / 2;
-    if (newCue->startTime() < m_list[index]->startTime() || (newCue->startTime() == m_list[index]->startTime() && newCue->endTime() > m_list[index]->endTime()))
-        add(newCue.release(), start, index);
-    else
-        add(newCue.release(), index + 1, end);
+    if (cue->startTime() < m_list[index]->startTime() || (cue->startTime() == m_list[index]->startTime() && cue->endTime() > m_list[index]->endTime()))
+        return add(cue.release(), start, index);
+
+    return add(cue.release(), index + 1, end);
 }
 
-void TextTrackCueList::remove(TextTrackCue* cue)
+bool TextTrackCueList::remove(TextTrackCue* cue)
 {
     size_t index = m_list.find(cue);
     if (index == notFound)
-        return;
+        return false;
+
     cue->setIsActive(false);
     m_list.remove(index);
+    return true;
 }
 
 bool TextTrackCueList::contains(TextTrackCue* cue) const
index 774850c..7a7f904 100644 (file)
@@ -49,14 +49,13 @@ public:
     TextTrackCue* getCueById(const String&) const;
     TextTrackCueList* activeCues();
 
-    void add(PassRefPtr<TextTrackCue>);
-    void add(const Vector<RefPtr<TextTrackCue> >&);
-    void remove(TextTrackCue*);
+    bool add(PassRefPtr<TextTrackCue>);
+    bool remove(TextTrackCue*);
     bool contains(TextTrackCue*) const;
 
 private:
     TextTrackCueList();
-    void add(PassRefPtr<TextTrackCue>, size_t, size_t);
+    bool add(PassRefPtr<TextTrackCue>, size_t, size_t);
     void clear();
     
     Vector<RefPtr<TextTrackCue> > m_list;
index 2016062..564fe71 100644 (file)
@@ -145,7 +145,8 @@ void TextTrackLoader::notifyFinished(CachedResource* resource)
 
     processNewCueData(resource);
 
-    m_state = resource->errorOccurred() ? Failed : Finished;
+    if (m_state != Failed)
+        m_state = resource->errorOccurred() ? Failed : Finished;
 
     if (!m_cueLoadTimer.isActive())
         m_cueLoadTimer.startOneShot(0);