void WebVTTTreeBuilder::constructTreeFromToken(Document& document) { // http://dev.w3.org/html5/webvtt/#webvtt-cue-text-dom-construction-rules switch (m_token.type()) { case WebVTTTokenTypes::Character: { RefPtr<Text> child = Text::create(document, m_token.characters()); m_currentNode->parserAppendChild(child); break; } case WebVTTTokenTypes::StartTag: { WebVTTNodeType nodeType = tokenToNodeType(m_token); if (nodeType == WebVTTNodeTypeNone) break; WebVTTNodeType currentType = m_currentNode->isWebVTTElement() ? toWebVTTElement(m_currentNode.get())->webVTTNodeType() : WebVTTNodeTypeNone; // <rt> is only allowed if the current node is <ruby>. if (nodeType == WebVTTNodeTypeRubyText && currentType != WebVTTNodeTypeRuby) break; RefPtr<WebVTTElement> child = WebVTTElement::create(nodeType, document); if (!m_token.classes().isEmpty()) child->setAttribute(classAttr, m_token.classes()); if (nodeType == WebVTTNodeTypeVoice) child->setAttribute(WebVTTElement::voiceAttributeName(), m_token.annotation()); else if (nodeType == WebVTTNodeTypeLanguage) { m_languageStack.append(m_token.annotation()); child->setAttribute(WebVTTElement::langAttributeName(), m_languageStack.last()); } if (!m_languageStack.isEmpty()) child->setLanguage(m_languageStack.last()); m_currentNode->parserAppendChild(child); m_currentNode = child; break; } case WebVTTTokenTypes::EndTag: { WebVTTNodeType nodeType = tokenToNodeType(m_token); if (nodeType == WebVTTNodeTypeNone) break; // The only non-VTTElement would be the DocumentFragment root. (Text // nodes and PIs will never appear as m_currentNode.) if (!m_currentNode->isWebVTTElement()) break; WebVTTNodeType currentType = toWebVTTElement(m_currentNode.get())->webVTTNodeType(); bool matchesCurrent = nodeType == currentType; if (!matchesCurrent) { // </ruby> auto-closes <rt> if (currentType == WebVTTNodeTypeRubyText && nodeType == WebVTTNodeTypeRuby) { if (m_currentNode->parentNode()) m_currentNode = m_currentNode->parentNode(); } else break; } if (nodeType == WebVTTNodeTypeLanguage) m_languageStack.removeLast(); if (m_currentNode->parentNode()) m_currentNode = m_currentNode->parentNode(); break; } case WebVTTTokenTypes::TimestampTag: { String charactersString = m_token.characters(); double parsedTimeStamp; if (WebVTTParser::collectTimeStamp(charactersString, parsedTimeStamp)) m_currentNode->parserAppendChild(ProcessingInstruction::create(document, "timestamp", charactersString)); break; } default: break; } }
static WebVTTNodeType tokenToNodeType(WebVTTToken& token) { switch (token.name().size()) { case 1: if (token.name()[0] == 'c') return WebVTTNodeTypeClass; if (token.name()[0] == 'v') return WebVTTNodeTypeVoice; if (token.name()[0] == 'b') return WebVTTNodeTypeBold; if (token.name()[0] == 'i') return WebVTTNodeTypeItalic; if (token.name()[0] == 'u') return WebVTTNodeTypeUnderline; break; case 2: if (token.name()[0] == 'r' && token.name()[1] == 't') return WebVTTNodeTypeRubyText; break; case 4: if (token.name()[0] == 'r' && token.name()[1] == 'u' && token.name()[2] == 'b' && token.name()[3] == 'y') return WebVTTNodeTypeRuby; if (token.name()[0] == 'l' && token.name()[1] == 'a' && token.name()[2] == 'n' && token.name()[3] == 'g') return WebVTTNodeTypeLanguage; break; } return WebVTTNodeTypeNone; }
static inline bool isLangToken(WebVTTToken& token) { return token.name().size() == 4 && token.name()[0] == 'l' && token.name()[1] == 'a' && token.name()[2] == 'n' && token.name()[3] == 'g'; }