| 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 |