Diff
Modified: trunk/LayoutTests/ChangeLog (139691 => 139692)
--- trunk/LayoutTests/ChangeLog 2013-01-15 01:13:45 UTC (rev 139691)
+++ trunk/LayoutTests/ChangeLog 2013-01-15 01:17:16 UTC (rev 139692)
@@ -1,3 +1,15 @@
+2013-01-14 Dima Gorbik <dgor...@apple.com>
+
+ Implement element type selectors for the WebVTT ::cue pseudo class
+ https://bugs.webkit.org/show_bug.cgi?id=105480
+
+ Reviewed by Antti Koivisto.
+
+ * media/track/captions-webvtt/styling.vtt:
+ * media/track/track-css-matching-expected.txt:
+ * media/track/track-css-matching.html:
+ * media/track/track-webvtt-tc026-voice.html: voice elements should be spans according to specs.
+
2013-01-14 Xianzhu Wang <wangxian...@chromium.org>
Sometimes RenderLayer::updateNeedsCompositedScrolling is not called
Modified: trunk/LayoutTests/media/track/captions-webvtt/styling.vtt (139691 => 139692)
--- trunk/LayoutTests/media/track/captions-webvtt/styling.vtt 2013-01-15 01:13:45 UTC (rev 139691)
+++ trunk/LayoutTests/media/track/captions-webvtt/styling.vtt 2013-01-15 01:17:16 UTC (rev 139692)
@@ -1,13 +1,17 @@
WEBVTT
1
-00:00.000 --> 00:01.000
+00:00.000 --> 00:00.200
Lorum ipsum
2
-00:01.000 --> 00:02.000
+00:00.200 --> 00:00.400
<c.red>dolor sit </c><c.green>amet, consectetur </c><c.red2>adipiscing elit</c>
3
-00:02.000 --> 00:05.000
-<00:02.000><c>Suspendisse accumsan, </c><00:03.000><c>mauris sed </c><00:04.000><c>euismod pharetra</c>
\ No newline at end of file
+00:00.400 --> 00:01.000
+<00:00.400><c>Suspendisse accumsan, </c><00:00.600><c>mauris sed </c><00:00.800><c>euismod pharetra</c>
+
+4
+00:01.000 --> 00:01.200
+<c>Aliquam sollicitudin</c> <v>massa ac magna vulputate dignissim</v> <b>posuere et fermentum</b>
Modified: trunk/LayoutTests/media/track/track-css-matching-expected.txt (139691 => 139692)
--- trunk/LayoutTests/media/track/track-css-matching-expected.txt 2013-01-15 01:13:45 UTC (rev 139691)
+++ trunk/LayoutTests/media/track/track-css-matching-expected.txt 2013-01-15 01:17:16 UTC (rev 139692)
@@ -5,25 +5,34 @@
EXPECTED (getComputedStyle(cueNode).color == 'rgb(0, 128, 0)') OK
EXPECTED (getComputedStyle(cueNode).color == 'rgb(255, 0, 0)') OK
-RUN(video.currentTime = 2.5)
+RUN(video.currentTime = 0.5)
EVENT(seeked)
2. Test that cues are being matched properly by the ':future' pseudo class.
-EXPECTED (getComputedStyle(cueNode).color == 'rgb(255, 255, 255)') OK
+EXPECTED (getComputedStyle(cueNode).color == 'rgb(128, 0, 128)') OK
EXPECTED (getComputedStyle(cueNode).color == 'rgb(128, 128, 128)') OK
EXPECTED (getComputedStyle(cueNode).color == 'rgb(128, 128, 128)') OK
-RUN(video.currentTime = 3.5)
+RUN(video.currentTime = 0.7)
EVENT(seeked)
-EXPECTED (getComputedStyle(cueNode).color == 'rgb(255, 255, 255)') OK
-EXPECTED (getComputedStyle(cueNode).color == 'rgb(255, 255, 255)') OK
+EXPECTED (getComputedStyle(cueNode).color == 'rgb(128, 0, 128)') OK
+EXPECTED (getComputedStyle(cueNode).color == 'rgb(128, 0, 128)') OK
EXPECTED (getComputedStyle(cueNode).color == 'rgb(128, 128, 128)') OK
-RUN(video.currentTime = 4.5)
+RUN(video.currentTime = 0.9)
EVENT(seeked)
-EXPECTED (getComputedStyle(cueNode).color == 'rgb(255, 255, 255)') OK
-EXPECTED (getComputedStyle(cueNode).color == 'rgb(255, 255, 255)') OK
-EXPECTED (getComputedStyle(cueNode).color == 'rgb(255, 255, 255)') OK
+EXPECTED (getComputedStyle(cueNode).color == 'rgb(128, 0, 128)') OK
+EXPECTED (getComputedStyle(cueNode).color == 'rgb(128, 0, 128)') OK
+EXPECTED (getComputedStyle(cueNode).color == 'rgb(128, 0, 128)') OK
+
+RUN(video.currentTime = 1.1)
+EVENT(seeked)
+
+
+3. Test that cues are being matched properly by tag.
+EXPECTED (getComputedStyle(cueNode).color == 'rgb(128, 0, 128)') OK
+EXPECTED (getComputedStyle(cueNode).color == 'rgb(255, 255, 0)') OK
+EXPECTED (getComputedStyle(cueNode).color == 'rgb(0, 255, 0)') OK
END OF TEST
Modified: trunk/LayoutTests/media/track/track-css-matching.html (139691 => 139692)
--- trunk/LayoutTests/media/track/track-css-matching.html 2013-01-15 01:13:45 UTC (rev 139691)
+++ trunk/LayoutTests/media/track/track-css-matching.html 2013-01-15 01:17:16 UTC (rev 139692)
@@ -8,10 +8,12 @@
<script src=""
<style>
-
+ video::cue(c) {color: purple}
+ video::cue(v) {color: yellow}
+ video::cue(b) {color: lime}
video::cue(.red, .red2) { color:red }
#testvideo::cue(.green) { color:green }
-
+ video::cue(:future) {color: gray}
</style>
<script>
@@ -19,10 +21,12 @@
var cueNode;
var seekedCount = 0;
var info = [["rgb(255, 0, 0)", "rgb(0, 128, 0)", "rgb(255, 0, 0)"],
- ["rgb(255, 255, 255)", "rgb(128, 128, 128)", "rgb(128, 128, 128)"],
- ["rgb(255, 255, 255)", "rgb(255, 255, 255)", "rgb(128, 128, 128)"],
- ["rgb(255, 255, 255)", "rgb(255, 255, 255)", "rgb(255, 255, 255)"]];
-
+ ["rgb(128, 0, 128)", "rgb(128, 128, 128)", "rgb(128, 128, 128)"],
+ ["rgb(128, 0, 128)", "rgb(128, 0, 128)", "rgb(128, 128, 128)"],
+ ["rgb(128, 0, 128)", "rgb(128, 0, 128)", "rgb(128, 0, 128)"],
+ ["rgb(128, 0, 128)", "rgb(255, 255, 0)", "rgb(0, 255, 0)"]];
+ var seekTimes = [0.3, 0.5, 0.7, 0.9, 1.1, 1.3];
+
function skipNonElements(root)
{
nextElementSibling = root;
@@ -41,6 +45,10 @@
consoleWrite("");
consoleWrite("");
consoleWrite("2. Test that cues are being matched properly by the ':future' pseudo class.");
+ } else if (seekedCount == 4) {
+ consoleWrite("");
+ consoleWrite("");
+ consoleWrite("3. Test that cues are being matched properly by tag.");
}
cueNode = skipNonElements(textTrackDisplayElement(video, 'all-nodes').firstChild);
@@ -55,7 +63,7 @@
endTest();
else {
consoleWrite("");
- run("video.currentTime = " + (video.currentTime + 1));
+ run("video.currentTime = " + seekTimes[seekedCount]);
}
}
@@ -66,7 +74,7 @@
video.src = "" '../content/test');
video.id = "testvideo";
waitForEvent('seeked', seeked);
- waitForEvent('canplaythrough', function() { video.currentTime = 1.5; });
+ waitForEvent('canplaythrough', function() { video.currentTime = seekTimes[0]; });
}
</script>
Modified: trunk/LayoutTests/media/track/track-webvtt-tc026-voice.html (139691 => 139692)
--- trunk/LayoutTests/media/track/track-webvtt-tc026-voice.html 2013-01-15 01:13:45 UTC (rev 139691)
+++ trunk/LayoutTests/media/track/track-webvtt-tc026-voice.html 2013-01-15 01:17:16 UTC (rev 139692)
@@ -24,31 +24,31 @@
testExpected("video.textTracks[" + i + "].cues.length", "3");
var fragment = document.createDocumentFragment();
- var q = document.createElement("q");
- q.className = "blue";
- q.title = "Speaker";
- q.appendChild(document.createTextNode("Bear is Coming!!!!!"));
- fragment.appendChild(q);
+ var cspan = document.createElement("span");
+ cspan.className = "blue";
+ cspan.title = "Speaker";
+ cspan.appendChild(document.createTextNode("Bear is Coming!!!!!"));
+ fragment.appendChild(cspan);
fragment.appendChild(document.createTextNode("\nText span with a class and an annotation."));
testExpected(fragment.isEqualNode(video.textTracks[i].cues[0].getCueAsHTML()), true);
fragment = document.createDocumentFragment();
- q = document.createElement("q");
- q.title = "Doe Hunter";
- q.appendChild(document.createTextNode("I said Bear is coming!!!!"));
- fragment.appendChild(q);
+ cspan = document.createElement("span");
+ cspan.title = "Doe Hunter";
+ cspan.appendChild(document.createTextNode("I said Bear is coming!!!!"));
+ fragment.appendChild(cspan);
testExpected(fragment.isEqualNode(video.textTracks[i].cues[1].getCueAsHTML()), true);
fragment = document.createDocumentFragment();
fragment.appendChild(document.createTextNode("I said "));
- q = document.createElement("q");
- q.className = "blue";
- q.title = "Speaker";
- q.appendChild(document.createTextNode("Bear is coming now"));
- fragment.appendChild(q);
+ cspan = document.createElement("span");
+ cspan.className = "blue";
+ cspan.title = "Speaker";
+ cspan.appendChild(document.createTextNode("Bear is coming now"));
+ fragment.appendChild(cspan);
fragment.appendChild(document.createTextNode("!!!!"));
testExpected(fragment.isEqualNode(video.textTracks[i].cues[2].getCueAsHTML()), true);
Modified: trunk/Source/WebCore/ChangeLog (139691 => 139692)
--- trunk/Source/WebCore/ChangeLog 2013-01-15 01:13:45 UTC (rev 139691)
+++ trunk/Source/WebCore/ChangeLog 2013-01-15 01:17:16 UTC (rev 139692)
@@ -1,3 +1,37 @@
+2013-01-14 Dima Gorbik <dgor...@apple.com>
+
+ Implement element type selectors for the WebVTT ::cue pseudo class
+ https://bugs.webkit.org/show_bug.cgi?id=105480
+
+ Reviewed by Antti Koivisto.
+
+ Implemented tag matching for the WebVTT specific tags "c" and "v". All common html tags like "b" and "i" are
+ handled without any changes to the code. Creating a rendering tree and DOM tree now use different code paths.
+ They both are made by cloning and modifying the tree produced by the parser. Voice tags now use spans for both
+ rendering and DOM trees to conform to specs. Since this changes a lot of code little refactoring has been
+ done. Removed m_hasInnerTimestamps since it is no longer needed, it doesn't affect anything. m_documentFragment
+ was renamed to m_webVTTNodeTree.
+
+ Existing tests were modified to cover this case.
+
+ * html/track/TextTrackCue.cpp:
+ (WebCore::TextTrackCue::TextTrackCue):
+ (WebCore::TextTrackCue::setText): rename m_documentFragment to m_webVTTNodeTree
+ (WebCore::TextTrackCue::createWebVTTNodeTree): parse the cue if it hasn't been parsed before.
+ (WebCore::TextTrackCue::copyWebVTTNodeToDOMTree): clone and prepare a node for using in the DOM tree according to specs.
+ (WebCore::TextTrackCue::getCueAsHTML): get a DOM tree for the cue.
+ (WebCore::TextTrackCue::createCueRenderingTree): create a rendering tree (main tree is just being cloned for now).
+ (WebCore::TextTrackCue::markFutureAndPastNodes): tightening the argument type.
+ (WebCore::TextTrackCue::updateDisplayTree):
+ (WebCore::TextTrackCue::getDisplayTree): code cleanup, removed m_hasInnerTimeStamps.
+ * html/track/TextTrackCue.h:
+ (WebCore::TextTrackCue::voiceElementTagName):
+ (TextTrackCue):
+ (WebCore::TextTrackCue::classElementTagName):
+ * html/track/WebVTTParser.cpp:
+ (WebCore::WebVTTParser::constructTreeFromToken): type of the newly created elements was changed to Element to avoid hitting
+ an assertion when cloning because a cloned element will not have HTMLElement type for elements with "v" and "c" tag.
+
2013-01-14 Xianzhu Wang <wangxian...@chromium.org>
Sometimes RenderLayer::updateNeedsCompositedScrolling is not called
Modified: trunk/Source/WebCore/html/track/TextTrackCue.cpp (139691 => 139692)
--- trunk/Source/WebCore/html/track/TextTrackCue.cpp 2013-01-15 01:13:45 UTC (rev 139691)
+++ trunk/Source/WebCore/html/track/TextTrackCue.cpp 2013-01-15 01:17:16 UTC (rev 139692)
@@ -41,6 +41,7 @@
#include "Event.h"
#include "HTMLDivElement.h"
#include "HTMLMediaElement.h"
+#include "HTMLSpanElement.h"
#include "NodeTraversal.h"
#include "RenderTextTrackCue.h"
#include "Text.h"
@@ -200,13 +201,12 @@
, m_cueIndex(invalidCueIndex)
, m_writingDirection(Horizontal)
, m_cueAlignment(Middle)
- , m_documentFragment(0)
+ , m_webVTTNodeTree(0)
, m_track(0)
, m_scriptExecutionContext(context)
, m_isActive(false)
, m_pauseOnExit(false)
, m_snapToLines(true)
- , m_hasInnerTimestamps(false)
, m_allDocumentNodes(HTMLDivElement::create(static_cast<Document*>(context)))
, m_displayTreeShouldChange(true)
, m_displayTree(TextTrackCueBox::create(static_cast<Document*>(m_scriptExecutionContext), this))
@@ -463,7 +463,7 @@
cueWillChange();
// Clear the document fragment but don't bother to create it again just yet as we can do that
// when it is requested.
- m_documentFragment = 0;
+ m_webVTTNodeTree = 0;
m_content = text;
cueDidChange();
}
@@ -481,29 +481,46 @@
m_cueIndex = invalidCueIndex;
}
-PassRefPtr<DocumentFragment> TextTrackCue::getCueAsHTML()
+void TextTrackCue::createWebVTTNodeTree()
{
- RefPtr<DocumentFragment> clonedFragment;
- Document* document;
+ if (!m_webVTTNodeTree)
+ m_webVTTNodeTree = WebVTTParser::create(0, m_scriptExecutionContext)->createDocumentFragmentFromCueText(m_content);
+}
- if (!m_documentFragment) {
- m_hasInnerTimestamps = false;
- m_documentFragment = WebVTTParser::create(0, m_scriptExecutionContext)->createDocumentFragmentFromCueText(m_content);
+void TextTrackCue::copyWebVTTNodeToDOMTree(ContainerNode* webVTTNode, ContainerNode* parent)
+{
+ for (Node* node = webVTTNode->firstChild(); node; node = node->nextSibling()) {
+ RefPtr<Node> clonedNode;
+ // Specs require voice and class WebVTT elements to be spans for DOM trees.
+ if (node->hasTagName(voiceElementTagName()) || node->hasTagName(classElementTagName())) {
+ clonedNode = HTMLSpanElement::create(spanTag, static_cast<Document*>(m_scriptExecutionContext));
+ toElement(clonedNode.get())->setAttribute(classAttr, toElement(node)->getAttribute(classAttr));
+ toElement(clonedNode.get())->setAttribute(titleAttr, toElement(node)->getAttribute(titleAttr));
+ } else
+ clonedNode = node->cloneNode(false);
- if (!m_documentFragment)
- return 0;
-
- for (Node *child = m_documentFragment->firstChild(); !m_hasInnerTimestamps && child; child = child->nextSibling()) {
- if (child->nodeName() == "timestamp")
- m_hasInnerTimestamps = true;
- }
+ parent->appendChild(clonedNode, ASSERT_NO_EXCEPTION);
+ if (node->isContainerNode())
+ copyWebVTTNodeToDOMTree(toContainerNode(node), toContainerNode(clonedNode.get()));
}
+}
- document = static_cast<Document*>(m_scriptExecutionContext);
+PassRefPtr<DocumentFragment> TextTrackCue::getCueAsHTML()
+{
+ createWebVTTNodeTree();
+ Document* document = static_cast<Document*>(m_scriptExecutionContext);
+ RefPtr<DocumentFragment> clonedFragment = DocumentFragment::create(document);
+ copyWebVTTNodeToDOMTree(m_webVTTNodeTree.get(), clonedFragment.get());
+ return clonedFragment.release();
+}
+PassRefPtr<DocumentFragment> TextTrackCue::createCueRenderingTree()
+{
+ RefPtr<DocumentFragment> clonedFragment;
+ createWebVTTNodeTree();
+ Document* document = static_cast<Document*>(m_scriptExecutionContext);
clonedFragment = DocumentFragment::create(document);
- m_documentFragment->cloneChildNodes(clonedFragment.get());
-
+ m_webVTTNodeTree->cloneChildNodes(clonedFragment.get());
return clonedFragment.release();
}
@@ -658,7 +675,7 @@
m_computedLinePosition = calculateComputedLinePosition();
}
-void TextTrackCue::markFutureAndPastNodes(Node* root, double previousTimestamp, double movieTime)
+void TextTrackCue::markFutureAndPastNodes(ContainerNode* root, double previousTimestamp, double movieTime)
{
DEFINE_STATIC_LOCAL(const String, timestampTag, (ASCIILiteral("timestamp")));
@@ -695,7 +712,7 @@
m_allDocumentNodes->removeChildren();
// Update the two sets containing past and future WebVTT objects.
- RefPtr<DocumentFragment> referenceTree = getCueAsHTML();
+ RefPtr<DocumentFragment> referenceTree = createCueRenderingTree();
markFutureAndPastNodes(referenceTree.get(), startTime(), movieTime);
m_allDocumentNodes->appendChild(referenceTree);
}
@@ -736,9 +753,6 @@
// normally would in CSS, it is instead forcibly wrapped at the box's edge.)
m_displayTree->applyCSSProperties();
- if (m_hasInnerTimestamps)
- updateDisplayTree(track()->mediaElement()->currentTime());
-
m_displayTreeShouldChange = false;
// 10.15. Let cue's text track cue display state have the CSS boxes in
Modified: trunk/Source/WebCore/html/track/TextTrackCue.h (139691 => 139692)
--- trunk/Source/WebCore/html/track/TextTrackCue.h 2013-01-15 01:13:45 UTC (rev 139691)
+++ trunk/Source/WebCore/html/track/TextTrackCue.h 2013-01-15 01:17:16 UTC (rev 139692)
@@ -78,6 +78,18 @@
return adoptRef(new TextTrackCue(context, start, end, content));
}
+ static const QualifiedName& voiceElementTagName()
+ {
+ DEFINE_STATIC_LOCAL(QualifiedName, vTag, (nullAtom, "v", nullAtom));
+ return vTag;
+ }
+
+ static const QualifiedName& classElementTagName()
+ {
+ DEFINE_STATIC_LOCAL(QualifiedName, cTag, (nullAtom, "c", nullAtom));
+ return cTag;
+ }
+
virtual ~TextTrackCue();
static const AtomicString& allNodesShadowPseudoId();
@@ -125,6 +137,7 @@
void invalidateCueIndex();
PassRefPtr<DocumentFragment> getCueAsHTML();
+ PassRefPtr<DocumentFragment> createCueRenderingTree();
using EventTarget::dispatchEvent;
virtual bool dispatchEvent(PassRefPtr<Event>) OVERRIDE;
@@ -135,7 +148,7 @@
PassRefPtr<TextTrackCueBox> getDisplayTree();
void updateDisplayTree(float);
void removeDisplayTree();
- void markFutureAndPastNodes(Node*, double, double);
+ void markFutureAndPastNodes(ContainerNode*, double, double);
int calculateComputedLinePosition();
@@ -197,7 +210,7 @@
enum Alignment { Start, Middle, End };
Alignment m_cueAlignment;
- RefPtr<DocumentFragment> m_documentFragment;
+ RefPtr<DocumentFragment> m_webVTTNodeTree;
TextTrack* m_track;
EventTargetData m_eventTargetData;
@@ -207,7 +220,6 @@
bool m_pauseOnExit;
bool m_snapToLines;
- bool m_hasInnerTimestamps;
RefPtr<HTMLDivElement> m_allDocumentNodes;
bool m_displayTreeShouldChange;
@@ -221,6 +233,9 @@
int m_displaySize;
std::pair<float, float> m_displayPosition;
+
+ void createWebVTTNodeTree();
+ void copyWebVTTNodeToDOMTree(ContainerNode* WebVTTNode, ContainerNode* root);
};
} // namespace WebCore
Modified: trunk/Source/WebCore/html/track/WebVTTParser.cpp (139691 => 139692)
--- trunk/Source/WebCore/html/track/WebVTTParser.cpp 2013-01-15 01:13:45 UTC (rev 139691)
+++ trunk/Source/WebCore/html/track/WebVTTParser.cpp 2013-01-15 01:17:16 UTC (rev 139692)
@@ -346,7 +346,7 @@
QualifiedName tagName(nullAtom, tokenTagName, xhtmlNamespaceURI);
// http://dev.w3.org/html5/webvtt/#webvtt-cue-text-dom-construction-rules
-
+
switch (m_token.type()) {
case WebVTTTokenTypes::Character: {
String content(m_token.characters().data(), m_token.characters().size());
@@ -355,18 +355,18 @@
break;
}
case WebVTTTokenTypes::StartTag: {
- RefPtr<HTMLElement> child;
+ RefPtr<Element> child;
if (isRecognizedTag(tokenTagName))
child = HTMLElement::create(tagName, document);
else if (m_token.name().size() == 1 && m_token.name()[0] == 'c')
- child = HTMLElement::create(spanTag, document);
+ child = Element::create(TextTrackCue::classElementTagName(), document);
else if (m_token.name().size() == 1 && m_token.name()[0] == 'v')
- child = HTMLElement::create(qTag, document);
+ child = Element::create(TextTrackCue::voiceElementTagName(), document);
if (child) {
if (m_token.classes().size() > 0)
child->setAttribute(classAttr, AtomicString(m_token.classes().data(), m_token.classes().size()));
- if (child->hasTagName(qTag))
+ if (child->hasTagName(TextTrackCue::voiceElementTagName()))
child->setAttribute(titleAttr, AtomicString(m_token.annotation().data(), m_token.annotation().size()));
m_currentNode->parserAppendChild(child);
m_currentNode = child;