<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[70899] branches/chromium/552</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/70899">70899</a></dd>
<dt>Author</dt> <dd>jschuh@chromium.org</dd>
<dt>Date</dt> <dd>2010-10-29 10:47:35 -0700 (Fri, 29 Oct 2010)</dd>
</dl>

<h3>Log Message</h3>
<pre>Merge 70063 - 2010-10-19  Eric Carlson  &lt;eric.carlson@apple.com&gt;

        Reviewed by Darin Adler.

        https://bugs.webkit.org/show_bug.cgi?id=46763
        CRASH in WebCore::ThreadTimers::sharedTimerFiredInternal

        Fix crashes caused by moving and deleting &lt;source&gt; element(s) of active media element.

        Tests: media/video-source-moved.html
               media/video-source-removed.html

        * html/HTMLMediaElement.cpp:
        (WebCore::HTMLMediaElement::HTMLMediaElement): Add logging. Initialize selectNextSourceChild.
        (WebCore::HTMLMediaElement::~HTMLMediaElement): Ditto.
        (WebCore::HTMLMediaElement::insertedIntoDocument): Ditto.
        (WebCore::HTMLMediaElement::removedFromDocument): Ditto.
        (WebCore::HTMLMediaElement::scheduleLoad): Ditto.
        (WebCore::HTMLMediaElement::setNetworkState): Deal with m_currentSourceNode being null when
        the media engine signals a failure by skipping the error message and continuing as usual.
        (WebCore::HTMLMediaElement::setVolume): Fix logging typo.
        (WebCore::HTMLMediaElement::havePotentialSourceChild): Save and restore m_nextChildNodeToConsider
        around call to selectNextSourceChild because they are both significant.
        (WebCore::HTMLMediaElement::selectNextSourceChild): Use m_nextChildNodeToConsider to pick
        the first node to consider. Bail immediately if it signals that we have already processed 
        every &lt;source&gt; node. Stach the node following the current source element in m_nextChildNodeToConsider
        so we can resume the search even if m_currentSourceNode is removed while it is being processed.
        (WebCore::HTMLMediaElement::sourceWasAdded): New, move logic from HTMLSourceElement::insertedIntoTree
        here and correct it to deal with a &lt;source&gt; node being inserted immediately after the
        current &lt;source&gt; node and a new &lt;source&gt; node being inserted at the end of the list after
        all candidates have failed.
        (WebCore::HTMLMediaElement::sourceWillBeRemoved): New, deal with current source node and next
        potential node being removed.
        * html/HTMLMediaElement.h:
        (WebCore::HTMLMediaElement::sourceChildEndOfListValue): New, define sentinal value used to indicate
        that all nodes have been processed.

        * html/HTMLSourceElement.cpp:
        (WebCore::HTMLSourceElement::HTMLSourceElement): Add logging.
        (WebCore::HTMLSourceElement::insertedIntoTree): Call mediaElement-&gt;sourceWasAdded instead
        of having logic here.
        (WebCore::HTMLSourceElement::willRemove): New, call mediaElement-&gt;sourceWillBeRemoved
        (WebCore::HTMLSourceElement::scheduleErrorEvent): Add logging.
        (WebCore::HTMLSourceElement::cancelPendingErrorEvent): Add logging.
        * html/HTMLSourceElement.h:

2010-10-19  Eric Carlson  &lt;eric.carlson@apple.com&gt;

        Reviewed by Darin Adler.

        https://bugs.webkit.org/show_bug.cgi?id=46763
        CRASH in WebCore::ThreadTimers::sharedTimerFiredInternal

        Test moving and deleting &lt;source&gt; element(s) of active &lt;video&gt;.

        * media/media-file.js:
        (mimeTypeForExtension): New, added to make it possible to set 'type' attribute on &lt;source&gt;.

        * media/video-source-moved-expected.txt: Added.
        * media/video-source-moved.html: Added.
        * media/video-source-removed-expected.txt: Added.
        * media/video-source-removed.html: Added.


