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 25 matching lines...) Expand all Loading... |
36 #include "core/dom/Text.h" | 36 #include "core/dom/Text.h" |
37 #include "core/html/track/vtt/VTTElement.h" | 37 #include "core/html/track/vtt/VTTElement.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; | |
47 const unsigned fileIdentifierLength = 6; | 46 const unsigned fileIdentifierLength = 6; |
48 | 47 |
49 static unsigned scanDigits(const String& input, unsigned* position) | 48 static unsigned scanDigits(const String& input, unsigned* position) |
50 { | 49 { |
51 unsigned startPosition = *position; | 50 unsigned startPosition = *position; |
52 while (*position < input.length() && isASCIIDigit(input[*position])) | 51 while (*position < input.length() && isASCIIDigit(input[*position])) |
53 (*position)++; | 52 (*position)++; |
54 return *position - startPosition; | 53 return *position - startPosition; |
55 } | 54 } |
56 | 55 |
(...skipping 27 matching lines...) Expand all Loading... |
84 string.append(input[(*position)++]); | 83 string.append(input[(*position)++]); |
85 return string.toString(); | 84 return string.toString(); |
86 } | 85 } |
87 | 86 |
88 void VTTParser::skipWhiteSpace(const String& line, unsigned* position) | 87 void VTTParser::skipWhiteSpace(const String& line, unsigned* position) |
89 { | 88 { |
90 while (*position < line.length() && isASpace(line[*position])) | 89 while (*position < line.length() && isASpace(line[*position])) |
91 (*position)++; | 90 (*position)++; |
92 } | 91 } |
93 | 92 |
94 float VTTParser::parseFloatPercentageValue(const String& value, bool& isValidSet
ting) | 93 bool VTTParser::parseFloatPercentageValue(const String& value, float& percentage
) |
95 { | 94 { |
96 // '%' must be present and at the end of the setting value. | 95 // '%' must be present and at the end of the setting value. |
97 if (value.find('%', 1) != value.length() - 1) { | 96 if (value.isEmpty() || value[value.length() - 1] != '%') |
98 isValidSetting = false; | 97 return false; |
99 return 0; | |
100 } | |
101 | 98 |
102 unsigned position = 0; | 99 unsigned position = 0; |
103 unsigned digitsBeforeDot = scanDigits(value, &position); | 100 unsigned digitsBeforeDot = scanDigits(value, &position); |
104 unsigned digitsAfterDot = 0; | 101 unsigned digitsAfterDot = 0; |
105 if (value[position] == '.') { | 102 if (value[position] == '.') { |
106 position++; | 103 position++; |
107 | 104 |
108 digitsAfterDot = scanDigits(value, &position); | 105 digitsAfterDot = scanDigits(value, &position); |
109 } | 106 } |
110 | 107 |
111 // At least one digit required. | 108 // At least one digit required. |
112 if (!digitsBeforeDot && !digitsAfterDot) { | 109 if (!digitsBeforeDot && !digitsAfterDot) |
113 isValidSetting = false; | 110 return false; |
114 return 0; | |
115 } | |
116 | 111 |
117 float number = value.toFloat(); | 112 float number = value.toFloat(); |
118 isValidSetting = number >= 0 && number <= 100; | 113 if (number < 0 || number > 100) |
119 return number; | 114 return false; |
| 115 |
| 116 percentage = number; |
| 117 return true; |
120 } | 118 } |
121 | 119 |
122 FloatPoint VTTParser::parseFloatPercentageValuePair(const String& value, char de
limiter, bool& isValidSetting) | 120 bool VTTParser::parseFloatPercentageValuePair(const String& value, char delimite
r, FloatPoint& valuePair) |
123 { | 121 { |
124 // The delimiter can't be the first or second value because a pair of | 122 // The delimiter can't be the first or second value because a pair of |
125 // percentages (x%,y%) implies that at least the first two characters | 123 // percentages (x%,y%) implies that at least the first two characters |
126 // are the first percentage value. | 124 // are the first percentage value. |
127 size_t delimiterOffset = value.find(delimiter, 2); | 125 size_t delimiterOffset = value.find(delimiter, 2); |
128 if (delimiterOffset == kNotFound || delimiterOffset == value.length() - 1) { | 126 if (delimiterOffset == kNotFound || delimiterOffset == value.length() - 1) |
129 isValidSetting = false; | 127 return false; |
130 return FloatPoint(0, 0); | |
131 } | |
132 | 128 |
133 bool isFirstValueValid; | 129 float firstCoord; |
134 float firstCoord = parseFloatPercentageValue(value.substring(0, delimiterOff
set), isFirstValueValid); | 130 if (!parseFloatPercentageValue(value.substring(0, delimiterOffset), firstCoo
rd)) |
| 131 return false; |
135 | 132 |
136 bool isSecondValueValid; | 133 float secondCoord; |
137 float secondCoord = parseFloatPercentageValue(value.substring(delimiterOffse
t + 1, value.length() - 1), isSecondValueValid); | 134 if (!parseFloatPercentageValue(value.substring(delimiterOffset + 1, value.le
ngth() - 1), secondCoord)) |
| 135 return false; |
138 | 136 |
139 isValidSetting = isFirstValueValid && isSecondValueValid; | 137 valuePair = FloatPoint(firstCoord, secondCoord); |
140 return FloatPoint(firstCoord, secondCoord); | 138 return true; |
141 } | 139 } |
142 | 140 |
143 VTTParser::VTTParser(VTTParserClient* client, Document& document) | 141 VTTParser::VTTParser(VTTParserClient* client, Document& document) |
144 : m_document(&document) | 142 : m_document(&document) |
145 , m_state(Initial) | 143 , m_state(Initial) |
146 , m_decoder(TextResourceDecoder::create("text/plain", UTF8Encoding())) | 144 , m_decoder(TextResourceDecoder::create("text/plain", UTF8Encoding())) |
147 , m_currentStartTime(0) | 145 , m_currentStartTime(0) |
148 , m_currentEndTime(0) | 146 , m_currentEndTime(0) |
149 , m_client(client) | 147 , m_client(client) |
150 { | 148 { |
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
308 } | 306 } |
309 | 307 |
310 VTTParser::ParseState VTTParser::collectTimingsAndSettings(const String& line) | 308 VTTParser::ParseState VTTParser::collectTimingsAndSettings(const String& line) |
311 { | 309 { |
312 // Collect WebVTT cue timings and settings. (5.3 WebVTT cue timings and sett
ings parsing.) | 310 // Collect WebVTT cue timings and settings. (5.3 WebVTT cue timings and sett
ings parsing.) |
313 // Steps 1 - 3 - Let input be the string being parsed and position be a poin
ter into input. | 311 // Steps 1 - 3 - Let input be the string being parsed and position be a poin
ter into input. |
314 unsigned position = 0; | 312 unsigned position = 0; |
315 skipWhiteSpace(line, &position); | 313 skipWhiteSpace(line, &position); |
316 | 314 |
317 // 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. | 315 // 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. |
318 m_currentStartTime = collectTimeStamp(line, &position); | 316 if (!collectTimeStamp(line, &position, m_currentStartTime)) |
319 if (m_currentStartTime == malformedTime) | |
320 return BadCue; | 317 return BadCue; |
321 if (position >= line.length()) | 318 if (position >= line.length()) |
322 return BadCue; | 319 return BadCue; |
323 | 320 |
324 skipWhiteSpace(line, &position); | 321 skipWhiteSpace(line, &position); |
325 | 322 |
326 // Steps 6 - 9 - If the next three characters are not "-->", abort and retur
n failure. | 323 // Steps 6 - 9 - If the next three characters are not "-->", abort and retur
n failure. |
327 if (line.find("-->", position) == kNotFound) | 324 if (line.find("-->", position) == kNotFound) |
328 return BadCue; | 325 return BadCue; |
329 position += 3; | 326 position += 3; |
330 if (position >= line.length()) | 327 if (position >= line.length()) |
331 return BadCue; | 328 return BadCue; |
332 | 329 |
333 skipWhiteSpace(line, &position); | 330 skipWhiteSpace(line, &position); |
334 | 331 |
335 // 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. | 332 // 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. |
336 m_currentEndTime = collectTimeStamp(line, &position); | 333 if (!collectTimeStamp(line, &position, m_currentEndTime)) |
337 if (m_currentEndTime == malformedTime) | |
338 return BadCue; | 334 return BadCue; |
339 skipWhiteSpace(line, &position); | 335 skipWhiteSpace(line, &position); |
340 | 336 |
341 // Step 12 - Parse the WebVTT settings for the cue (conducted in TextTrackCu
e). | 337 // Step 12 - Parse the WebVTT settings for the cue (conducted in TextTrackCu
e). |
342 m_currentSettings = line.substring(position, line.length()-1); | 338 m_currentSettings = line.substring(position, line.length()-1); |
343 return CueText; | 339 return CueText; |
344 } | 340 } |
345 | 341 |
346 VTTParser::ParseState VTTParser::collectCueText(const String& line) | 342 VTTParser::ParseState VTTParser::collectCueText(const String& line) |
347 { | 343 { |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
465 if (m_regionList[i]->id() == region->id()) { | 461 if (m_regionList[i]->id() == region->id()) { |
466 m_regionList.remove(i); | 462 m_regionList.remove(i); |
467 break; | 463 break; |
468 } | 464 } |
469 } | 465 } |
470 | 466 |
471 // Step 12.5.11 | 467 // Step 12.5.11 |
472 m_regionList.append(region); | 468 m_regionList.append(region); |
473 } | 469 } |
474 | 470 |
475 double VTTParser::collectTimeStamp(const String& line, unsigned* position) | 471 bool VTTParser::collectTimeStamp(const String& line, unsigned* position, double&
timeStamp) |
476 { | 472 { |
477 // Collect a WebVTT timestamp (5.3 WebVTT cue timings and settings parsing.) | 473 // Collect a WebVTT timestamp (5.3 WebVTT cue timings and settings parsing.) |
478 // Steps 1 - 4 - Initial checks, let most significant units be minutes. | 474 // Steps 1 - 4 - Initial checks, let most significant units be minutes. |
479 enum Mode { Minutes, Hours }; | 475 enum Mode { Minutes, Hours }; |
480 Mode mode = Minutes; | 476 Mode mode = Minutes; |
481 | 477 |
482 // Steps 5 - 7 - Collect a sequence of characters that are 0-9. | 478 // Steps 5 - 7 - Collect a sequence of characters that are 0-9. |
483 // If not 2 characters or value is greater than 59, interpret as hours. | 479 // If not 2 characters or value is greater than 59, interpret as hours. |
484 int value1; | 480 int value1; |
485 unsigned value1Digits = collectDigitsToInt(line, position, value1); | 481 unsigned value1Digits = collectDigitsToInt(line, position, value1); |
486 if (!value1Digits) | 482 if (!value1Digits) |
487 return malformedTime; | 483 return false; |
488 if (value1Digits != 2 || value1 > 59) | 484 if (value1Digits != 2 || value1 > 59) |
489 mode = Hours; | 485 mode = Hours; |
490 | 486 |
491 // Steps 8 - 11 - Collect the next sequence of 0-9 after ':' (must be 2 char
s). | 487 // Steps 8 - 11 - Collect the next sequence of 0-9 after ':' (must be 2 char
s). |
492 if (*position >= line.length() || line[(*position)++] != ':') | 488 if (*position >= line.length() || line[(*position)++] != ':') |
493 return malformedTime; | 489 return false; |
494 int value2; | 490 int value2; |
495 if (collectDigitsToInt(line, position, value2) != 2) | 491 if (collectDigitsToInt(line, position, value2) != 2) |
496 return malformedTime; | 492 return false; |
497 | 493 |
498 // Step 12 - Detect whether this timestamp includes hours. | 494 // Step 12 - Detect whether this timestamp includes hours. |
499 int value3; | 495 int value3; |
500 if (mode == Hours || (*position < line.length() && line[*position] == ':'))
{ | 496 if (mode == Hours || (*position < line.length() && line[*position] == ':'))
{ |
501 if (*position >= line.length() || line[(*position)++] != ':') | 497 if (*position >= line.length() || line[(*position)++] != ':') |
502 return malformedTime; | 498 return false; |
503 if (collectDigitsToInt(line, position, value3) != 2) | 499 if (collectDigitsToInt(line, position, value3) != 2) |
504 return malformedTime; | 500 return false; |
505 } else { | 501 } else { |
506 value3 = value2; | 502 value3 = value2; |
507 value2 = value1; | 503 value2 = value1; |
508 value1 = 0; | 504 value1 = 0; |
509 } | 505 } |
510 | 506 |
511 // Steps 13 - 17 - Collect next sequence of 0-9 after '.' (must be 3 chars). | 507 // Steps 13 - 17 - Collect next sequence of 0-9 after '.' (must be 3 chars). |
512 if (*position >= line.length() || line[(*position)++] != '.') | 508 if (*position >= line.length() || line[(*position)++] != '.') |
513 return malformedTime; | 509 return false; |
514 int value4; | 510 int value4; |
515 if (collectDigitsToInt(line, position, value4) != 3) | 511 if (collectDigitsToInt(line, position, value4) != 3) |
516 return malformedTime; | 512 return false; |
517 if (value2 > 59 || value3 > 59) | 513 if (value2 > 59 || value3 > 59) |
518 return malformedTime; | 514 return false; |
519 | 515 |
520 // Steps 18 - 19 - Calculate result. | 516 // Steps 18 - 19 - Calculate result. |
521 return (value1 * secondsPerHour) + (value2 * secondsPerMinute) + value3 + (v
alue4 * secondsPerMillisecond); | 517 timeStamp = (value1 * secondsPerHour) + (value2 * secondsPerMinute) + value3
+ (value4 * secondsPerMillisecond); |
| 518 return true; |
522 } | 519 } |
523 | 520 |
524 static VTTNodeType tokenToNodeType(VTTToken& token) | 521 static VTTNodeType tokenToNodeType(VTTToken& token) |
525 { | 522 { |
526 switch (token.name().length()) { | 523 switch (token.name().length()) { |
527 case 1: | 524 case 1: |
528 if (token.name()[0] == 'c') | 525 if (token.name()[0] == 'c') |
529 return VTTNodeTypeClass; | 526 return VTTNodeTypeClass; |
530 if (token.name()[0] == 'v') | 527 if (token.name()[0] == 'v') |
531 return VTTNodeTypeVoice; | 528 return VTTNodeTypeVoice; |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
609 } | 606 } |
610 if (nodeType == VTTNodeTypeLanguage) | 607 if (nodeType == VTTNodeTypeLanguage) |
611 m_languageStack.removeLast(); | 608 m_languageStack.removeLast(); |
612 if (m_currentNode->parentNode()) | 609 if (m_currentNode->parentNode()) |
613 m_currentNode = m_currentNode->parentNode(); | 610 m_currentNode = m_currentNode->parentNode(); |
614 break; | 611 break; |
615 } | 612 } |
616 case VTTTokenTypes::TimestampTag: { | 613 case VTTTokenTypes::TimestampTag: { |
617 unsigned position = 0; | 614 unsigned position = 0; |
618 String charactersString = m_token.characters(); | 615 String charactersString = m_token.characters(); |
619 double time = VTTParser::collectTimeStamp(charactersString, &position); | 616 double parsedTimeStamp; |
620 if (time != malformedTime) | 617 if (VTTParser::collectTimeStamp(charactersString, &position, parsedTimeS
tamp)) |
621 m_currentNode->parserAppendChild(ProcessingInstruction::create(docum
ent, "timestamp", charactersString)); | 618 m_currentNode->parserAppendChild(ProcessingInstruction::create(docum
ent, "timestamp", charactersString)); |
622 break; | 619 break; |
623 } | 620 } |
624 default: | 621 default: |
625 break; | 622 break; |
626 } | 623 } |
627 } | 624 } |
628 | 625 |
629 } | 626 } |
630 | 627 |
OLD | NEW |