Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(206)

Side by Side Diff: Source/core/html/track/WebVTTParser.cpp

Issue 64273013: Update WebVTT parser spec references (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
143 { 143 {
144 String textData = m_decoder->flush(); 144 String textData = m_decoder->flush();
145 m_lineReader.append(textData); 145 m_lineReader.append(textData);
146 m_lineReader.setEndOfStream(); 146 m_lineReader.setEndOfStream();
147 parse(); 147 parse();
148 flushPendingCue(); 148 flushPendingCue();
149 } 149 }
150 150
151 void WebVTTParser::parse() 151 void WebVTTParser::parse()
152 { 152 {
153 // 4.8.10.13.3 WHATWG WebVTT Parser algorithm. 153 // WebVTT parser algorithm. (5.1 WebVTT file parsing.)
154 // 1-3 - Initial setup. 154 // Steps 1 - 3 - Initial setup.
155 155
156 String line; 156 String line;
157 while (m_lineReader.getLine(line)) { 157 while (m_lineReader.getLine(line)) {
158 switch (m_state) { 158 switch (m_state) {
159 case Initial: 159 case Initial:
160 // 4-12 - Check for a valid WebVTT signature. 160 // Steps 4 - 9 - Check for a valid WebVTT signature.
161 if (!hasRequiredFileIdentifier(line)) { 161 if (!hasRequiredFileIdentifier(line)) {
162 if (m_client) 162 if (m_client)
163 m_client->fileFailedToParse(); 163 m_client->fileFailedToParse();
164 return; 164 return;
165 } 165 }
166 166
167 m_state = Header; 167 m_state = Header;
168 break; 168 break;
169 169
170 case Header: 170 case Header:
171 // Steps 10 - 14 - Allow a header (comment area) under the WEBVTT li ne.
171 collectMetadataHeader(line); 172 collectMetadataHeader(line);
172 173
173 // 13-18 - Allow a header (comment area) under the WEBVTT line.
174 if (line.isEmpty()) { 174 if (line.isEmpty()) {
175 if (m_client && m_regionList.size()) 175 if (m_client && m_regionList.size())
176 m_client->newRegionsParsed(); 176 m_client->newRegionsParsed();
177 177
178 m_state = Id; 178 m_state = Id;
179 break; 179 break;
180 } 180 }
181 181
182 // Step 16 - Line is not the empty string and does not contain "-->" .
182 break; 183 break;
183 184
184 case Id: 185 case Id:
185 // 19-29 - Allow any number of line terminators, then initialize new cue values. 186 // Steps 17 - 20 - Allow any number of line terminators, then initia lize new cue values.
186 if (line.isEmpty()) 187 if (line.isEmpty())
187 break; 188 break;
189
190 // Step 21 - Cue creation (start a new cue).
188 resetCueValues(); 191 resetCueValues();
189 192
190 // 30-39 - Check if this line contains an optional identifier or tim ing data. 193 // Steps 22 - 25 - Check if this line contains an optional identifie r or timing data.
191 m_state = collectCueId(line); 194 m_state = collectCueId(line);
192 break; 195 break;
193 196
194 case TimingsAndSettings: 197 case TimingsAndSettings:
198 // Steps 26 - 27 - Discard current cue if the line is empty.
195 if (line.isEmpty()) { 199 if (line.isEmpty()) {
196 m_state = Id; 200 m_state = Id;
197 break; 201 break;
198 } 202 }
199 203
200 // 40 - Collect cue timings and settings. 204 // Steps 28 - 29 - Collect cue timings and settings.
201 m_state = collectTimingsAndSettings(line); 205 m_state = collectTimingsAndSettings(line);
202 break; 206 break;
203 207
204 case CueText: 208 case CueText:
205 // 41-53 - Collect the cue text, create a cue, and add it to the out put. 209 // Steps 31 - 41 - Collect the cue text, create a cue, and add it to the output.
206 m_state = collectCueText(line); 210 m_state = collectCueText(line);
207 break; 211 break;
208 212
209 case BadCue: 213 case BadCue:
210 // 54-62 - Collect and discard the remaining cue. 214 // Steps 42 - 48 - Discard lines until an empty line or a potential timing line is seen.
211 m_state = ignoreBadCue(line); 215 m_state = ignoreBadCue(line);
212 break; 216 break;
213 } 217 }
214 } 218 }
215 } 219 }
216 220
217 void WebVTTParser::flushPendingCue() 221 void WebVTTParser::flushPendingCue()
218 { 222 {
219 ASSERT(m_lineReader.isAtEndOfStream()); 223 ASSERT(m_lineReader.isAtEndOfStream());
220 // If we're in the CueText state when we run out of data, we emit the pendin g cue. 224 // If we're in the CueText state when we run out of data, we emit the pendin g cue.
221 if (m_state == CueText) 225 if (m_state == CueText)
222 createNewCue(); 226 createNewCue();
223 } 227 }
224 228
225 bool WebVTTParser::hasRequiredFileIdentifier(const String& line) 229 bool WebVTTParser::hasRequiredFileIdentifier(const String& line)
226 { 230 {
227 // A WebVTT file identifier consists of an optional BOM character, 231 // A WebVTT file identifier consists of an optional BOM character,
228 // the string "WEBVTT" followed by an optional space or tab character, 232 // the string "WEBVTT" followed by an optional space or tab character,
229 // and any number of characters that are not line terminators ... 233 // and any number of characters that are not line terminators ...
230 if (!line.startsWith("WEBVTT", fileIdentifierLength)) 234 if (!line.startsWith("WEBVTT", fileIdentifierLength))
231 return false; 235 return false;
232 if (line.length() > fileIdentifierLength && !isASpace(line[fileIdentifierLen gth])) 236 if (line.length() > fileIdentifierLength && !isASpace(line[fileIdentifierLen gth]))
233 return false; 237 return false;
234 238
235 return true; 239 return true;
236 } 240 }
237 241
238 void WebVTTParser::collectMetadataHeader(const String& line) 242 void WebVTTParser::collectMetadataHeader(const String& line)
239 { 243 {
240 // 4.1 Extension of WebVTT header parsing (11 - 15) 244 // WebVTT header parsing (WebVTT parser algorithm step 12)
241 DEFINE_STATIC_LOCAL(const AtomicString, regionHeaderName, ("Region", AtomicS tring::ConstructFromLiteral)); 245 DEFINE_STATIC_LOCAL(const AtomicString, regionHeaderName, ("Region", AtomicS tring::ConstructFromLiteral));
242 246
243 // 15.4 If line contains the character ":" (A U+003A COLON), then set metada ta's 247 // Step 12.4 If line contains the character ":" (A U+003A COLON), then set m etadata's
244 // name to the substring of line before the first ":" character and 248 // name to the substring of line before the first ":" character and
245 // metadata's value to the substring after this character. 249 // metadata's value to the substring after this character.
246 if (!RuntimeEnabledFeatures::webVTTRegionsEnabled() || !line.contains(":")) 250 if (!RuntimeEnabledFeatures::webVTTRegionsEnabled() || !line.contains(":"))
247 return; 251 return;
248 252
249 unsigned colonPosition = line.find(":"); 253 unsigned colonPosition = line.find(":");
250 String headerName = line.substring(0, colonPosition); 254 String headerName = line.substring(0, colonPosition);
251 255
252 // 15.5 If metadata's name equals "Region": 256 // Steps 12.5 If metadata's name equals "Region":
253 if (headerName == regionHeaderName) { 257 if (headerName == regionHeaderName) {
254 String headerValue = line.substring(colonPosition + 1); 258 String headerValue = line.substring(colonPosition + 1);
255 // 15.5.1 - 15.5.8 Region creation: Let region be a new text track regio n [...] 259 // Steps 12.5.1 - 12.5.11 Region creation: Let region be a new text trac k region [...]
256 createNewRegion(headerValue); 260 createNewRegion(headerValue);
257 } 261 }
258 } 262 }
259 263
260 WebVTTParser::ParseState WebVTTParser::collectCueId(const String& line) 264 WebVTTParser::ParseState WebVTTParser::collectCueId(const String& line)
261 { 265 {
262 if (line.contains("-->")) 266 if (line.contains("-->"))
263 return collectTimingsAndSettings(line); 267 return collectTimingsAndSettings(line);
264 m_currentId = line; 268 m_currentId = line;
265 return TimingsAndSettings; 269 return TimingsAndSettings;
266 } 270 }
267 271
268 WebVTTParser::ParseState WebVTTParser::collectTimingsAndSettings(const String& l ine) 272 WebVTTParser::ParseState WebVTTParser::collectTimingsAndSettings(const String& l ine)
269 { 273 {
270 // 4.8.10.13.3 Collect WebVTT cue timings and settings. 274 // Collect WebVTT cue timings and settings. (5.3 WebVTT cue timings and sett ings parsing.)
271 // 1-3 - Let input be the string being parsed and position be a pointer into input 275 // Steps 1 - 3 - Let input be the string being parsed and position be a poin ter into input.
272 unsigned position = 0; 276 unsigned position = 0;
273 skipWhiteSpace(line, &position); 277 skipWhiteSpace(line, &position);
274 278
275 // 4-5 - Collect a WebVTT timestamp. If that fails, then abort and return fa ilure. Otherwise, let cue's text track cue start time be the collected time. 279 // Steps 4 - 5 - Collect a WebVTT timestamp. If that fails, then abort and r eturn failure. Otherwise, let cue's text track cue start time be the collected t ime.
276 m_currentStartTime = collectTimeStamp(line, &position); 280 m_currentStartTime = collectTimeStamp(line, &position);
277 if (m_currentStartTime == malformedTime) 281 if (m_currentStartTime == malformedTime)
278 return BadCue; 282 return BadCue;
279 if (position >= line.length()) 283 if (position >= line.length())
280 return BadCue; 284 return BadCue;
281 285
282 skipWhiteSpace(line, &position); 286 skipWhiteSpace(line, &position);
283 287
284 // 6-9 - If the next three characters are not "-->", abort and return failur e. 288 // Steps 6 - 9 - If the next three characters are not "-->", abort and retur n failure.
285 if (line.find("-->", position) == kNotFound) 289 if (line.find("-->", position) == kNotFound)
286 return BadCue; 290 return BadCue;
287 position += 3; 291 position += 3;
288 if (position >= line.length()) 292 if (position >= line.length())
289 return BadCue; 293 return BadCue;
290 294
291 skipWhiteSpace(line, &position); 295 skipWhiteSpace(line, &position);
292 296
293 // 10-11 - Collect a WebVTT timestamp. If that fails, then abort and return failure. Otherwise, let cue's text track cue end time be the collected time. 297 // Steps 10 - 11 - Collect a WebVTT timestamp. If that fails, then abort and return failure. Otherwise, let cue's text track cue end time be the collected t ime.
294 m_currentEndTime = collectTimeStamp(line, &position); 298 m_currentEndTime = collectTimeStamp(line, &position);
295 if (m_currentEndTime == malformedTime) 299 if (m_currentEndTime == malformedTime)
296 return BadCue; 300 return BadCue;
297 skipWhiteSpace(line, &position); 301 skipWhiteSpace(line, &position);
298 302
299 // 12 - Parse the WebVTT settings for the cue (conducted in TextTrackCue). 303 // Step 12 - Parse the WebVTT settings for the cue (conducted in TextTrackCu e).
300 m_currentSettings = line.substring(position, line.length()-1); 304 m_currentSettings = line.substring(position, line.length()-1);
301 return CueText; 305 return CueText;
302 } 306 }
303 307
304 WebVTTParser::ParseState WebVTTParser::collectCueText(const String& line) 308 WebVTTParser::ParseState WebVTTParser::collectCueText(const String& line)
305 { 309 {
306 if (line.isEmpty()) { 310 if (line.isEmpty()) {
307 createNewCue(); 311 createNewCue();
308 return Id; 312 return Id;
309 } 313 }
(...skipping 24 matching lines...) Expand all
334 338
335 WebVTTToken m_token; 339 WebVTTToken m_token;
336 RefPtr<ContainerNode> m_currentNode; 340 RefPtr<ContainerNode> m_currentNode;
337 Vector<AtomicString> m_languageStack; 341 Vector<AtomicString> m_languageStack;
338 Document& m_document; 342 Document& m_document;
339 }; 343 };
340 344
341 PassRefPtr<DocumentFragment> WebVTTTreeBuilder::buildFromString(const String& cu eText) 345 PassRefPtr<DocumentFragment> WebVTTTreeBuilder::buildFromString(const String& cu eText)
342 { 346 {
343 // Cue text processing based on 347 // Cue text processing based on
344 // 4.8.10.13.4 WebVTT cue text parsing rules and 348 // 5.4 WebVTT cue text parsing rules, and
345 // 4.8.10.13.5 WebVTT cue text DOM construction rules. 349 // 5.5 WebVTT cue text DOM construction rules
346 350
347 RefPtr<DocumentFragment> fragment = DocumentFragment::create(m_document); 351 RefPtr<DocumentFragment> fragment = DocumentFragment::create(m_document);
348 352
349 if (cueText.isEmpty()) { 353 if (cueText.isEmpty()) {
350 fragment->parserAppendChild(Text::create(m_document, "")); 354 fragment->parserAppendChild(Text::create(m_document, ""));
351 return fragment; 355 return fragment;
352 } 356 }
353 357
354 m_currentNode = fragment; 358 m_currentNode = fragment;
355 359
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
388 m_currentStartTime = 0; 392 m_currentStartTime = 0;
389 m_currentEndTime = 0; 393 m_currentEndTime = 0;
390 m_currentContent.clear(); 394 m_currentContent.clear();
391 } 395 }
392 396
393 void WebVTTParser::createNewRegion(const String& headerValue) 397 void WebVTTParser::createNewRegion(const String& headerValue)
394 { 398 {
395 if (headerValue.isEmpty()) 399 if (headerValue.isEmpty())
396 return; 400 return;
397 401
402 // Steps 12.5.1 - 12.5.9 - Construct and initialize a WebVTT Region object.
398 RefPtr<VTTRegion> region = VTTRegion::create(); 403 RefPtr<VTTRegion> region = VTTRegion::create();
399 region->setRegionSettings(headerValue); 404 region->setRegionSettings(headerValue);
400 405
401 // 15.5.10 If the text track list of regions regions contains a region 406 // Step 12.5.10 If the text track list of regions regions contains a region
402 // with the same region identifier value as region, remove that region. 407 // with the same region identifier value as region, remove that region.
403 for (size_t i = 0; i < m_regionList.size(); ++i) 408 for (size_t i = 0; i < m_regionList.size(); ++i)
404 if (m_regionList[i]->id() == region->id()) { 409 if (m_regionList[i]->id() == region->id()) {
405 m_regionList.remove(i); 410 m_regionList.remove(i);
406 break; 411 break;
407 } 412 }
408 413
414 // Step 12.5.11
409 m_regionList.append(region); 415 m_regionList.append(region);
410 } 416 }
411 417
412 double WebVTTParser::collectTimeStamp(const String& line, unsigned* position) 418 double WebVTTParser::collectTimeStamp(const String& line, unsigned* position)
413 { 419 {
414 // 4.8.10.13.3 Collect a WebVTT timestamp. 420 // Collect a WebVTT timestamp (5.3 WebVTT cue timings and settings parsing.)
415 // 1-4 - Initial checks, let most significant units be minutes. 421 // Steps 1 - 4 - Initial checks, let most significant units be minutes.
416 enum Mode { minutes, hours }; 422 enum Mode { minutes, hours };
417 Mode mode = minutes; 423 Mode mode = minutes;
418 if (*position >= line.length() || !isASCIIDigit(line[*position])) 424 if (*position >= line.length() || !isASCIIDigit(line[*position]))
419 return malformedTime; 425 return malformedTime;
420 426
421 // 5-6 - Collect a sequence of characters that are 0-9. 427 // Steps 5 - 6 - Collect a sequence of characters that are 0-9.
422 String digits1 = collectDigits(line, position); 428 String digits1 = collectDigits(line, position);
423 int value1 = digits1.toInt(); 429 int value1 = digits1.toInt();
424 430
425 // 7 - If not 2 characters or value is greater than 59, interpret as hours. 431 // Step 7 - If not 2 characters or value is greater than 59, interpret as ho urs.
426 if (digits1.length() != 2 || value1 > 59) 432 if (digits1.length() != 2 || value1 > 59)
427 mode = hours; 433 mode = hours;
428 434
429 // 8-12 - Collect the next sequence of 0-9 after ':' (must be 2 chars). 435 // Steps 8 - 11 - Collect the next sequence of 0-9 after ':' (must be 2 char s).
430 if (*position >= line.length() || line[(*position)++] != ':') 436 if (*position >= line.length() || line[(*position)++] != ':')
431 return malformedTime; 437 return malformedTime;
432 if (*position >= line.length() || !isASCIIDigit(line[(*position)])) 438 if (*position >= line.length() || !isASCIIDigit(line[(*position)]))
433 return malformedTime; 439 return malformedTime;
434 String digits2 = collectDigits(line, position); 440 String digits2 = collectDigits(line, position);
435 int value2 = digits2.toInt(); 441 int value2 = digits2.toInt();
436 if (digits2.length() != 2) 442 if (digits2.length() != 2)
437 return malformedTime; 443 return malformedTime;
438 444
439 // 13 - Detect whether this timestamp includes hours. 445 // Step 12 - Detect whether this timestamp includes hours.
440 int value3; 446 int value3;
441 if (mode == hours || (*position < line.length() && line[*position] == ':')) { 447 if (mode == hours || (*position < line.length() && line[*position] == ':')) {
442 if (*position >= line.length() || line[(*position)++] != ':') 448 if (*position >= line.length() || line[(*position)++] != ':')
443 return malformedTime; 449 return malformedTime;
444 if (*position >= line.length() || !isASCIIDigit(line[*position])) 450 if (*position >= line.length() || !isASCIIDigit(line[*position]))
445 return malformedTime; 451 return malformedTime;
446 String digits3 = collectDigits(line, position); 452 String digits3 = collectDigits(line, position);
447 if (digits3.length() != 2) 453 if (digits3.length() != 2)
448 return malformedTime; 454 return malformedTime;
449 value3 = digits3.toInt(); 455 value3 = digits3.toInt();
450 } else { 456 } else {
451 value3 = value2; 457 value3 = value2;
452 value2 = value1; 458 value2 = value1;
453 value1 = 0; 459 value1 = 0;
454 } 460 }
455 461
456 // 14-19 - Collect next sequence of 0-9 after '.' (must be 3 chars). 462 // Steps 13 - 17 - Collect next sequence of 0-9 after '.' (must be 3 chars).
457 if (*position >= line.length() || line[(*position)++] != '.') 463 if (*position >= line.length() || line[(*position)++] != '.')
458 return malformedTime; 464 return malformedTime;
459 if (*position >= line.length() || !isASCIIDigit(line[*position])) 465 if (*position >= line.length() || !isASCIIDigit(line[*position]))
460 return malformedTime; 466 return malformedTime;
461 String digits4 = collectDigits(line, position); 467 String digits4 = collectDigits(line, position);
462 if (digits4.length() != 3) 468 if (digits4.length() != 3)
463 return malformedTime; 469 return malformedTime;
464 int value4 = digits4.toInt(); 470 int value4 = digits4.toInt();
465 if (value2 > 59 || value3 > 59) 471 if (value2 > 59 || value3 > 59)
466 return malformedTime; 472 return malformedTime;
467 473
468 // 20-21 - Calculate result. 474 // Steps 18 - 19 - Calculate result.
469 return (value1 * secondsPerHour) + (value2 * secondsPerMinute) + value3 + (v alue4 * secondsPerMillisecond); 475 return (value1 * secondsPerHour) + (value2 * secondsPerMinute) + value3 + (v alue4 * secondsPerMillisecond);
470 } 476 }
471 477
472 static WebVTTNodeType tokenToNodeType(WebVTTToken& token) 478 static WebVTTNodeType tokenToNodeType(WebVTTToken& token)
473 { 479 {
474 switch (token.name().size()) { 480 switch (token.name().size()) {
475 case 1: 481 case 1:
476 if (token.name()[0] == 'c') 482 if (token.name()[0] == 'c')
477 return WebVTTNodeTypeClass; 483 return WebVTTNodeTypeClass;
478 if (token.name()[0] == 'v') 484 if (token.name()[0] == 'v')
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
558 } 564 }
559 565
560 void WebVTTParser::skipWhiteSpace(const String& line, unsigned* position) 566 void WebVTTParser::skipWhiteSpace(const String& line, unsigned* position)
561 { 567 {
562 while (*position < line.length() && isASpace(line[*position])) 568 while (*position < line.length() && isASpace(line[*position]))
563 (*position)++; 569 (*position)++;
564 } 570 }
565 571
566 } 572 }
567 573
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698