BUG=59593
TBR=jschuh@chromium.org</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#brancheschromium552LayoutTestsmediamediafilejs">branches/chromium/552/LayoutTests/media/media-file.js</a></li>
<li><a href="#brancheschromium552WebCorehtmlHTMLMediaElementcpp">branches/chromium/552/WebCore/html/HTMLMediaElement.cpp</a></li>
<li><a href="#brancheschromium552WebCorehtmlHTMLMediaElementh">branches/chromium/552/WebCore/html/HTMLMediaElement.h</a></li>
<li><a href="#brancheschromium552WebCorehtmlHTMLSourceElementcpp">branches/chromium/552/WebCore/html/HTMLSourceElement.cpp</a></li>
<li><a href="#brancheschromium552WebCorehtmlHTMLSourceElementh">branches/chromium/552/WebCore/html/HTMLSourceElement.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#brancheschromium552LayoutTestsmediavideosourcemovedexpectedtxt">branches/chromium/552/LayoutTests/media/video-source-moved-expected.txt</a></li>
<li><a href="#brancheschromium552LayoutTestsmediavideosourcemovedhtml">branches/chromium/552/LayoutTests/media/video-source-moved.html</a></li>
<li><a href="#brancheschromium552LayoutTestsmediavideosourceremovedexpectedtxt">branches/chromium/552/LayoutTests/media/video-source-removed-expected.txt</a></li>
<li><a href="#brancheschromium552LayoutTestsmediavideosourceremovedhtml">branches/chromium/552/LayoutTests/media/video-source-removed.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="brancheschromium552LayoutTestsmediamediafilejs"></a>
<div class="modfile"><h4>Modified: branches/chromium/552/LayoutTests/media/media-file.js (70898 => 70899)</h4>
<pre class="diff"><span>
<span class="info">--- branches/chromium/552/LayoutTests/media/media-file.js        2010-10-29 17:45:44 UTC (rev 70898)
+++ branches/chromium/552/LayoutTests/media/media-file.js        2010-10-29 17:47:35 UTC (rev 70899)
</span><span class="lines">@@ -31,6 +31,19 @@
</span><span class="cx">     return &quot;&quot;;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+function mimeTypeForExtension(extension) {
+    for (var i = 0; i &lt; videoCodecs.length; ++i) {
+        if (extension == videoCodecs[i][1])
+            return videoCodecs[i][0];
+    }
+    for (var i = 0; i &lt; audioCodecs.length; ++i) {
+        if (extension == audioCodecs[i][1])
+            return audioCodecs[i][0];
+    }
+
+    return &quot;&quot;;
+}
+
</ins><span class="cx"> function setSrcByTagName(tagName, src) {
</span><span class="cx">     var elements = document.getElementsByTagName(tagName);
</span><span class="cx">     if (elements) {
</span></span></pre></div>
<a id="brancheschromium552LayoutTestsmediavideosourcemovedexpectedtxtfromrev70063trunkLayoutTestsmediavideosourcemovedexpectedtxt"></a>
<div class="copfile"><h4>Copied: branches/chromium/552/LayoutTests/media/video-source-moved-expected.txt (from rev 70063, trunk/LayoutTests/media/video-source-moved-expected.txt) (0 => 70899)</h4>
<pre class="diff"><span>
<span class="info">--- branches/chromium/552/LayoutTests/media/video-source-moved-expected.txt                                (rev 0)
+++ branches/chromium/552/LayoutTests/media/video-source-moved-expected.txt        2010-10-29 17:47:35 UTC (rev 70899)
</span><span class="lines">@@ -0,0 +1,34 @@
</span><ins>+Test to make sure a &lt;source&gt; moved after the media element begins processing is handled correctly.
+
+Moving previous &lt;source&gt; element to end of list, it should be processed again.
+EXPECTED ([object HTMLSourceElement] != 'null') OK
+&lt;source&gt; moved was processed a second time. OK
+
+Moving current &lt;source&gt; element, it should be processed again.
+EXPECTED ([object HTMLSourceElement] != 'null') OK
+&lt;source&gt; moved was processed a second time. OK
+
+Moving next &lt;source&gt; element, it should be processed again.
+EXPECTED ([object HTMLSourceElement] != 'null') OK
+&lt;source&gt; moved was processed a second time. OK
+
+Moving current &lt;source&gt; element to beginning of list, it should not be processed again.
+EXPECTED ([object HTMLSourceElement] != 'null') OK
+&lt;source&gt; moved was not processed OK
+
+Moving next &lt;source&gt; element to beginning of list, it should never processed.
+EXPECTED ([object HTMLSourceElement] != 'null') OK
+&lt;source&gt; moved was not processed OK
+
+&lt;span&gt; inserted after current &lt;source&gt; element before it is removed, processing should proceed normally.
+EXPECTED ([object HTMLSourceElement] != 'null') OK
+&lt;source&gt; moved was not processed OK
+
+&lt;span&gt; inserted after next &lt;source&gt; element before it is removed, processing should proceed normally.
+EXPECTED ([object HTMLSourceElement] != 'null') OK
+&lt;source&gt; moved was not processed OK
+
+PASS
+
+END OF TEST
+
</ins></span></pre></div>
<a id="brancheschromium552LayoutTestsmediavideosourcemovedhtmlfromrev70063trunkLayoutTestsmediavideosourcemovedhtml"></a>
<div class="copfile"><h4>Copied: branches/chromium/552/LayoutTests/media/video-source-moved.html (from rev 70063, trunk/LayoutTests/media/video-source-moved.html) (0 => 70899)</h4>
<pre class="diff"><span>
<span class="info">--- branches/chromium/552/LayoutTests/media/video-source-moved.html                                (rev 0)
+++ branches/chromium/552/LayoutTests/media/video-source-moved.html        2010-10-29 17:47:35 UTC (rev 70899)
</span><span class="lines">@@ -0,0 +1,205 @@
</span><ins>+&lt;!doctype HTML&gt;
+&lt;html&gt;
+    &lt;head&gt;
+        &lt;title&gt;moving &amp;lt;source&amp;gt; element test&lt;/title&gt;
+        &lt;script src=video-test.js&gt;&lt;/script&gt;
+        &lt;script src=media-file.js&gt;&lt;/script&gt;
+        &lt;script&gt;
+
+            var testInfo = 
+            {
+                current : -1,
+                tests : 
+                [
+                    { fcn : moveToEnd, errorCount : 0, moved : null, done : false, iteration : 1},
+                    { fcn : moveToEnd, errorCount : 0, moved : null, done : false, iteration : 2},
+                    { fcn : moveToEnd, errorCount : 0, moved : null, done : false, iteration : 3},
+                    { fcn : moveEarlier, errorCount : 0, moved : null, iteration : 1 },
+                    { fcn : moveEarlier, errorCount : 0, moved : null, iteration : 2 },
+                    { fcn : moveEarlier, errorCount : 0, moved : null, iteration : 3 },
+                    { fcn : moveEarlier, errorCount : 0, moved : null, iteration : 4 }
+                ]
+            };
+
+            function findCurrentSourceElement()
+            {
+                var sources = video.getElementsByTagName('source');
+                var currentSrc = video.currentSrc;
+                var ndx;
+                for (ndx = 0; ndx &lt; sources.length; ++ndx) {
+                    if (sources[ndx].src == currentSrc)
+                        break;
+                }
+                if (ndx &gt;= sources.length) {
+                    failTest(currentSrc + &quot; not found in &amp;lt;source&amp;gt; list&quot;);
+                    return null;
+                }
+                return sources[ndx];
+            }
+
+            function moveEarlier(test, event)
+            {
+                if (test.done)
+                    return;
+
+                switch (++test.errorCount)
+                {
+                    case 1:
+                        // Do nothing on the first error event
+                        break;
+
+                    case 2:
+                        var current = findCurrentSourceElement();
+                        switch (test.iteration)
+                        {
+                            case 1:
+                                consoleWrite(&quot;Moving &lt;b&gt;current&lt;&quot; + &quot;/b&gt; &amp;lt;source&amp;gt; element to beginning of list, it should not be processed again.&quot;);
+                                test.moved = video.removeChild(current);
+                                break;
+                            case 2:
+                                consoleWrite(&quot;Moving &lt;b&gt;next&lt;&quot; + &quot;/b&gt; &amp;lt;source&amp;gt; element to beginning of list, it should never processed.&quot;);
+                                test.moved = video.removeChild(current.nextSibling);
+                                break;
+                            case 3:
+                                consoleWrite(&quot;&amp;lt;span&amp;gt; inserted after &lt;b&gt;current&lt;&quot; + &quot;/b&gt; &amp;lt;source&amp;gt; element before it is removed, processing should proceed normally.&quot;);
+                                var span = document.createElement(&quot;span&quot;)
+                                span.appendChild(document.createTextNode(&quot;Your browser doesn't support HTML5 video!&quot;));
+                                video.insertBefore(span, current.nextSibling);
+                                test.moved = video.removeChild(current);
+                                break;
+                            case 4:
+                                consoleWrite(&quot;&amp;lt;span&amp;gt; inserted after &lt;b&gt;next&lt;&quot; + &quot;/b&gt; &amp;lt;source&amp;gt; element before it is removed, processing should proceed normally.&quot;);
+                                var span = document.createElement(&quot;span&quot;)
+                                span.appendChild(document.createTextNode(&quot;Your browser doesn't support HTML5 video!&quot;));
+                                video.insertBefore(span, current.nextSibling.nextSibling);
+                                test.moved = video.removeChild(current.nextSibling);
+                                break;
+                            default:
+                                failTest(&quot;Malformed test data!&quot;);
+                                break;
+                        }
+
+                        testExpected(test.moved, null, '!=');
+                        video.insertBefore(test.moved, video.firstChild);
+                        break;
+
+                    default:
+                        // We should never get an error for the element we moved.
+                        if (event.target == test.moved) {
+                            failTest(&quot;Error fired for &amp;lt;source&amp;gt; moved to beginning of list.&quot;);
+                            test.done = true;
+                            return;
+                        } else if (!event.target.nextSibling) {
+                            logResult(true, &quot;&amp;lt;source&amp;gt; moved was not processed&quot;); 
+                            setTimeout(configureNextTest, 100);
+                        }
+                        break;
+                }
+            }
+
+            function moveToEnd(test, event)
+            {
+                switch (++test.errorCount)
+                {
+                    case 1:
+                        // Do nothing on the first error event
+                        break;
+
+                    case 2:
+                        var current = findCurrentSourceElement();
+                        switch (test.iteration)
+                        {
+                            case 1:
+                                consoleWrite(&quot;Moving &lt;b&gt;previous&lt;&quot; + &quot;/b&gt; &amp;lt;source&amp;gt; element to end of list, it should be processed again.&quot;);
+                                test.moved = video.removeChild(current.previousSibling);
+                                break;
+                            case 2:
+                                consoleWrite(&quot;Moving &lt;b&gt;current&lt;&quot; + &quot;/b&gt; &amp;lt;source&amp;gt; element, it should be processed again.&quot;);
+                                test.moved = video.removeChild(current);
+                                break;
+                            case 3:
+                                consoleWrite(&quot;Moving &lt;b&gt;next&lt;&quot; + &quot;/b&gt; &amp;lt;source&amp;gt; element, it should be processed again.&quot;);
+                                test.moved = video.removeChild(current.nextSibling);
+                                break;
+                            default:
+                                failTest(&quot;Malformed test data!&quot;);
+                                break;
+                        }
+
+                        testExpected(test.moved, null, '!=');
+                        video.appendChild(test.moved);
+                        break;
+
+                    default:
+                        if (event.target == test.moved) {
+                            logResult(true, &quot;&amp;lt;source&amp;gt; moved was processed a second time.&quot;); 
+                            setTimeout(configureNextTest, 100);
+                        }  else if (!event.target.nextSibling) {
+                            // We should never reach the end of the source list since the tests stops
+                            // when the error fires for the moved element.
+                            failTest(&quot;Error never fired for &amp;lt;source&amp;gt; moved!&quot;);
+                        }
+                        break;
+                }
+            }
+
+            function runOneTest(evt)
+            {
+                var test = testInfo.tests[testInfo.current];
+                test.fcn(test, evt);
+            }
+
+            function addSource(index)
+            {
+                var source = document.createElement('source');
+                source.src = findMediaFile(&quot;video&quot;, index + &quot;-&quot; + Date.now());
+                source.type = mimeTypeForExtension(source.src.split('.')[1]);
+                video.appendChild(source);
+            }
+            
+            function runNextTest()
+            {
+                consoleWrite(&quot;&quot;);
+                if (++testInfo.current &gt;= testInfo.tests.length) {
+                    consoleWrite(&quot;PASS&lt;br&gt;&quot;);
+                    endTest();
+                    return;
+                }
+
+                testInfo.errorCount = 0;
+                video = mediaElement = document.createElement('video');
+                document.body.appendChild(video);
+
+                // Add a bunch of source elements with bogus urls because we want to rearrange elements 
+                // after the media engine begins processing sources, and we can't predict the delay 
+                // between when the media element fires an 'error' event and our handler is called,
+                // but we need to guarantee that there are &lt;source&gt; elements that haven't been processed
+                // when we run the test.
+                for (var ndx = 1; ndx &lt;= 10; ndx++)
+                    addSource(ndx);
+            }
+
+            function configureNextTest()
+            {
+                var videos = document.querySelectorAll('video');
+                for (var ndx = 0; ndx &lt; videos.length; ++ndx)
+                    videos[ndx].parentNode.removeChild(videos[ndx]);
+                video = mediaElement = null;
+                setTimeout(runNextTest, 100);
+            }
+
+            function setup()
+            {
+                document.addEventListener(&quot;error&quot;, runOneTest, true);
+                configureNextTest();
+            }
+
+        &lt;/script&gt;
+    &lt;/head&gt;
+
+    &lt;body&gt;
+        &lt;div&gt;Test to make sure a &amp;lt;source&amp;gt; moved after the media element begins processing 
+        is handled correctly.&lt;/div&gt;
+        &lt;script&gt;setup()&lt;/script&gt;
+    &lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="brancheschromium552LayoutTestsmediavideosourceremovedexpectedtxtfromrev70063trunkLayoutTestsmediavideosourceremovedexpectedtxt"></a>
<div class="copfile"><h4>Copied: branches/chromium/552/LayoutTests/media/video-source-removed-expected.txt (from rev 70063, trunk/LayoutTests/media/video-source-removed-expected.txt) (0 => 70899)</h4>
<pre class="diff"><span>
<span class="info">--- branches/chromium/552/LayoutTests/media/video-source-removed-expected.txt                                (rev 0)
+++ branches/chromium/552/LayoutTests/media/video-source-removed-expected.txt        2010-10-29 17:47:35 UTC (rev 70899)
</span><span class="lines">@@ -0,0 +1,33 @@
</span><ins>+Test to make sure removing a media element's &lt;source&gt;(s) does not cause a crash.
+
+Removing all &lt;source&gt; elements with removeChild()
+-&gt; removeChild(0)
+-&gt; removeChild(1)
+-&gt; removeChild(2)
+-&gt; removeChild(3)
+-&gt; removeChild(4)
+-&gt; removeChild(5)
+-&gt; removeChild(6)
+-&gt; removeChild(7)
+-&gt; removeChild(8)
+-&gt; removeChild(9)
+
+Removing all &lt;source&gt; by setting .innerHTML
+-&gt; video.innerHTML = ''
+
+Removing all &lt;source&gt; elements with replaceChild()
+-&gt; replaceChild(0)
+-&gt; replaceChild(1)
+-&gt; replaceChild(2)
+-&gt; replaceChild(3)
+-&gt; replaceChild(4)
+-&gt; replaceChild(5)
+-&gt; replaceChild(6)
+-&gt; replaceChild(7)
+-&gt; replaceChild(8)
+-&gt; replaceChild(9)
+
+PASS: A crash did not occur when removing &lt;source&gt; elements.
+
+END OF TEST
+
</ins></span></pre></div>
<a id="brancheschromium552LayoutTestsmediavideosourceremovedhtmlfromrev70063trunkLayoutTestsmediavideosourceremovedhtml"></a>
<div class="copfile"><h4>Copied: branches/chromium/552/LayoutTests/media/video-source-removed.html (from rev 70063, trunk/LayoutTests/media/video-source-removed.html) (0 => 70899)</h4>
<pre class="diff"><span>
<span class="info">--- branches/chromium/552/LayoutTests/media/video-source-removed.html                                (rev 0)
+++ branches/chromium/552/LayoutTests/media/video-source-removed.html        2010-10-29 17:47:35 UTC (rev 70899)
</span><span class="lines">@@ -0,0 +1,92 @@
</span><ins>+&lt;!doctype HTML&gt;
+&lt;html&gt;
+    &lt;head&gt;
+        &lt;title&gt;crash after removing &amp;lt;source&amp;gt; test&lt;/title&gt;
+        &lt;script src=video-test.js&gt;&lt;/script&gt;
+        &lt;script src=media-file.js&gt;&lt;/script&gt;
+        &lt;script&gt;
+
+            var testInfo = 
+            {
+                current : -1,
+                tests : [removeChild, innerHTML, replaceChild]
+            };
+
+            function removeChild(sources)
+            {
+                consoleWrite(&quot;Removing all &amp;lt;source&amp;gt; elements with &lt;i&gt;removeChild()&lt;&quot; + &quot;/i&gt;&quot;);
+                for (var ndx = 0; ndx &lt; sources.length; ++ndx) {
+                    consoleWrite(&quot; -&gt; removeChild(&quot; + ndx + &quot;)&quot;); 
+                    video.removeChild(sources[ndx]);
+               }
+            }
+
+            function innerHTML()
+            {
+                consoleWrite(&quot;Removing all &amp;lt;source&amp;gt; by setting &lt;i&gt;.innerHTML&lt;&quot; + &quot;/i&gt;&quot;);
+                consoleWrite(&quot; -&gt; video.innerHTML = ''&quot;); 
+            }
+
+            function replaceChild(sources)
+            {
+                consoleWrite(&quot;Removing all &amp;lt;source&amp;gt; elements with &lt;i&gt;replaceChild()&lt;&quot; + &quot;/i&gt;&quot;);
+                var span = document.createElement(&quot;span&quot;)
+                span.appendChild(document.createTextNode(&quot;Yo&quot;));
+                for (var ndx = 0; ndx &lt; sources.length; ++ndx) {
+                    consoleWrite(&quot; -&gt; replaceChild(&quot; + ndx + &quot;)&quot;); 
+                   video.replaceChild(span, sources[ndx]);
+                }
+            }
+
+            function runOneTest()
+            {
+                testInfo.tests[testInfo.current](document.querySelectorAll('source'));
+                setTimeout(configureNextTest, 100);
+            }
+
+            function addSource(index)
+            {
+                source = document.createElement('source');
+                source.src = findMediaFile(&quot;video&quot;, index + &quot;-&quot; + Date.now());
+                source.type = mimeTypeForExtension(source.src.split('.')[1]);
+                video.appendChild(source);
+            }
+            
+            function runNextTest()
+            {
+                consoleWrite(&quot;&quot;);
+                if (++testInfo.current &gt;= testInfo.tests.length) {
+                    consoleWrite(&quot;PASS: A crash did not occur when removing &amp;lt;source&amp;gt; elements.&lt;br&gt;&quot;);
+                    endTest();
+                    return;
+                }
+
+                video = mediaElement = document.createElement('video');
+                document.body.appendChild(video);
+                video.addEventListener(&quot;loadstart&quot;, runOneTest);
+
+                // Add a bunch of source elements with bogus urls because we want to remove elements 
+                // after the media engine begins processing sources, and we can't predict the delay 
+                // between when the media element fires an 'error' event and our handler is called,
+                // but we need to guarantee that there are &lt;source&gt; elements that haven't been processed
+                // when we run the test.
+                for (var ndx = 1; ndx &lt;= 10; ndx++)
+                    addSource(ndx);
+            }
+
+            function configureNextTest()
+            {
+                var videos = document.querySelectorAll('video');
+                for (var ndx = 0; ndx &lt; videos.length; ++ndx)
+                    videos[ndx].parentNode.removeChild(videos[ndx]);
+                video = mediaElement = null;
+                setTimeout(runNextTest, 100);
+            }
+        &lt;/script&gt;
+    &lt;/head&gt;
+
+    &lt;body&gt;
+        Test to make sure removing a media element's &amp;lt;source&amp;gt;(s) does not cause a crash.
+        &lt;script&gt;configureNextTest()&lt;/script&gt;
+    &lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="brancheschromium552WebCorehtmlHTMLMediaElementcpp"></a>
<div class="modfile"><h4>Modified: branches/chromium/552/WebCore/html/HTMLMediaElement.cpp (70898 => 70899)</h4>
<pre class="diff"><span>
<span class="info">--- branches/chromium/552/WebCore/html/HTMLMediaElement.cpp        2010-10-29 17:45:44 UTC (rev 70898)
+++ branches/chromium/552/WebCore/html/HTMLMediaElement.cpp        2010-10-29 17:47:35 UTC (rev 70899)
</span><span class="lines">@@ -125,6 +125,7 @@
</span><span class="cx">     , m_lastTimeUpdateEventMovieTime(numeric_limits&lt;float&gt;::max())
</span><span class="cx">     , m_loadState(WaitingForSource)
</span><span class="cx">     , m_currentSourceNode(0)
</span><ins>+    , m_nextChildNodeToConsider(0)
</ins><span class="cx">     , m_player(0)
</span><span class="cx"> #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
</span><span class="cx">     , m_proxyWidget(0)
</span><span class="lines">@@ -155,12 +156,14 @@
</span><span class="cx">     , m_loadInitiatedByUserGesture(false)
</span><span class="cx">     , m_completelyLoaded(false)
</span><span class="cx"> {
</span><ins>+    LOG(Media, &quot;HTMLMediaElement::HTMLMediaElement&quot;);
</ins><span class="cx">     document-&gt;registerForDocumentActivationCallbacks(this);
</span><span class="cx">     document-&gt;registerForMediaVolumeCallbacks(this);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> HTMLMediaElement::~HTMLMediaElement()
</span><span class="cx"> {
</span><ins>+    LOG(Media, &quot;HTMLMediaElement::~HTMLMediaElement&quot;);
</ins><span class="cx">     if (m_isWaitingUntilMediaCanStart)
</span><span class="cx">         document()-&gt;removeMediaCanStartListener(this);
</span><span class="cx">     setShouldDelayLoadEvent(false);
</span><span class="lines">@@ -324,6 +327,7 @@
</span><span class="cx">  
</span><span class="cx"> void HTMLMediaElement::insertedIntoDocument()
</span><span class="cx"> {
</span><ins>+    LOG(Media, &quot;HTMLMediaElement::removedFromDocument&quot;);
</ins><span class="cx">     HTMLElement::insertedIntoDocument();
</span><span class="cx">     if (!getAttribute(srcAttr).isEmpty() &amp;&amp; m_networkState == NETWORK_EMPTY)
</span><span class="cx">         scheduleLoad();
</span><span class="lines">@@ -331,6 +335,7 @@
</span><span class="cx"> 
</span><span class="cx"> void HTMLMediaElement::removedFromDocument()
</span><span class="cx"> {
</span><ins>+    LOG(Media, &quot;HTMLMediaElement::removedFromDocument&quot;);
</ins><span class="cx">     if (m_networkState &gt; NETWORK_EMPTY)
</span><span class="cx">         pause(processingUserGesture());
</span><span class="cx">     if (m_isFullscreen)
</span><span class="lines">@@ -370,6 +375,7 @@
</span><span class="cx"> 
</span><span class="cx"> void HTMLMediaElement::scheduleLoad()
</span><span class="cx"> {
</span><ins>+    LOG(Media, &quot;HTMLMediaElement::scheduleLoad&quot;);
</ins><span class="cx"> #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
</span><span class="cx">     createMediaPlayerProxy();
</span><span class="cx"> #endif
</span><span class="lines">@@ -863,7 +869,7 @@
</span><span class="cx">     LOG(Media, &quot;HTMLMediaElement::setNetworkState(%d) - current state is %d&quot;, static_cast&lt;int&gt;(state), static_cast&lt;int&gt;(m_networkState));
</span><span class="cx"> 
</span><span class="cx">     if (state == MediaPlayer::Empty) {
</span><del>-        // just update the cached state and leave, we can't do anything 
</del><ins>+        // Just update the cached state and leave, we can't do anything.
</ins><span class="cx">         m_networkState = NETWORK_EMPTY;
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="lines">@@ -874,16 +880,17 @@
</span><span class="cx">         // If we failed while trying to load a &lt;source&gt; element, the movie was never parsed, and there are more
</span><span class="cx">         // &lt;source&gt; children, schedule the next one
</span><span class="cx">         if (m_readyState &lt; HAVE_METADATA &amp;&amp; m_loadState == LoadingFromSourceElement) {
</span><del>-            ASSERT(m_currentSourceNode);
-            if (!m_currentSourceNode)
-                return;
</del><span class="cx"> 
</span><del>-            m_currentSourceNode-&gt;scheduleErrorEvent();
</del><ins>+            if (m_currentSourceNode)
+                m_currentSourceNode-&gt;scheduleErrorEvent();
+            else
+                LOG(Media, &quot;HTMLMediaElement::setNetworkState - error event not sent, &lt;source&gt; was removed&quot;);
+
</ins><span class="cx">             if (havePotentialSourceChild()) {
</span><del>-                LOG(Media, &quot;HTMLMediaElement::setNetworkState scheduling next &lt;source&gt;&quot;);
</del><ins>+                LOG(Media, &quot;HTMLMediaElement::setNetworkState - scheduling next &lt;source&gt;&quot;);
</ins><span class="cx">                 scheduleNextSourceChild();
</span><span class="cx">             } else {
</span><del>-                LOG(Media, &quot;HTMLMediaElement::setNetworkState no more &lt;source&gt; elements, waiting&quot;);
</del><ins>+                LOG(Media, &quot;HTMLMediaElement::setNetworkState - no more &lt;source&gt; elements, waiting&quot;);
</ins><span class="cx">                 waitForSourceChange();
</span><span class="cx">             }
</span><span class="cx"> 
</span><span class="lines">@@ -1419,7 +1426,7 @@
</span><span class="cx"> 
</span><span class="cx"> void HTMLMediaElement::setVolume(float vol, ExceptionCode&amp; ec)
</span><span class="cx"> {
</span><del>-    LOG(Media, &quot;HTMLMediaElement::setControls(%f)&quot;, vol);
</del><ins>+    LOG(Media, &quot;HTMLMediaElement::setVolume(%f)&quot;, vol);
</ins><span class="cx"> 
</span><span class="cx">     if (vol &lt; 0.0f || vol &gt; 1.0f) {
</span><span class="cx">         ec = INDEX_SIZE_ERR;
</span><span class="lines">@@ -1567,11 +1574,15 @@
</span><span class="cx"> 
</span><span class="cx"> bool HTMLMediaElement::havePotentialSourceChild()
</span><span class="cx"> {
</span><del>-    // Stash the current &lt;source&gt; node so we can restore it after checking
-    // to see there is another potential
</del><ins>+    // Stash the current &lt;source&gt; node and next nodes so we can restore them after checking
+    // to see there is another potential.
</ins><span class="cx">     HTMLSourceElement* currentSourceNode = m_currentSourceNode;
</span><ins>+    Node* nextNode = m_nextChildNodeToConsider;
+
</ins><span class="cx">     KURL nextURL = selectNextSourceChild(0, DoNothing);
</span><ins>+
</ins><span class="cx">     m_currentSourceNode = currentSourceNode;
</span><ins>+    m_nextChildNodeToConsider = nextNode;
</ins><span class="cx"> 
</span><span class="cx">     return nextURL.isValid();
</span><span class="cx"> }
</span><span class="lines">@@ -1585,23 +1596,30 @@
</span><span class="cx">         LOG(Media, &quot;HTMLMediaElement::selectNextSourceChild(contentType : \&quot;%s\&quot;)&quot;, contentType ? contentType-&gt;raw().utf8().data() : &quot;&quot;);
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+    if (m_nextChildNodeToConsider == sourceChildEndOfListValue()) {
+#if !LOG_DISABLED
+        if (shouldLog)
+            LOG(Media, &quot;HTMLMediaElement::selectNextSourceChild -&gt; 0x0000, \&quot;\&quot;&quot;);
+#endif
+        return KURL();
+    }
+
</ins><span class="cx">     KURL mediaURL;
</span><span class="cx">     Node* node;
</span><del>-    bool lookingForPreviousNode = m_currentSourceNode;
</del><ins>+    HTMLSourceElement* source;
+    bool lookingForStartNode = m_nextChildNodeToConsider;
</ins><span class="cx">     bool canUse = false;
</span><span class="cx"> 
</span><span class="cx">     for (node = firstChild(); !canUse &amp;&amp; node; node = node-&gt;nextSibling()) {
</span><ins>+        if (lookingForStartNode &amp;&amp; m_nextChildNodeToConsider != node)
+            continue;
+        lookingForStartNode = false;
+        
</ins><span class="cx">         if (!node-&gt;hasTagName(sourceTag))
</span><span class="cx">             continue;
</span><span class="cx"> 
</span><del>-        if (lookingForPreviousNode) {
-            if (m_currentSourceNode == static_cast&lt;HTMLSourceElement*&gt;(node))
-                lookingForPreviousNode = false;
-            continue;
-        }
</del><ins>+        source = static_cast&lt;HTMLSourceElement*&gt;(node);
</ins><span class="cx"> 
</span><del>-        HTMLSourceElement* source = static_cast&lt;HTMLSourceElement*&gt;(node);
-
</del><span class="cx">         // If candidate does not have a src attribute, or if its src attribute's value is the empty string ... jump down to the failed step below
</span><span class="cx">         mediaURL = source-&gt;getNonEmptyURLAttribute(srcAttr);
</span><span class="cx"> #if !LOG_DISABLED
</span><span class="lines">@@ -1635,26 +1653,108 @@
</span><span class="cx">         if (!isSafeToLoadURL(mediaURL, actionIfInvalid) || !dispatchBeforeLoadEvent(mediaURL.string()))
</span><span class="cx">             goto check_again;
</span><span class="cx"> 
</span><del>-        // Making it this far means the &lt;source&gt; looks reasonable
</del><ins>+        // Making it this far means the &lt;source&gt; looks reasonable.
</ins><span class="cx">         canUse = true;
</span><del>-        if (contentType)
-            *contentType = ContentType(source-&gt;type());
</del><span class="cx"> 
</span><span class="cx"> check_again:
</span><span class="cx">         if (!canUse &amp;&amp; actionIfInvalid == Complain)
</span><span class="cx">             source-&gt;scheduleErrorEvent();
</span><del>-        m_currentSourceNode = static_cast&lt;HTMLSourceElement*&gt;(node);
</del><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if (!canUse)
</del><ins>+    if (canUse) {
+        if (contentType)
+            *contentType = ContentType(source-&gt;type());
+        m_currentSourceNode = source;
+        m_nextChildNodeToConsider = source-&gt;nextSibling();
+        if (!m_nextChildNodeToConsider)
+            m_nextChildNodeToConsider = sourceChildEndOfListValue();
+    } else {
</ins><span class="cx">         m_currentSourceNode = 0;
</span><ins>+        m_nextChildNodeToConsider = sourceChildEndOfListValue();
+    }
+
</ins><span class="cx"> #if !LOG_DISABLED
</span><span class="cx">     if (shouldLog)
</span><del>-        LOG(Media, &quot;HTMLMediaElement::selectNextSourceChild -&gt; %s&quot;, canUse ? urlForLogging(mediaURL.string()).utf8().data() : &quot;&quot;);
</del><ins>+        LOG(Media, &quot;HTMLMediaElement::selectNextSourceChild -&gt; %p, %s&quot;, m_currentSourceNode, canUse ? urlForLogging(mediaURL.string()).utf8().data() : &quot;&quot;);
</ins><span class="cx"> #endif
</span><span class="cx">     return canUse ? mediaURL : KURL();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void HTMLMediaElement::sourceWasAdded(HTMLSourceElement* source)
+{
+    LOG(Media, &quot;HTMLMediaElement::sourceWasAdded(%p)&quot;, source);
+
+#if !LOG_DISABLED
+    if (source-&gt;hasTagName(sourceTag)) {
+        KURL url = source-&gt;getNonEmptyURLAttribute(srcAttr);
+        LOG(Media, &quot;HTMLMediaElement::sourceWasAdded - 'src' is %s&quot;, urlForLogging(url).utf8().data());
+    }
+#endif
+    
+    // We should only consider a &lt;source&gt; element when there is not src attribute at all.
+    if (hasAttribute(srcAttr))
+        return;
+
+    // 4.8.8 - If a source element is inserted as a child of a media element that has no src 
+    // attribute and whose networkState has the value NETWORK_EMPTY, the user agent must invoke 
+    // the media element's resource selection algorithm.
+    if (networkState() == HTMLMediaElement::NETWORK_EMPTY) {
+        scheduleLoad();
+        return;
+    }
+
+    if (m_currentSourceNode &amp;&amp; source == m_currentSourceNode-&gt;nextSibling()) {
+        LOG(Media, &quot;HTMLMediaElement::sourceWasAdded - &lt;source&gt; inserted immediately after current source&quot;);
+        m_nextChildNodeToConsider = source;
+        return;
+    }
+
+    if (m_nextChildNodeToConsider != sourceChildEndOfListValue())
+        return;
+    
+    // 4.8.9.5, resource selection algorithm, source elements section:
+    // 20 - Wait until the node after pointer is a node other than the end of the list. (This step might wait forever.)
+    // 21 - Asynchronously await a stable state...
+    // 22 - Set the element's delaying-the-load-event flag back to true (this delays the load event again, in case 
+    // it hasn't been fired yet).
+    setShouldDelayLoadEvent(true);
+
+    // 23 - Set the networkState back to NETWORK_LOADING.
+    m_networkState = NETWORK_LOADING;
+    
+    // 24 - Jump back to the find next candidate step above.
+    m_nextChildNodeToConsider = source;
+    scheduleNextSourceChild();
+}
+
+void HTMLMediaElement::sourceWillBeRemoved(HTMLSourceElement* source)
+{
+    LOG(Media, &quot;HTMLMediaElement::sourceWillBeRemoved(%p)&quot;, source);
+
+#if !LOG_DISABLED
+    if (source-&gt;hasTagName(sourceTag)) {
+        KURL url = source-&gt;getNonEmptyURLAttribute(srcAttr);
+        LOG(Media, &quot;HTMLMediaElement::sourceWillBeRemoved - 'src' is %s&quot;, urlForLogging(url).utf8().data());
+    }
+#endif
+
+    if (source != m_currentSourceNode &amp;&amp; source != m_nextChildNodeToConsider)
+        return;
+
+    if (source == m_nextChildNodeToConsider) {
+        m_nextChildNodeToConsider = m_nextChildNodeToConsider-&gt;nextSibling();
+        if (!m_nextChildNodeToConsider)
+            m_nextChildNodeToConsider = sourceChildEndOfListValue();
+        LOG(Media, &quot;HTMLMediaElement::sourceRemoved - m_nextChildNodeToConsider set to %p&quot;, m_nextChildNodeToConsider);
+    } else if (source == m_currentSourceNode) {
+        // Clear the current source node pointer, but don't change the movie as the spec says:
+        // 4.8.8 - Dynamically modifying a source element and its attribute when the element is already 
+        // inserted in a video or audio element will have no effect.
+        m_currentSourceNode = 0;
+        LOG(Media, &quot;HTMLMediaElement::sourceRemoved - m_currentSourceNode set to 0&quot;);
+    }
+}
+
</ins><span class="cx"> void HTMLMediaElement::mediaPlayerTimeChanged(MediaPlayer*)
</span><span class="cx"> {
</span><span class="cx">     LOG(Media, &quot;HTMLMediaElement::mediaPlayerTimeChanged&quot;);
</span></span></pre></div>
<a id="brancheschromium552WebCorehtmlHTMLMediaElementh"></a>
<div class="modfile"><h4>Modified: branches/chromium/552/WebCore/html/HTMLMediaElement.h (70898 => 70899)</h4>
<pre class="diff"><span>
<span class="info">--- branches/chromium/552/WebCore/html/HTMLMediaElement.h        2010-10-29 17:45:44 UTC (rev 70898)
+++ branches/chromium/552/WebCore/html/HTMLMediaElement.h        2010-10-29 17:47:35 UTC (rev 70899)
</span><span class="lines">@@ -169,6 +169,9 @@
</span><span class="cx"> 
</span><span class="cx">     bool processingUserGesture() const;
</span><span class="cx"> 
</span><ins>+    void sourceWillBeRemoved(HTMLSourceElement*);
+    void sourceWasAdded(HTMLSourceElement*);
+
</ins><span class="cx"> protected:
</span><span class="cx">     HTMLMediaElement(const QualifiedName&amp;, Document*);
</span><span class="cx">     virtual ~HTMLMediaElement();
</span><span class="lines">@@ -331,7 +334,9 @@
</span><span class="cx">     enum LoadState { WaitingForSource, LoadingFromSrcAttr, LoadingFromSourceElement };
</span><span class="cx">     LoadState m_loadState;
</span><span class="cx">     HTMLSourceElement* m_currentSourceNode;
</span><del>-    
</del><ins>+    Node* m_nextChildNodeToConsider;
+    Node* sourceChildEndOfListValue() { return static_cast&lt;Node*&gt;(this); }
+
</ins><span class="cx">     OwnPtr&lt;MediaPlayer&gt; m_player;
</span><span class="cx"> #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
</span><span class="cx">     RefPtr&lt;Widget&gt; m_proxyWidget;
</span></span></pre></div>
<a id="brancheschromium552WebCorehtmlHTMLSourceElementcpp"></a>
<div class="modfile"><h4>Modified: branches/chromium/552/WebCore/html/HTMLSourceElement.cpp (70898 => 70899)</h4>
<pre class="diff"><span>
<span class="info">--- branches/chromium/552/WebCore/html/HTMLSourceElement.cpp        2010-10-29 17:45:44 UTC (rev 70898)
+++ branches/chromium/552/WebCore/html/HTMLSourceElement.cpp        2010-10-29 17:47:35 UTC (rev 70899)
</span><span class="lines">@@ -33,6 +33,7 @@
</span><span class="cx"> #include &quot;HTMLDocument.h&quot;
</span><span class="cx"> #include &quot;HTMLMediaElement.h&quot;
</span><span class="cx"> #include &quot;HTMLNames.h&quot;
</span><ins>+#include &quot;Logging.h&quot;
</ins><span class="cx"> 
</span><span class="cx"> using namespace std;
</span><span class="cx"> 
</span><span class="lines">@@ -44,6 +45,7 @@
</span><span class="cx">     : HTMLElement(tagName, document)
</span><span class="cx">     , m_errorEventTimer(this, &amp;HTMLSourceElement::errorEventTimerFired)
</span><span class="cx"> {
</span><ins>+    LOG(Media, &quot;HTMLSourceElement::HTMLSourceElement - %p&quot;, this);
</ins><span class="cx">     ASSERT(hasTagName(sourceTag));
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -55,13 +57,17 @@
</span><span class="cx"> void HTMLSourceElement::insertedIntoTree(bool deep)
</span><span class="cx"> {
</span><span class="cx">     HTMLElement::insertedIntoTree(deep);
</span><del>-    if (parentNode() &amp;&amp; (parentNode()-&gt;hasTagName(audioTag) ||  parentNode()-&gt;hasTagName(videoTag))) {
-        HTMLMediaElement* media = static_cast&lt;HTMLMediaElement*&gt;(parentNode());
-        if (media-&gt;networkState() == HTMLMediaElement::NETWORK_EMPTY)
-            media-&gt;scheduleLoad();
-    }
</del><ins>+    if (parentNode() &amp;&amp; (parentNode()-&gt;hasTagName(audioTag) || parentNode()-&gt;hasTagName(videoTag)))
+        static_cast&lt;HTMLMediaElement*&gt;(parentNode())-&gt;sourceWasAdded(this);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void HTMLSourceElement::willRemove()
+{
+    if (parentNode() &amp;&amp; (parentNode()-&gt;hasTagName(audioTag) || parentNode()-&gt;hasTagName(videoTag)))
+        static_cast&lt;HTMLMediaElement*&gt;(parentNode())-&gt;sourceWillBeRemoved(this);
+    HTMLElement::willRemove();
+}
+    
</ins><span class="cx"> void HTMLSourceElement::setSrc(const String&amp; url)
</span><span class="cx"> {
</span><span class="cx">     setAttribute(srcAttr, url);
</span><span class="lines">@@ -89,6 +95,7 @@
</span><span class="cx"> 
</span><span class="cx"> void HTMLSourceElement::scheduleErrorEvent()
</span><span class="cx"> {
</span><ins>+    LOG(Media, &quot;HTMLSourceElement::scheduleErrorEvent - %p&quot;, this);
</ins><span class="cx">     if (m_errorEventTimer.isActive())
</span><span class="cx">         return;
</span><span class="cx"> 
</span><span class="lines">@@ -97,11 +104,13 @@
</span><span class="cx"> 
</span><span class="cx"> void HTMLSourceElement::cancelPendingErrorEvent()
</span><span class="cx"> {
</span><ins>+    LOG(Media, &quot;HTMLSourceElement::cancelPendingErrorEvent - %p&quot;, this);
</ins><span class="cx">     m_errorEventTimer.stop();
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void HTMLSourceElement::errorEventTimerFired(Timer&lt;HTMLSourceElement&gt;*)
</span><span class="cx"> {
</span><ins>+    LOG(Media, &quot;HTMLSourceElement::errorEventTimerFired - %p&quot;, this);
</ins><span class="cx">     dispatchEvent(Event::create(eventNames().errorEvent, false, true));
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="brancheschromium552WebCorehtmlHTMLSourceElementh"></a>
<div class="modfile"><h4>Modified: branches/chromium/552/WebCore/html/HTMLSourceElement.h (70898 => 70899)</h4>
<pre class="diff"><span>
<span class="info">--- branches/chromium/552/WebCore/html/HTMLSourceElement.h        2010-10-29 17:45:44 UTC (rev 70898)
+++ branches/chromium/552/WebCore/html/HTMLSourceElement.h        2010-10-29 17:47:35 UTC (rev 70899)
</span><span class="lines">@@ -50,6 +50,7 @@
</span><span class="cx">     HTMLSourceElement(const QualifiedName&amp;, Document*);
</span><span class="cx">     
</span><span class="cx">     virtual void insertedIntoTree(bool);
</span><ins>+    virtual void willRemove();
</ins><span class="cx">     virtual bool isURLAttribute(Attribute*) const;
</span><span class="cx"> 
</span><span class="cx">     void errorEventTimerFired(Timer&lt;HTMLSourceElement&gt;*);
</span></span></pre>
</div>
</div>

</body>
</html>