OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2011 Google Inc. All rights reserved. | 2 * Copyright (C) 2011 Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
6 * met: | 6 * met: |
7 * | 7 * |
8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
(...skipping 22 matching lines...) Expand all Loading... |
33 #include "core/html/track/vtt/VTTTokenizer.h" | 33 #include "core/html/track/vtt/VTTTokenizer.h" |
34 | 34 |
35 #include "core/xml/parser/MarkupTokenizerInlines.h" | 35 #include "core/xml/parser/MarkupTokenizerInlines.h" |
36 #include "wtf/unicode/CharacterNames.h" | 36 #include "wtf/unicode/CharacterNames.h" |
37 | 37 |
38 namespace WebCore { | 38 namespace WebCore { |
39 | 39 |
40 #define WEBVTT_BEGIN_STATE(stateName) BEGIN_STATE(VTTTokenizerState, stateName) | 40 #define WEBVTT_BEGIN_STATE(stateName) BEGIN_STATE(VTTTokenizerState, stateName) |
41 #define WEBVTT_ADVANCE_TO(stateName) ADVANCE_TO(VTTTokenizerState, stateName) | 41 #define WEBVTT_ADVANCE_TO(stateName) ADVANCE_TO(VTTTokenizerState, stateName) |
42 | 42 |
| 43 template<unsigned charactersCount> |
| 44 ALWAYS_INLINE bool equalLiteral(const StringBuilder& s, const char (&characters)
[charactersCount]) |
| 45 { |
| 46 return WTF::equal(s, reinterpret_cast<const LChar*>(characters), charactersC
ount - 1); |
| 47 } |
| 48 |
43 VTTTokenizer::VTTTokenizer() | 49 VTTTokenizer::VTTTokenizer() |
44 : m_inputStreamPreprocessor(this) | 50 : m_inputStreamPreprocessor(this) |
45 { | 51 { |
46 reset(); | 52 reset(); |
47 } | 53 } |
48 | 54 |
49 template <typename CharacterType> | |
50 inline bool vectorEqualsString(const Vector<CharacterType, 32>& vector, const St
ring& string) | |
51 { | |
52 if (vector.size() != string.length()) | |
53 return false; | |
54 | |
55 if (!string.length()) | |
56 return true; | |
57 | |
58 return equal(string.impl(), vector.data(), vector.size()); | |
59 } | |
60 | |
61 void VTTTokenizer::reset() | 55 void VTTTokenizer::reset() |
62 { | 56 { |
63 m_token = 0; | 57 m_token = 0; |
64 m_buffer.clear(); | 58 m_buffer.clear(); |
65 } | 59 } |
66 | 60 |
67 bool VTTTokenizer::nextToken(SegmentedString& source, VTTToken& token) | 61 bool VTTTokenizer::nextToken(SegmentedString& source, VTTToken& token) |
68 { | 62 { |
69 // If we have a token in progress, then we're supposed to be called back | 63 // If we have a token in progress, then we're supposed to be called back |
70 // with the same token so we can finish it. | 64 // with the same token so we can finish it. |
71 ASSERT(!m_token || m_token == &token || token.type() == VTTTokenTypes::Unini
tialized); | 65 ASSERT(!m_token || m_token == &token || token.type() == VTTTokenTypes::Unini
tialized); |
72 m_token = &token; | 66 m_token = &token; |
73 | 67 |
74 if (source.isEmpty() || !m_inputStreamPreprocessor.peek(source)) | 68 if (source.isEmpty() || !m_inputStreamPreprocessor.peek(source)) |
75 return haveBufferedCharacterToken(); | 69 return haveBufferedCharacterToken(); |
76 | 70 |
77 UChar cc = m_inputStreamPreprocessor.nextInputCharacter(); | 71 UChar cc = m_inputStreamPreprocessor.nextInputCharacter(); |
78 | 72 |
79 m_state = VTTTokenizerState::DataState; | 73 m_state = VTTTokenizerState::DataState; |
80 | 74 |
81 // 4.8.10.13.4 WebVTT cue text tokenizer | 75 // 4.8.10.13.4 WebVTT cue text tokenizer |
82 switch (m_state) { | 76 switch (m_state) { |
83 WEBVTT_BEGIN_STATE(DataState) { | 77 WEBVTT_BEGIN_STATE(DataState) { |
84 if (cc == '&') { | 78 if (cc == '&') { |
85 m_buffer.append(static_cast<LChar>(cc)); | 79 m_buffer.append(static_cast<LChar>(cc)); |
86 WEBVTT_ADVANCE_TO(EscapeState); | 80 WEBVTT_ADVANCE_TO(EscapeState); |
87 } else if (cc == '<') { | 81 } else if (cc == '<') { |
88 // FIXME: the explicit Vector conversion copies into a temporary | 82 if (m_token->type() == VTTTokenTypes::Uninitialized || m_token->
characters().isEmpty()) { |
89 // and is wasteful. | |
90 if (m_token->type() == VTTTokenTypes::Uninitialized | |
91 || vectorEqualsString<UChar>(Vector<UChar, 32>(m_token->char
acters()), emptyString())) { | |
92 WEBVTT_ADVANCE_TO(TagState); | 83 WEBVTT_ADVANCE_TO(TagState); |
93 } else { | 84 } else { |
94 // We don't want to advance input or perform a state transit
ion - just return a (new) token. | 85 // We don't want to advance input or perform a state transit
ion - just return a (new) token. |
95 // (On the next call to nextToken we will see '<' again, but
take the other branch in this if instead.) | 86 // (On the next call to nextToken we will see '<' again, but
take the other branch in this if instead.) |
96 return emitToken(VTTTokenTypes::Character); | 87 return emitToken(VTTTokenTypes::Character); |
97 } | 88 } |
98 } else if (cc == kEndOfFileMarker) { | 89 } else if (cc == kEndOfFileMarker) { |
99 return emitToken(VTTTokenTypes::Character); | 90 return emitToken(VTTTokenTypes::Character); |
100 } else { | 91 } else { |
101 bufferCharacter(cc); | 92 bufferCharacter(cc); |
102 WEBVTT_ADVANCE_TO(DataState); | 93 WEBVTT_ADVANCE_TO(DataState); |
103 } | 94 } |
104 } | 95 } |
105 END_STATE() | 96 END_STATE() |
106 | 97 |
107 WEBVTT_BEGIN_STATE(EscapeState) { | 98 WEBVTT_BEGIN_STATE(EscapeState) { |
108 if (cc == ';') { | 99 if (cc == ';') { |
109 if (vectorEqualsString(m_buffer, "&")) { | 100 if (equalLiteral(m_buffer, "&")) { |
110 bufferCharacter('&'); | 101 bufferCharacter('&'); |
111 } else if (vectorEqualsString(m_buffer, "<")) { | 102 } else if (equalLiteral(m_buffer, "<")) { |
112 bufferCharacter('<'); | 103 bufferCharacter('<'); |
113 } else if (vectorEqualsString(m_buffer, ">")) { | 104 } else if (equalLiteral(m_buffer, ">")) { |
114 bufferCharacter('>'); | 105 bufferCharacter('>'); |
115 } else if (vectorEqualsString(m_buffer, "&lrm")) { | 106 } else if (equalLiteral(m_buffer, "&lrm")) { |
116 bufferCharacter(leftToRightMark); | 107 bufferCharacter(leftToRightMark); |
117 } else if (vectorEqualsString(m_buffer, "&rlm")) { | 108 } else if (equalLiteral(m_buffer, "&rlm")) { |
118 bufferCharacter(rightToLeftMark); | 109 bufferCharacter(rightToLeftMark); |
119 } else if (vectorEqualsString(m_buffer, " ")) { | 110 } else if (equalLiteral(m_buffer, " ")) { |
120 bufferCharacter(noBreakSpace); | 111 bufferCharacter(noBreakSpace); |
121 } else { | 112 } else { |
122 m_buffer.append(static_cast<LChar>(cc)); | 113 m_buffer.append(static_cast<LChar>(cc)); |
123 m_token->appendToCharacter(m_buffer); | 114 m_token->appendToCharacter(m_buffer); |
124 } | 115 } |
125 m_buffer.clear(); | 116 m_buffer.clear(); |
126 WEBVTT_ADVANCE_TO(DataState); | 117 WEBVTT_ADVANCE_TO(DataState); |
127 } else if (isASCIIAlphanumeric(cc)) { | 118 } else if (isASCIIAlphanumeric(cc)) { |
128 m_buffer.append(static_cast<LChar>(cc)); | 119 m_buffer.append(static_cast<LChar>(cc)); |
129 WEBVTT_ADVANCE_TO(EscapeState); | 120 WEBVTT_ADVANCE_TO(EscapeState); |
130 } else if (cc == kEndOfFileMarker) { | 121 } else if (cc == kEndOfFileMarker) { |
131 m_token->appendToCharacter(m_buffer); | 122 m_token->appendToCharacter(m_buffer); |
132 return emitToken(VTTTokenTypes::Character); | 123 return emitToken(VTTTokenTypes::Character); |
133 } else { | 124 } else { |
134 if (!vectorEqualsString(m_buffer, "&")) | 125 if (!equalLiteral(m_buffer, "&")) |
135 m_token->appendToCharacter(m_buffer); | 126 m_token->appendToCharacter(m_buffer); |
136 m_buffer.clear(); | 127 m_buffer.clear(); |
137 WEBVTT_ADVANCE_TO(DataState); | 128 WEBVTT_ADVANCE_TO(DataState); |
138 } | 129 } |
139 } | 130 } |
140 END_STATE() | 131 END_STATE() |
141 | 132 |
142 WEBVTT_BEGIN_STATE(TagState) { | 133 WEBVTT_BEGIN_STATE(TagState) { |
143 if (isTokenizerWhitespace(cc)) { | 134 if (isTokenizerWhitespace(cc)) { |
144 m_token->beginEmptyStartTag(); | 135 m_token->beginEmptyStartTag(); |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
230 END_STATE() | 221 END_STATE() |
231 | 222 |
232 } | 223 } |
233 | 224 |
234 ASSERT_NOT_REACHED(); | 225 ASSERT_NOT_REACHED(); |
235 return false; | 226 return false; |
236 } | 227 } |
237 | 228 |
238 } | 229 } |
239 | 230 |
OLD | NEW |