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