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 26 matching lines...) Expand all Loading... |
37 #include "core/html/track/WebVTTElement.h" | 37 #include "core/html/track/WebVTTElement.h" |
38 #include "platform/text/SegmentedString.h" | 38 #include "platform/text/SegmentedString.h" |
39 #include "wtf/text/WTFString.h" | 39 #include "wtf/text/WTFString.h" |
40 | 40 |
41 namespace WebCore { | 41 namespace WebCore { |
42 | 42 |
43 const double secondsPerHour = 3600; | 43 const double secondsPerHour = 3600; |
44 const double secondsPerMinute = 60; | 44 const double secondsPerMinute = 60; |
45 const double secondsPerMillisecond = 0.001; | 45 const double secondsPerMillisecond = 0.001; |
46 const double malformedTime = -1; | 46 const double malformedTime = -1; |
47 const unsigned bomLength = 3; | |
48 const unsigned fileIdentifierLength = 6; | 47 const unsigned fileIdentifierLength = 6; |
49 | 48 |
50 String WebVTTParser::collectDigits(const String& input, unsigned* position) | 49 String WebVTTParser::collectDigits(const String& input, unsigned* position) |
51 { | 50 { |
52 StringBuilder digits; | 51 StringBuilder digits; |
53 while (*position < input.length() && isASCIIDigit(input[*position])) | 52 while (*position < input.length() && isASCIIDigit(input[*position])) |
54 digits.append(input[(*position)++]); | 53 digits.append(input[(*position)++]); |
55 return digits.toString(); | 54 return digits.toString(); |
56 } | 55 } |
57 | 56 |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
107 bool isSecondValueValid; | 106 bool isSecondValueValid; |
108 float secondCoord = parseFloatPercentageValue(value.substring(delimiterOffse
t + 1, value.length() - 1), isSecondValueValid); | 107 float secondCoord = parseFloatPercentageValue(value.substring(delimiterOffse
t + 1, value.length() - 1), isSecondValueValid); |
109 | 108 |
110 isValidSetting = isFirstValueValid && isSecondValueValid; | 109 isValidSetting = isFirstValueValid && isSecondValueValid; |
111 return FloatPoint(firstCoord, secondCoord); | 110 return FloatPoint(firstCoord, secondCoord); |
112 } | 111 } |
113 | 112 |
114 WebVTTParser::WebVTTParser(WebVTTParserClient* client, Document& document) | 113 WebVTTParser::WebVTTParser(WebVTTParserClient* client, Document& document) |
115 : m_document(&document) | 114 : m_document(&document) |
116 , m_state(Initial) | 115 , m_state(Initial) |
| 116 , m_decoder(TextResourceDecoder::create("text/plain", UTF8Encoding())) |
117 , m_currentStartTime(0) | 117 , m_currentStartTime(0) |
118 , m_currentEndTime(0) | 118 , m_currentEndTime(0) |
119 , m_tokenizer(WebVTTTokenizer::create()) | 119 , m_tokenizer(WebVTTTokenizer::create()) |
120 , m_client(client) | 120 , m_client(client) |
121 { | 121 { |
122 } | 122 } |
123 | 123 |
124 void WebVTTParser::getNewCues(Vector<RefPtr<TextTrackCue> >& outputCues) | 124 void WebVTTParser::getNewCues(Vector<RefPtr<TextTrackCue> >& outputCues) |
125 { | 125 { |
126 outputCues = m_cuelist; | 126 outputCues = m_cuelist; |
127 m_cuelist.clear(); | 127 m_cuelist.clear(); |
128 } | 128 } |
129 | 129 |
130 void WebVTTParser::getNewRegions(Vector<RefPtr<TextTrackRegion> >& outputRegions
) | 130 void WebVTTParser::getNewRegions(Vector<RefPtr<TextTrackRegion> >& outputRegions
) |
131 { | 131 { |
132 outputRegions = m_regionList; | 132 outputRegions = m_regionList; |
133 m_regionList.clear(); | 133 m_regionList.clear(); |
134 } | 134 } |
135 | 135 |
136 void WebVTTParser::parseBytes(const char* data, unsigned length) | 136 void WebVTTParser::parseBytes(const char* data, unsigned length) |
137 { | 137 { |
| 138 String textData = m_decoder->decode(data, length); |
| 139 |
138 // 4.8.10.13.3 WHATWG WebVTT Parser algorithm. | 140 // 4.8.10.13.3 WHATWG WebVTT Parser algorithm. |
139 // 1-3 - Initial setup. | 141 // 1-3 - Initial setup. |
140 unsigned position = 0; | 142 unsigned position = 0; |
141 | 143 |
142 while (position < length) { | 144 while (position < textData.length()) { |
143 String line = collectNextLine(data, length, &position); | 145 String line = collectNextLine(textData, &position); |
144 | 146 |
145 switch (m_state) { | 147 switch (m_state) { |
146 case Initial: | 148 case Initial: |
147 // Buffer up at least 9 bytes before proceeding with checking for th
e file identifier. | 149 // 4-12 - Check for a valid WebVTT signature. |
148 m_identifierData.append(data, length); | 150 if (!hasRequiredFileIdentifier(line)) { |
149 if (m_identifierData.size() < bomLength + fileIdentifierLength) | |
150 return; | |
151 | |
152 // 4-12 - Collect the first line and check for "WEBVTT". | |
153 if (!hasRequiredFileIdentifier()) { | |
154 if (m_client) | 151 if (m_client) |
155 m_client->fileFailedToParse(); | 152 m_client->fileFailedToParse(); |
156 return; | 153 return; |
157 } | 154 } |
158 | 155 |
159 m_state = Header; | 156 m_state = Header; |
160 m_identifierData.clear(); | |
161 break; | 157 break; |
162 | 158 |
163 case Header: | 159 case Header: |
164 collectMetadataHeader(line); | 160 collectMetadataHeader(line); |
165 | 161 |
166 // 13-18 - Allow a header (comment area) under the WEBVTT line. | 162 // 13-18 - Allow a header (comment area) under the WEBVTT line. |
167 if (line.isEmpty()) { | 163 if (line.isEmpty()) { |
168 if (m_client && m_regionList.size()) | 164 if (m_client && m_regionList.size()) |
169 m_client->newRegionsParsed(); | 165 m_client->newRegionsParsed(); |
170 | 166 |
(...skipping 13 matching lines...) Expand all Loading... |
184 m_state = collectCueId(line); | 180 m_state = collectCueId(line); |
185 break; | 181 break; |
186 | 182 |
187 case TimingsAndSettings: | 183 case TimingsAndSettings: |
188 // 40 - Collect cue timings and settings. | 184 // 40 - Collect cue timings and settings. |
189 m_state = collectTimingsAndSettings(line); | 185 m_state = collectTimingsAndSettings(line); |
190 break; | 186 break; |
191 | 187 |
192 case CueText: | 188 case CueText: |
193 // 41-53 - Collect the cue text, create a cue, and add it to the out
put. | 189 // 41-53 - Collect the cue text, create a cue, and add it to the out
put. |
194 m_state = collectCueText(line, length, position); | 190 m_state = collectCueText(line, position >= textData.length()); |
195 break; | 191 break; |
196 | 192 |
197 case BadCue: | 193 case BadCue: |
198 // 54-62 - Collect and discard the remaining cue. | 194 // 54-62 - Collect and discard the remaining cue. |
199 m_state = ignoreBadCue(line); | 195 m_state = ignoreBadCue(line); |
200 break; | 196 break; |
201 } | 197 } |
202 } | 198 } |
203 } | 199 } |
204 | 200 |
205 bool WebVTTParser::hasRequiredFileIdentifier() | 201 bool WebVTTParser::hasRequiredFileIdentifier(const String& line) |
206 { | 202 { |
207 // A WebVTT file identifier consists of an optional BOM character, | 203 // A WebVTT file identifier consists of an optional BOM character, |
208 // the string "WEBVTT" followed by an optional space or tab character, | 204 // the string "WEBVTT" followed by an optional space or tab character, |
209 // and any number of characters that are not line terminators ... | 205 // and any number of characters that are not line terminators ... |
210 unsigned position = 0; | 206 if (!line.startsWith("WEBVTT", fileIdentifierLength)) |
211 if (m_identifierData.size() >= bomLength && m_identifierData[0] == '\xEF' &&
m_identifierData[1] == '\xBB' && m_identifierData[2] == '\xBF') | |
212 position += bomLength; | |
213 String line = collectNextLine(m_identifierData.data(), m_identifierData.size
(), &position); | |
214 | |
215 if (line.length() < fileIdentifierLength) | |
216 return false; | 207 return false; |
217 if (line.substring(0, fileIdentifierLength) != "WEBVTT") | 208 if (line.length() > fileIdentifierLength && !isASpace(line[fileIdentifierLen
gth])) |
218 return false; | |
219 if (line.length() > fileIdentifierLength && line[fileIdentifierLength] != '
' && line[fileIdentifierLength] != '\t') | |
220 return false; | 209 return false; |
221 | 210 |
222 return true; | 211 return true; |
223 } | 212 } |
224 | 213 |
225 void WebVTTParser::collectMetadataHeader(const String& line) | 214 void WebVTTParser::collectMetadataHeader(const String& line) |
226 { | 215 { |
227 // 4.1 Extension of WebVTT header parsing (11 - 15) | 216 // 4.1 Extension of WebVTT header parsing (11 - 15) |
228 DEFINE_STATIC_LOCAL(const AtomicString, regionHeaderName, ("Region", AtomicS
tring::ConstructFromLiteral)); | 217 DEFINE_STATIC_LOCAL(const AtomicString, regionHeaderName, ("Region", AtomicS
tring::ConstructFromLiteral)); |
229 | 218 |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
281 m_currentEndTime = collectTimeStamp(line, &position); | 270 m_currentEndTime = collectTimeStamp(line, &position); |
282 if (m_currentEndTime == malformedTime) | 271 if (m_currentEndTime == malformedTime) |
283 return BadCue; | 272 return BadCue; |
284 skipWhiteSpace(line, &position); | 273 skipWhiteSpace(line, &position); |
285 | 274 |
286 // 12 - Parse the WebVTT settings for the cue (conducted in TextTrackCue). | 275 // 12 - Parse the WebVTT settings for the cue (conducted in TextTrackCue). |
287 m_currentSettings = line.substring(position, line.length()-1); | 276 m_currentSettings = line.substring(position, line.length()-1); |
288 return CueText; | 277 return CueText; |
289 } | 278 } |
290 | 279 |
291 WebVTTParser::ParseState WebVTTParser::collectCueText(const String& line, unsign
ed length, unsigned position) | 280 WebVTTParser::ParseState WebVTTParser::collectCueText(const String& line, bool i
sAtEnd) |
292 { | 281 { |
293 if (line.isEmpty()) { | 282 if (line.isEmpty()) { |
294 createNewCue(); | 283 createNewCue(); |
295 return Id; | 284 return Id; |
296 } | 285 } |
297 if (!m_currentContent.isEmpty()) | 286 if (!m_currentContent.isEmpty()) |
298 m_currentContent.append("\n"); | 287 m_currentContent.append("\n"); |
299 m_currentContent.append(line); | 288 m_currentContent.append(line); |
300 | 289 |
301 if (position >= length) | 290 if (isAtEnd) |
302 createNewCue(); | 291 createNewCue(); |
303 | 292 |
304 return CueText; | 293 return CueText; |
305 } | 294 } |
306 | 295 |
307 WebVTTParser::ParseState WebVTTParser::ignoreBadCue(const String& line) | 296 WebVTTParser::ParseState WebVTTParser::ignoreBadCue(const String& line) |
308 { | 297 { |
309 if (!line.isEmpty()) | 298 if (!line.isEmpty()) |
310 return BadCue; | 299 return BadCue; |
311 return Id; | 300 return Id; |
(...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
525 } | 514 } |
526 m_token.clear(); | 515 m_token.clear(); |
527 } | 516 } |
528 | 517 |
529 void WebVTTParser::skipWhiteSpace(const String& line, unsigned* position) | 518 void WebVTTParser::skipWhiteSpace(const String& line, unsigned* position) |
530 { | 519 { |
531 while (*position < line.length() && isASpace(line[*position])) | 520 while (*position < line.length() && isASpace(line[*position])) |
532 (*position)++; | 521 (*position)++; |
533 } | 522 } |
534 | 523 |
535 void WebVTTParser::skipLineTerminator(const char* data, unsigned length, unsigne
d* position) | 524 void WebVTTParser::skipLineTerminator(const String& data, unsigned* position) |
536 { | 525 { |
537 if (*position >= length) | 526 if (*position >= data.length()) |
538 return; | 527 return; |
539 if (data[*position] == '\r') | 528 if (data[*position] == '\r') |
540 (*position)++; | 529 (*position)++; |
541 if (*position >= length) | 530 if (*position >= data.length()) |
542 return; | 531 return; |
543 if (data[*position] == '\n') | 532 if (data[*position] == '\n') |
544 (*position)++; | 533 (*position)++; |
545 } | 534 } |
546 | 535 |
547 String WebVTTParser::collectNextLine(const char* data, unsigned length, unsigned
* position) | 536 String WebVTTParser::collectNextLine(const String& data, unsigned* position) |
548 { | 537 { |
549 unsigned oldPosition = *position; | 538 unsigned oldPosition = *position; |
550 while (*position < length && data[*position] != '\r' && data[*position] != '
\n') | 539 while (*position < data.length() && data[*position] != '\r' && data[*positio
n] != '\n') |
551 (*position)++; | 540 (*position)++; |
552 String line = String::fromUTF8(data + oldPosition, *position - oldPosition); | 541 String line = data.substring(oldPosition, *position - oldPosition); |
553 skipLineTerminator(data, length, position); | 542 skipLineTerminator(data, position); |
554 return line; | 543 return line; |
555 } | 544 } |
556 | 545 |
557 } | 546 } |
558 | 547 |
OLD | NEW |