| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2011 Google Inc. All rights reserved. | 2 * Copyright (C) 2011 Google Inc. All rights reserved. |
| 3 * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved. | 3 * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved. |
| 4 * | 4 * |
| 5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
| 6 * modification, are permitted provided that the following conditions are | 6 * modification, are permitted provided that the following conditions are |
| 7 * met: | 7 * met: |
| 8 * | 8 * |
| 9 * * Redistributions of source code must retain the above copyright | 9 * * Redistributions of source code must retain the above copyright |
| 10 * notice, this list of conditions and the following disclaimer. | 10 * notice, this list of conditions and the following disclaimer. |
| (...skipping 14 matching lines...) Expand all Loading... |
| 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 30 */ | 30 */ |
| 31 | 31 |
| 32 #include "config.h" | 32 #include "config.h" |
| 33 #include "core/html/track/TextTrackCue.h" | 33 #include "core/html/track/TextTrackCue.h" |
| 34 | 34 |
| 35 #include "CSSPropertyNames.h" | |
| 36 #include "CSSValueKeywords.h" | |
| 37 #include "RuntimeEnabledFeatures.h" | |
| 38 #include "bindings/v8/ExceptionStatePlaceholder.h" | 35 #include "bindings/v8/ExceptionStatePlaceholder.h" |
| 39 #include "core/dom/DocumentFragment.h" | |
| 40 #include "core/events/Event.h" | 36 #include "core/events/Event.h" |
| 41 #include "core/dom/NodeTraversal.h" | |
| 42 #include "core/html/HTMLDivElement.h" | 37 #include "core/html/HTMLDivElement.h" |
| 43 #include "core/html/track/TextTrack.h" | 38 #include "core/html/track/TextTrack.h" |
| 44 #include "core/html/track/TextTrackCueList.h" | 39 #include "core/html/track/TextTrackCueList.h" |
| 45 #include "core/html/track/vtt/VTTElement.h" | |
| 46 #include "core/html/track/vtt/VTTParser.h" | |
| 47 #include "core/html/track/vtt/VTTRegionList.h" | |
| 48 #include "core/rendering/RenderTextTrackCue.h" | |
| 49 #include "wtf/MathExtras.h" | |
| 50 #include "wtf/text/StringBuilder.h" | |
| 51 | 40 |
| 52 namespace WebCore { | 41 namespace WebCore { |
| 53 | 42 |
| 54 static const int invalidCueIndex = -1; | 43 static const int invalidCueIndex = -1; |
| 55 static const int undefinedPosition = -1; | |
| 56 | 44 |
| 57 static const CSSValueID displayWritingModeMap[] = { | 45 // ---------------------------- |
| 58 CSSValueHorizontalTb, CSSValueVerticalRl, CSSValueVerticalLr | |
| 59 }; | |
| 60 COMPILE_ASSERT(WTF_ARRAY_LENGTH(displayWritingModeMap) == TextTrackCue::NumberOf
WritingDirections, | |
| 61 displayWritingModeMap_has_wrong_size); | |
| 62 | 46 |
| 63 static const CSSValueID displayAlignmentMap[] = { | 47 TextTrackCueBox::TextTrackCueBox(Document& document) |
| 64 CSSValueStart, CSSValueCenter, CSSValueEnd, CSSValueLeft, CSSValueRight | 48 : HTMLDivElement(document) |
| 65 }; | |
| 66 COMPILE_ASSERT(WTF_ARRAY_LENGTH(displayAlignmentMap) == TextTrackCue::NumberOfAl
ignments, | |
| 67 displayAlignmentMap_has_wrong_size); | |
| 68 | |
| 69 static const String& startKeyword() | |
| 70 { | 49 { |
| 71 DEFINE_STATIC_LOCAL(const String, start, ("start")); | |
| 72 return start; | |
| 73 } | |
| 74 | |
| 75 static const String& middleKeyword() | |
| 76 { | |
| 77 DEFINE_STATIC_LOCAL(const String, middle, ("middle")); | |
| 78 return middle; | |
| 79 } | |
| 80 | |
| 81 static const String& endKeyword() | |
| 82 { | |
| 83 DEFINE_STATIC_LOCAL(const String, end, ("end")); | |
| 84 return end; | |
| 85 } | |
| 86 | |
| 87 static const String& leftKeyword() | |
| 88 { | |
| 89 DEFINE_STATIC_LOCAL(const String, left, ("left")); | |
| 90 return left; | |
| 91 } | |
| 92 | |
| 93 static const String& rightKeyword() | |
| 94 { | |
| 95 DEFINE_STATIC_LOCAL(const String, right, ("right")); | |
| 96 return right; | |
| 97 } | |
| 98 | |
| 99 static const String& horizontalKeyword() | |
| 100 { | |
| 101 return emptyString(); | |
| 102 } | |
| 103 | |
| 104 static const String& verticalGrowingLeftKeyword() | |
| 105 { | |
| 106 DEFINE_STATIC_LOCAL(const String, verticalrl, ("rl")); | |
| 107 return verticalrl; | |
| 108 } | |
| 109 | |
| 110 static const String& verticalGrowingRightKeyword() | |
| 111 { | |
| 112 DEFINE_STATIC_LOCAL(const String, verticallr, ("lr")); | |
| 113 return verticallr; | |
| 114 } | 50 } |
| 115 | 51 |
| 116 // ---------------------------- | 52 // ---------------------------- |
| 117 | 53 |
| 118 TextTrackCueBox::TextTrackCueBox(Document& document, TextTrackCue* cue) | 54 TextTrackCue::TextTrackCue(double start, double end) |
| 119 : HTMLDivElement(document) | |
| 120 , m_cue(cue) | |
| 121 { | |
| 122 setPart(textTrackCueBoxShadowPseudoId()); | |
| 123 } | |
| 124 | |
| 125 TextTrackCue* TextTrackCueBox::getCue() const | |
| 126 { | |
| 127 return m_cue; | |
| 128 } | |
| 129 | |
| 130 void TextTrackCueBox::applyCSSProperties(const IntSize&) | |
| 131 { | |
| 132 // FIXME: Apply all the initial CSS positioning properties. http://wkb.ug/79
916 | |
| 133 if (!m_cue->regionId().isEmpty()) { | |
| 134 setInlineStyleProperty(CSSPropertyPosition, CSSValueRelative); | |
| 135 return; | |
| 136 } | |
| 137 | |
| 138 // 3.5.1 On the (root) List of WebVTT Node Objects: | |
| 139 | |
| 140 // the 'position' property must be set to 'absolute' | |
| 141 setInlineStyleProperty(CSSPropertyPosition, CSSValueAbsolute); | |
| 142 | |
| 143 // the 'unicode-bidi' property must be set to 'plaintext' | |
| 144 setInlineStyleProperty(CSSPropertyUnicodeBidi, CSSValueWebkitPlaintext); | |
| 145 | |
| 146 // the 'direction' property must be set to direction | |
| 147 setInlineStyleProperty(CSSPropertyDirection, m_cue->getCSSWritingDirection()
); | |
| 148 | |
| 149 // the 'writing-mode' property must be set to writing-mode | |
| 150 setInlineStyleProperty(CSSPropertyWebkitWritingMode, m_cue->getCSSWritingMod
e()); | |
| 151 | |
| 152 std::pair<float, float> position = m_cue->getCSSPosition(); | |
| 153 | |
| 154 // the 'top' property must be set to top, | |
| 155 setInlineStyleProperty(CSSPropertyTop, position.second, CSSPrimitiveValue::C
SS_PERCENTAGE); | |
| 156 | |
| 157 // the 'left' property must be set to left | |
| 158 setInlineStyleProperty(CSSPropertyLeft, position.first, CSSPrimitiveValue::C
SS_PERCENTAGE); | |
| 159 | |
| 160 // the 'width' property must be set to width, and the 'height' property mus
t be set to height | |
| 161 if (m_cue->vertical() == horizontalKeyword()) { | |
| 162 setInlineStyleProperty(CSSPropertyWidth, static_cast<double>(m_cue->getC
SSSize()), CSSPrimitiveValue::CSS_PERCENTAGE); | |
| 163 setInlineStyleProperty(CSSPropertyHeight, CSSValueAuto); | |
| 164 } else { | |
| 165 setInlineStyleProperty(CSSPropertyWidth, CSSValueAuto); | |
| 166 setInlineStyleProperty(CSSPropertyHeight, static_cast<double>(m_cue->get
CSSSize()), CSSPrimitiveValue::CSS_PERCENTAGE); | |
| 167 } | |
| 168 | |
| 169 // The 'text-align' property on the (root) List of WebVTT Node Objects must | |
| 170 // be set to the value in the second cell of the row of the table below | |
| 171 // whose first cell is the value of the corresponding cue's text track cue | |
| 172 // alignment: | |
| 173 setInlineStyleProperty(CSSPropertyTextAlign, m_cue->getCSSAlignment()); | |
| 174 | |
| 175 if (!m_cue->snapToLines()) { | |
| 176 // 10.13.1 Set up x and y: | |
| 177 // Note: x and y are set through the CSS left and top above. | |
| 178 | |
| 179 // 10.13.2 Position the boxes in boxes such that the point x% along the | |
| 180 // width of the bounding box of the boxes in boxes is x% of the way | |
| 181 // across the width of the video's rendering area, and the point y% | |
| 182 // along the height of the bounding box of the boxes in boxes is y% | |
| 183 // of the way across the height of the video's rendering area, while | |
| 184 // maintaining the relative positions of the boxes in boxes to each | |
| 185 // other. | |
| 186 setInlineStyleProperty(CSSPropertyWebkitTransform, | |
| 187 String::format("translate(-%.2f%%, -%.2f%%)", position.first, po
sition.second)); | |
| 188 | |
| 189 setInlineStyleProperty(CSSPropertyWhiteSpace, CSSValuePre); | |
| 190 } | |
| 191 } | |
| 192 | |
| 193 const AtomicString& TextTrackCueBox::textTrackCueBoxShadowPseudoId() | |
| 194 { | |
| 195 DEFINE_STATIC_LOCAL(const AtomicString, trackDisplayBoxShadowPseudoId, ("-we
bkit-media-text-track-display", AtomicString::ConstructFromLiteral)); | |
| 196 return trackDisplayBoxShadowPseudoId; | |
| 197 } | |
| 198 | |
| 199 RenderObject* TextTrackCueBox::createRenderer(RenderStyle*) | |
| 200 { | |
| 201 return new RenderTextTrackCue(this); | |
| 202 } | |
| 203 | |
| 204 // ---------------------------- | |
| 205 | |
| 206 TextTrackCue::TextTrackCue(Document& document, double start, double end, const S
tring& content) | |
| 207 : m_startTime(start) | 55 : m_startTime(start) |
| 208 , m_endTime(end) | 56 , m_endTime(end) |
| 209 , m_content(content) | |
| 210 , m_linePosition(undefinedPosition) | |
| 211 , m_computedLinePosition(undefinedPosition) | |
| 212 , m_textPosition(50) | |
| 213 , m_cueSize(100) | |
| 214 , m_cueIndex(invalidCueIndex) | 57 , m_cueIndex(invalidCueIndex) |
| 215 , m_writingDirection(Horizontal) | |
| 216 , m_cueAlignment(Middle) | |
| 217 , m_webVTTNodeTree(0) | |
| 218 , m_track(0) | 58 , m_track(0) |
| 219 , m_isActive(false) | 59 , m_isActive(false) |
| 220 , m_pauseOnExit(false) | 60 , m_pauseOnExit(false) |
| 221 , m_snapToLines(true) | |
| 222 , m_cueBackgroundBox(HTMLDivElement::create(document)) | |
| 223 , m_displayTreeShouldChange(true) | |
| 224 , m_displayDirection(CSSValueLtr) | |
| 225 , m_notifyRegion(true) | |
| 226 { | 61 { |
| 227 } | 62 } |
| 228 | 63 |
| 229 TextTrackCue::~TextTrackCue() | |
| 230 { | |
| 231 displayTreeInternal()->remove(ASSERT_NO_EXCEPTION); | |
| 232 } | |
| 233 | |
| 234 PassRefPtr<TextTrackCueBox> TextTrackCue::displayTreeInternal() | |
| 235 { | |
| 236 if (!m_displayTree) | |
| 237 m_displayTree = TextTrackCueBox::create(document(), this); | |
| 238 return m_displayTree; | |
| 239 } | |
| 240 | |
| 241 void TextTrackCue::cueWillChange() | 64 void TextTrackCue::cueWillChange() |
| 242 { | 65 { |
| 243 if (m_track) | 66 if (m_track) |
| 244 m_track->cueWillChange(this); | 67 m_track->cueWillChange(this); |
| 245 } | 68 } |
| 246 | 69 |
| 247 void TextTrackCue::cueDidChange() | 70 void TextTrackCue::cueDidChange() |
| 248 { | 71 { |
| 249 if (m_track) | 72 if (m_track) |
| 250 m_track->cueDidChange(this); | 73 m_track->cueDidChange(this); |
| 251 | |
| 252 m_displayTreeShouldChange = true; | |
| 253 } | 74 } |
| 254 | 75 |
| 255 TextTrack* TextTrackCue::track() const | 76 TextTrack* TextTrackCue::track() const |
| 256 { | 77 { |
| 257 return m_track; | 78 return m_track; |
| 258 } | 79 } |
| 259 | 80 |
| 260 void TextTrackCue::setTrack(TextTrack* track) | 81 void TextTrackCue::setTrack(TextTrack* track) |
| 261 { | 82 { |
| 262 m_track = track; | 83 m_track = track; |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 309 void TextTrackCue::setPauseOnExit(bool value) | 130 void TextTrackCue::setPauseOnExit(bool value) |
| 310 { | 131 { |
| 311 if (m_pauseOnExit == value) | 132 if (m_pauseOnExit == value) |
| 312 return; | 133 return; |
| 313 | 134 |
| 314 cueWillChange(); | 135 cueWillChange(); |
| 315 m_pauseOnExit = value; | 136 m_pauseOnExit = value; |
| 316 cueDidChange(); | 137 cueDidChange(); |
| 317 } | 138 } |
| 318 | 139 |
| 319 const String& TextTrackCue::vertical() const | |
| 320 { | |
| 321 switch (m_writingDirection) { | |
| 322 case Horizontal: | |
| 323 return horizontalKeyword(); | |
| 324 case VerticalGrowingLeft: | |
| 325 return verticalGrowingLeftKeyword(); | |
| 326 case VerticalGrowingRight: | |
| 327 return verticalGrowingRightKeyword(); | |
| 328 default: | |
| 329 ASSERT_NOT_REACHED(); | |
| 330 return emptyString(); | |
| 331 } | |
| 332 } | |
| 333 | |
| 334 void TextTrackCue::setVertical(const String& value, ExceptionState& exceptionSta
te) | |
| 335 { | |
| 336 // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-ele
ment.html#dom-texttrackcue-vertical | |
| 337 // On setting, the text track cue writing direction must be set to the value
given | |
| 338 // in the first cell of the row in the table above whose second cell is a | |
| 339 // case-sensitive match for the new value, if any. If none of the values mat
ch, then | |
| 340 // the user agent must instead throw a SyntaxError exception. | |
| 341 | |
| 342 WritingDirection direction = m_writingDirection; | |
| 343 if (value == horizontalKeyword()) | |
| 344 direction = Horizontal; | |
| 345 else if (value == verticalGrowingLeftKeyword()) | |
| 346 direction = VerticalGrowingLeft; | |
| 347 else if (value == verticalGrowingRightKeyword()) | |
| 348 direction = VerticalGrowingRight; | |
| 349 else | |
| 350 exceptionState.throwUninformativeAndGenericDOMException(SyntaxError); | |
| 351 | |
| 352 if (direction == m_writingDirection) | |
| 353 return; | |
| 354 | |
| 355 cueWillChange(); | |
| 356 m_writingDirection = direction; | |
| 357 cueDidChange(); | |
| 358 } | |
| 359 | |
| 360 void TextTrackCue::setSnapToLines(bool value) | |
| 361 { | |
| 362 if (m_snapToLines == value) | |
| 363 return; | |
| 364 | |
| 365 cueWillChange(); | |
| 366 m_snapToLines = value; | |
| 367 cueDidChange(); | |
| 368 } | |
| 369 | |
| 370 void TextTrackCue::setLine(int position, ExceptionState& exceptionState) | |
| 371 { | |
| 372 // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-ele
ment.html#dom-texttrackcue-line | |
| 373 // On setting, if the text track cue snap-to-lines flag is not set, and the
new | |
| 374 // value is negative or greater than 100, then throw an IndexSizeError excep
tion. | |
| 375 if (!m_snapToLines && (position < 0 || position > 100)) { | |
| 376 exceptionState.throwUninformativeAndGenericDOMException(IndexSizeError); | |
| 377 return; | |
| 378 } | |
| 379 | |
| 380 // Otherwise, set the text track cue line position to the new value. | |
| 381 if (m_linePosition == position) | |
| 382 return; | |
| 383 | |
| 384 cueWillChange(); | |
| 385 m_linePosition = position; | |
| 386 m_computedLinePosition = calculateComputedLinePosition(); | |
| 387 cueDidChange(); | |
| 388 } | |
| 389 | |
| 390 void TextTrackCue::setPosition(int position, ExceptionState& exceptionState) | |
| 391 { | |
| 392 // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-ele
ment.html#dom-texttrackcue-position | |
| 393 // On setting, if the new value is negative or greater than 100, then throw
an IndexSizeError exception. | |
| 394 // Otherwise, set the text track cue text position to the new value. | |
| 395 if (position < 0 || position > 100) { | |
| 396 exceptionState.throwUninformativeAndGenericDOMException(IndexSizeError); | |
| 397 return; | |
| 398 } | |
| 399 | |
| 400 // Otherwise, set the text track cue line position to the new value. | |
| 401 if (m_textPosition == position) | |
| 402 return; | |
| 403 | |
| 404 cueWillChange(); | |
| 405 m_textPosition = position; | |
| 406 cueDidChange(); | |
| 407 } | |
| 408 | |
| 409 void TextTrackCue::setSize(int size, ExceptionState& exceptionState) | |
| 410 { | |
| 411 // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-ele
ment.html#dom-texttrackcue-size | |
| 412 // On setting, if the new value is negative or greater than 100, then throw
an IndexSizeError | |
| 413 // exception. Otherwise, set the text track cue size to the new value. | |
| 414 if (size < 0 || size > 100) { | |
| 415 exceptionState.throwUninformativeAndGenericDOMException(IndexSizeError); | |
| 416 return; | |
| 417 } | |
| 418 | |
| 419 // Otherwise, set the text track cue line position to the new value. | |
| 420 if (m_cueSize == size) | |
| 421 return; | |
| 422 | |
| 423 cueWillChange(); | |
| 424 m_cueSize = size; | |
| 425 cueDidChange(); | |
| 426 } | |
| 427 | |
| 428 const String& TextTrackCue::align() const | |
| 429 { | |
| 430 switch (m_cueAlignment) { | |
| 431 case Start: | |
| 432 return startKeyword(); | |
| 433 case Middle: | |
| 434 return middleKeyword(); | |
| 435 case End: | |
| 436 return endKeyword(); | |
| 437 case Left: | |
| 438 return leftKeyword(); | |
| 439 case Right: | |
| 440 return rightKeyword(); | |
| 441 default: | |
| 442 ASSERT_NOT_REACHED(); | |
| 443 return emptyString(); | |
| 444 } | |
| 445 } | |
| 446 | |
| 447 void TextTrackCue::setAlign(const String& value, ExceptionState& exceptionState) | |
| 448 { | |
| 449 // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-ele
ment.html#dom-texttrackcue-align | |
| 450 // On setting, the text track cue alignment must be set to the value given i
n the | |
| 451 // first cell of the row in the table above whose second cell is a case-sens
itive | |
| 452 // match for the new value, if any. If none of the values match, then the us
er | |
| 453 // agent must instead throw a SyntaxError exception. | |
| 454 | |
| 455 CueAlignment alignment = m_cueAlignment; | |
| 456 if (value == startKeyword()) | |
| 457 alignment = Start; | |
| 458 else if (value == middleKeyword()) | |
| 459 alignment = Middle; | |
| 460 else if (value == endKeyword()) | |
| 461 alignment = End; | |
| 462 else if (value == leftKeyword()) | |
| 463 alignment = Left; | |
| 464 else if (value == rightKeyword()) | |
| 465 alignment = Right; | |
| 466 else | |
| 467 exceptionState.throwUninformativeAndGenericDOMException(SyntaxError); | |
| 468 | |
| 469 if (alignment == m_cueAlignment) | |
| 470 return; | |
| 471 | |
| 472 cueWillChange(); | |
| 473 m_cueAlignment = alignment; | |
| 474 cueDidChange(); | |
| 475 } | |
| 476 | |
| 477 void TextTrackCue::setText(const String& text) | |
| 478 { | |
| 479 if (m_content == text) | |
| 480 return; | |
| 481 | |
| 482 cueWillChange(); | |
| 483 // Clear the document fragment but don't bother to create it again just yet
as we can do that | |
| 484 // when it is requested. | |
| 485 m_webVTTNodeTree = 0; | |
| 486 m_content = text; | |
| 487 cueDidChange(); | |
| 488 } | |
| 489 | |
| 490 int TextTrackCue::cueIndex() | 140 int TextTrackCue::cueIndex() |
| 491 { | 141 { |
| 492 if (m_cueIndex == invalidCueIndex) | 142 if (m_cueIndex == invalidCueIndex) |
| 493 m_cueIndex = track()->cues()->getCueIndex(this); | 143 m_cueIndex = track()->cues()->getCueIndex(this); |
| 494 | 144 |
| 495 return m_cueIndex; | 145 return m_cueIndex; |
| 496 } | 146 } |
| 497 | 147 |
| 498 void TextTrackCue::invalidateCueIndex() | 148 void TextTrackCue::invalidateCueIndex() |
| 499 { | 149 { |
| 500 m_cueIndex = invalidCueIndex; | 150 m_cueIndex = invalidCueIndex; |
| 501 } | 151 } |
| 502 | 152 |
| 503 void TextTrackCue::createVTTNodeTree() | |
| 504 { | |
| 505 if (!m_webVTTNodeTree) | |
| 506 m_webVTTNodeTree = VTTParser::createDocumentFragmentFromCueText(document
(), m_content); | |
| 507 } | |
| 508 | |
| 509 void TextTrackCue::copyVTTNodeToDOMTree(ContainerNode* webVTTNode, ContainerNode
* parent) | |
| 510 { | |
| 511 for (Node* node = webVTTNode->firstChild(); node; node = node->nextSibling()
) { | |
| 512 RefPtr<Node> clonedNode; | |
| 513 if (node->isVTTElement()) | |
| 514 clonedNode = toVTTElement(node)->createEquivalentHTMLElement(documen
t()); | |
| 515 else | |
| 516 clonedNode = node->cloneNode(false); | |
| 517 parent->appendChild(clonedNode); | |
| 518 if (node->isContainerNode()) | |
| 519 copyVTTNodeToDOMTree(toContainerNode(node), toContainerNode(clonedNo
de)); | |
| 520 } | |
| 521 } | |
| 522 | |
| 523 PassRefPtr<DocumentFragment> TextTrackCue::getCueAsHTML() | |
| 524 { | |
| 525 createVTTNodeTree(); | |
| 526 RefPtr<DocumentFragment> clonedFragment = DocumentFragment::create(document(
)); | |
| 527 copyVTTNodeToDOMTree(m_webVTTNodeTree.get(), clonedFragment.get()); | |
| 528 return clonedFragment.release(); | |
| 529 } | |
| 530 | |
| 531 PassRefPtr<DocumentFragment> TextTrackCue::createCueRenderingTree() | |
| 532 { | |
| 533 RefPtr<DocumentFragment> clonedFragment; | |
| 534 createVTTNodeTree(); | |
| 535 clonedFragment = DocumentFragment::create(document()); | |
| 536 m_webVTTNodeTree->cloneChildNodes(clonedFragment.get()); | |
| 537 return clonedFragment.release(); | |
| 538 } | |
| 539 | |
| 540 bool TextTrackCue::dispatchEvent(PassRefPtr<Event> event) | 153 bool TextTrackCue::dispatchEvent(PassRefPtr<Event> event) |
| 541 { | 154 { |
| 542 // When a TextTrack's mode is disabled: no cues are active, no events fired. | 155 // When a TextTrack's mode is disabled: no cues are active, no events fired. |
| 543 if (!track() || track()->mode() == TextTrack::disabledKeyword()) | 156 if (!track() || track()->mode() == TextTrack::disabledKeyword()) |
| 544 return false; | 157 return false; |
| 545 | 158 |
| 546 return EventTarget::dispatchEvent(event); | 159 return EventTarget::dispatchEvent(event); |
| 547 } | 160 } |
| 548 | 161 |
| 549 void TextTrackCue::setRegionId(const String& regionId) | |
| 550 { | |
| 551 if (m_regionId == regionId) | |
| 552 return; | |
| 553 | |
| 554 cueWillChange(); | |
| 555 m_regionId = regionId; | |
| 556 cueDidChange(); | |
| 557 } | |
| 558 | |
| 559 void TextTrackCue::notifyRegionWhenRemovingDisplayTree(bool notifyRegion) | |
| 560 { | |
| 561 m_notifyRegion = notifyRegion; | |
| 562 } | |
| 563 | |
| 564 bool TextTrackCue::isActive() | 162 bool TextTrackCue::isActive() |
| 565 { | 163 { |
| 566 return m_isActive && track() && track()->mode() != TextTrack::disabledKeywor
d(); | 164 return m_isActive && track() && track()->mode() != TextTrack::disabledKeywor
d(); |
| 567 } | 165 } |
| 568 | 166 |
| 569 void TextTrackCue::setIsActive(bool active) | 167 void TextTrackCue::setIsActive(bool active) |
| 570 { | 168 { |
| 571 m_isActive = active; | 169 m_isActive = active; |
| 572 | 170 |
| 573 // Remove the display tree as soon as the cue becomes inactive. | 171 // Remove the display tree as soon as the cue becomes inactive. |
| 574 if (!active) | 172 if (!active) |
| 575 removeDisplayTree(); | 173 removeDisplayTree(); |
| 576 } | 174 } |
| 577 | 175 |
| 578 int TextTrackCue::calculateComputedLinePosition() | |
| 579 { | |
| 580 // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-ele
ment.html#text-track-cue-computed-line-position | |
| 581 | |
| 582 // If the text track cue line position is numeric, then that is the text | |
| 583 // track cue computed line position. | |
| 584 if (m_linePosition != undefinedPosition) | |
| 585 return m_linePosition; | |
| 586 | |
| 587 // If the text track cue snap-to-lines flag of the text track cue is not | |
| 588 // set, the text track cue computed line position is the value 100; | |
| 589 if (!m_snapToLines) | |
| 590 return 100; | |
| 591 | |
| 592 // Otherwise, it is the value returned by the following algorithm: | |
| 593 | |
| 594 // If cue is not associated with a text track, return -1 and abort these | |
| 595 // steps. | |
| 596 if (!track()) | |
| 597 return -1; | |
| 598 | |
| 599 // Let n be the number of text tracks whose text track mode is showing or | |
| 600 // showing by default and that are in the media element's list of text | |
| 601 // tracks before track. | |
| 602 int n = track()->trackIndexRelativeToRenderedTracks(); | |
| 603 | |
| 604 // Increment n by one. | |
| 605 n++; | |
| 606 | |
| 607 // Negate n. | |
| 608 n = -n; | |
| 609 | |
| 610 return n; | |
| 611 } | |
| 612 | |
| 613 static bool isCueParagraphSeparator(UChar character) | |
| 614 { | |
| 615 // Within a cue, paragraph boundaries are only denoted by Type B characters, | |
| 616 // such as U+000A LINE FEED (LF), U+0085 NEXT LINE (NEL), and U+2029 PARAGRA
PH SEPARATOR. | |
| 617 return WTF::Unicode::category(character) & WTF::Unicode::Separator_Paragraph
; | |
| 618 } | |
| 619 | |
| 620 void TextTrackCue::determineTextDirection() | |
| 621 { | |
| 622 DEFINE_STATIC_LOCAL(const String, rtTag, ("rt")); | |
| 623 createVTTNodeTree(); | |
| 624 | |
| 625 // Apply the Unicode Bidirectional Algorithm's Paragraph Level steps to the | |
| 626 // concatenation of the values of each WebVTT Text Object in nodes, in a | |
| 627 // pre-order, depth-first traversal, excluding WebVTT Ruby Text Objects and | |
| 628 // their descendants. | |
| 629 StringBuilder paragraphBuilder; | |
| 630 for (Node* node = m_webVTTNodeTree->firstChild(); node; node = NodeTraversal
::next(*node, m_webVTTNodeTree.get())) { | |
| 631 if (!node->isTextNode() || node->localName() == rtTag) | |
| 632 continue; | |
| 633 | |
| 634 paragraphBuilder.append(node->nodeValue()); | |
| 635 } | |
| 636 | |
| 637 String paragraph = paragraphBuilder.toString(); | |
| 638 if (!paragraph.length()) | |
| 639 return; | |
| 640 | |
| 641 for (size_t i = 0; i < paragraph.length(); ++i) { | |
| 642 UChar current = paragraph[i]; | |
| 643 if (!current || isCueParagraphSeparator(current)) | |
| 644 return; | |
| 645 | |
| 646 if (UChar current = paragraph[i]) { | |
| 647 WTF::Unicode::Direction charDirection = WTF::Unicode::direction(curr
ent); | |
| 648 if (charDirection == WTF::Unicode::LeftToRight) { | |
| 649 m_displayDirection = CSSValueLtr; | |
| 650 return; | |
| 651 } | |
| 652 if (charDirection == WTF::Unicode::RightToLeft | |
| 653 || charDirection == WTF::Unicode::RightToLeftArabic) { | |
| 654 m_displayDirection = CSSValueRtl; | |
| 655 return; | |
| 656 } | |
| 657 } | |
| 658 } | |
| 659 } | |
| 660 | |
| 661 void TextTrackCue::calculateDisplayParameters() | |
| 662 { | |
| 663 // Steps 10.2, 10.3 | |
| 664 determineTextDirection(); | |
| 665 | |
| 666 // 10.4 If the text track cue writing direction is horizontal, then let | |
| 667 // block-flow be 'tb'. Otherwise, if the text track cue writing direction is | |
| 668 // vertical growing left, then let block-flow be 'lr'. Otherwise, the text | |
| 669 // track cue writing direction is vertical growing right; let block-flow be | |
| 670 // 'rl'. | |
| 671 | |
| 672 // The above step is done through the writing direction static map. | |
| 673 | |
| 674 // 10.5 Determine the value of maximum size for cue as per the appropriate | |
| 675 // rules from the following list: | |
| 676 int maximumSize = m_textPosition; | |
| 677 if ((m_writingDirection == Horizontal && m_cueAlignment == Start && m_displa
yDirection == CSSValueLtr) | |
| 678 || (m_writingDirection == Horizontal && m_cueAlignment == End && m_d
isplayDirection == CSSValueRtl) | |
| 679 || (m_writingDirection == Horizontal && m_cueAlignment == Left) | |
| 680 || (m_writingDirection == VerticalGrowingLeft && (m_cueAlignment ==
Start || m_cueAlignment == Left)) | |
| 681 || (m_writingDirection == VerticalGrowingRight && (m_cueAlignment ==
Start || m_cueAlignment == Left))) { | |
| 682 maximumSize = 100 - m_textPosition; | |
| 683 } else if ((m_writingDirection == Horizontal && m_cueAlignment == End && m_d
isplayDirection == CSSValueLtr) | |
| 684 || (m_writingDirection == Horizontal && m_cueAlignment == Start && m
_displayDirection == CSSValueRtl) | |
| 685 || (m_writingDirection == Horizontal && m_cueAlignment == Right) | |
| 686 || (m_writingDirection == VerticalGrowingLeft && (m_cueAlignment ==
End || m_cueAlignment == Right)) | |
| 687 || (m_writingDirection == VerticalGrowingRight && (m_cueAlignment ==
End || m_cueAlignment == Right))) { | |
| 688 maximumSize = m_textPosition; | |
| 689 } else if (m_cueAlignment == Middle) { | |
| 690 maximumSize = m_textPosition <= 50 ? m_textPosition : (100 - m_textPosit
ion); | |
| 691 maximumSize = maximumSize * 2; | |
| 692 } else { | |
| 693 ASSERT_NOT_REACHED(); | |
| 694 } | |
| 695 | |
| 696 // 10.6 If the text track cue size is less than maximum size, then let size | |
| 697 // be text track cue size. Otherwise, let size be maximum size. | |
| 698 m_displaySize = std::min(m_cueSize, maximumSize); | |
| 699 | |
| 700 // FIXME: Understand why step 10.7 is missing (just a copy/paste error?) | |
| 701 // Could be done within a spec implementation check - http://crbug.com/30158
0 | |
| 702 | |
| 703 // 10.8 Determine the value of x-position or y-position for cue as per the | |
| 704 // appropriate rules from the following list: | |
| 705 if (m_writingDirection == Horizontal) { | |
| 706 switch (m_cueAlignment) { | |
| 707 case Start: | |
| 708 if (m_displayDirection == CSSValueLtr) | |
| 709 m_displayPosition.first = m_textPosition; | |
| 710 else | |
| 711 m_displayPosition.first = 100 - m_textPosition - m_displaySize; | |
| 712 break; | |
| 713 case End: | |
| 714 if (m_displayDirection == CSSValueRtl) | |
| 715 m_displayPosition.first = 100 - m_textPosition; | |
| 716 else | |
| 717 m_displayPosition.first = m_textPosition - m_displaySize; | |
| 718 break; | |
| 719 case Left: | |
| 720 if (m_displayDirection == CSSValueLtr) | |
| 721 m_displayPosition.first = m_textPosition; | |
| 722 else | |
| 723 m_displayPosition.first = 100 - m_textPosition; | |
| 724 break; | |
| 725 case Right: | |
| 726 if (m_displayDirection == CSSValueLtr) | |
| 727 m_displayPosition.first = m_textPosition - m_displaySize; | |
| 728 else | |
| 729 m_displayPosition.first = 100 - m_textPosition - m_displaySize; | |
| 730 break; | |
| 731 case Middle: | |
| 732 if (m_displayDirection == CSSValueLtr) | |
| 733 m_displayPosition.first = m_textPosition - m_displaySize / 2; | |
| 734 else | |
| 735 m_displayPosition.first = 100 - m_textPosition - m_displaySize /
2; | |
| 736 break; | |
| 737 case NumberOfAlignments: | |
| 738 ASSERT_NOT_REACHED(); | |
| 739 } | |
| 740 } else { | |
| 741 // Cases for m_writingDirection being VerticalGrowing{Left|Right} | |
| 742 switch (m_cueAlignment) { | |
| 743 case Start: | |
| 744 case Left: | |
| 745 m_displayPosition.second = m_textPosition; | |
| 746 break; | |
| 747 case End: | |
| 748 case Right: | |
| 749 m_displayPosition.second = m_textPosition - m_displaySize; | |
| 750 break; | |
| 751 case Middle: | |
| 752 m_displayPosition.second = m_textPosition - m_displaySize / 2; | |
| 753 break; | |
| 754 case NumberOfAlignments: | |
| 755 ASSERT_NOT_REACHED(); | |
| 756 } | |
| 757 } | |
| 758 | |
| 759 // A text track cue has a text track cue computed line position whose value | |
| 760 // is defined in terms of the other aspects of the cue. | |
| 761 m_computedLinePosition = calculateComputedLinePosition(); | |
| 762 | |
| 763 // 10.9 Determine the value of whichever of x-position or y-position is not | |
| 764 // yet calculated for cue as per the appropriate rules from the following | |
| 765 // list: | |
| 766 if (m_snapToLines && m_displayPosition.second == undefinedPosition && m_writ
ingDirection == Horizontal) | |
| 767 m_displayPosition.second = 0; | |
| 768 | |
| 769 if (!m_snapToLines && m_displayPosition.second == undefinedPosition && m_wri
tingDirection == Horizontal) | |
| 770 m_displayPosition.second = m_computedLinePosition; | |
| 771 | |
| 772 if (m_snapToLines && m_displayPosition.first == undefinedPosition | |
| 773 && (m_writingDirection == VerticalGrowingLeft || m_writingDirection
== VerticalGrowingRight)) | |
| 774 m_displayPosition.first = 0; | |
| 775 | |
| 776 if (!m_snapToLines && (m_writingDirection == VerticalGrowingLeft || m_writin
gDirection == VerticalGrowingRight)) | |
| 777 m_displayPosition.first = m_computedLinePosition; | |
| 778 } | |
| 779 | |
| 780 void TextTrackCue::markFutureAndPastNodes(ContainerNode* root, double previousTi
mestamp, double movieTime) | |
| 781 { | |
| 782 DEFINE_STATIC_LOCAL(const String, timestampTag, ("timestamp")); | |
| 783 | |
| 784 bool isPastNode = true; | |
| 785 double currentTimestamp = previousTimestamp; | |
| 786 if (currentTimestamp > movieTime) | |
| 787 isPastNode = false; | |
| 788 | |
| 789 for (Node* child = root->firstChild(); child; child = NodeTraversal::next(*c
hild, root)) { | |
| 790 if (child->nodeName() == timestampTag) { | |
| 791 unsigned position = 0; | |
| 792 String timestamp = child->nodeValue(); | |
| 793 double currentTimestamp = VTTParser::collectTimeStamp(timestamp, &po
sition); | |
| 794 ASSERT(currentTimestamp != -1); | |
| 795 | |
| 796 if (currentTimestamp > movieTime) | |
| 797 isPastNode = false; | |
| 798 } | |
| 799 | |
| 800 if (child->isVTTElement()) { | |
| 801 toVTTElement(child)->setIsPastNode(isPastNode); | |
| 802 // Make an elemenet id match a cue id for style matching purposes. | |
| 803 if (!m_id.isEmpty()) | |
| 804 toElement(child)->setIdAttribute(m_id); | |
| 805 } | |
| 806 } | |
| 807 } | |
| 808 | |
| 809 void TextTrackCue::updateDisplayTree(double movieTime) | |
| 810 { | |
| 811 // The display tree may contain WebVTT timestamp objects representing | |
| 812 // timestamps (processing instructions), along with displayable nodes. | |
| 813 | |
| 814 if (!track()->isRendered()) | |
| 815 return; | |
| 816 | |
| 817 // Clear the contents of the set. | |
| 818 m_cueBackgroundBox->removeChildren(); | |
| 819 | |
| 820 // Update the two sets containing past and future WebVTT objects. | |
| 821 RefPtr<DocumentFragment> referenceTree = createCueRenderingTree(); | |
| 822 markFutureAndPastNodes(referenceTree.get(), startTime(), movieTime); | |
| 823 m_cueBackgroundBox->appendChild(referenceTree, ASSERT_NO_EXCEPTION); | |
| 824 } | |
| 825 | |
| 826 PassRefPtr<TextTrackCueBox> TextTrackCue::getDisplayTree(const IntSize& videoSiz
e) | |
| 827 { | |
| 828 RefPtr<TextTrackCueBox> displayTree = displayTreeInternal(); | |
| 829 if (!m_displayTreeShouldChange || !track()->isRendered()) | |
| 830 return displayTree; | |
| 831 | |
| 832 // 10.1 - 10.10 | |
| 833 calculateDisplayParameters(); | |
| 834 | |
| 835 // 10.11. Apply the terms of the CSS specifications to nodes within the | |
| 836 // following constraints, thus obtaining a set of CSS boxes positioned | |
| 837 // relative to an initial containing block: | |
| 838 displayTree->removeChildren(); | |
| 839 | |
| 840 // The document tree is the tree of WebVTT Node Objects rooted at nodes. | |
| 841 | |
| 842 // The children of the nodes must be wrapped in an anonymous box whose | |
| 843 // 'display' property has the value 'inline'. This is the WebVTT cue | |
| 844 // background box. | |
| 845 | |
| 846 // Note: This is contained by default in m_cueBackgroundBox. | |
| 847 m_cueBackgroundBox->setPart(cueShadowPseudoId()); | |
| 848 displayTree->appendChild(m_cueBackgroundBox); | |
| 849 | |
| 850 // FIXME(BUG 79916): Runs of children of WebVTT Ruby Objects that are not | |
| 851 // WebVTT Ruby Text Objects must be wrapped in anonymous boxes whose | |
| 852 // 'display' property has the value 'ruby-base'. | |
| 853 | |
| 854 // FIXME(BUG 79916): Text runs must be wrapped according to the CSS | |
| 855 // line-wrapping rules, except that additionally, regardless of the value of | |
| 856 // the 'white-space' property, lines must be wrapped at the edge of their | |
| 857 // containing blocks, even if doing so requires splitting a word where there | |
| 858 // is no line breaking opportunity. (Thus, normally text wraps as needed, | |
| 859 // but if there is a particularly long word, it does not overflow as it | |
| 860 // normally would in CSS, it is instead forcibly wrapped at the box's edge.) | |
| 861 displayTree->applyCSSProperties(videoSize); | |
| 862 | |
| 863 m_displayTreeShouldChange = false; | |
| 864 | |
| 865 // 10.15. Let cue's text track cue display state have the CSS boxes in | |
| 866 // boxes. | |
| 867 return displayTree; | |
| 868 } | |
| 869 | |
| 870 void TextTrackCue::removeDisplayTree() | |
| 871 { | |
| 872 if (m_notifyRegion && m_track->regions()) { | |
| 873 // The region needs to be informed about the cue removal. | |
| 874 VTTRegion* region = m_track->regions()->getRegionById(m_regionId); | |
| 875 if (region) | |
| 876 region->willRemoveTextTrackCueBox(m_displayTree.get()); | |
| 877 } | |
| 878 | |
| 879 displayTreeInternal()->remove(ASSERT_NO_EXCEPTION); | |
| 880 } | |
| 881 | |
| 882 std::pair<double, double> TextTrackCue::getPositionCoordinates() const | |
| 883 { | |
| 884 // This method is used for setting x and y when snap to lines is not set. | |
| 885 std::pair<double, double> coordinates; | |
| 886 | |
| 887 if (m_writingDirection == Horizontal && m_displayDirection == CSSValueLtr) { | |
| 888 coordinates.first = m_textPosition; | |
| 889 coordinates.second = m_computedLinePosition; | |
| 890 | |
| 891 return coordinates; | |
| 892 } | |
| 893 | |
| 894 if (m_writingDirection == Horizontal && m_displayDirection == CSSValueRtl) { | |
| 895 coordinates.first = 100 - m_textPosition; | |
| 896 coordinates.second = m_computedLinePosition; | |
| 897 | |
| 898 return coordinates; | |
| 899 } | |
| 900 | |
| 901 if (m_writingDirection == VerticalGrowingLeft) { | |
| 902 coordinates.first = 100 - m_computedLinePosition; | |
| 903 coordinates.second = m_textPosition; | |
| 904 | |
| 905 return coordinates; | |
| 906 } | |
| 907 | |
| 908 if (m_writingDirection == VerticalGrowingRight) { | |
| 909 coordinates.first = m_computedLinePosition; | |
| 910 coordinates.second = m_textPosition; | |
| 911 | |
| 912 return coordinates; | |
| 913 } | |
| 914 | |
| 915 ASSERT_NOT_REACHED(); | |
| 916 | |
| 917 return coordinates; | |
| 918 } | |
| 919 | |
| 920 TextTrackCue::CueSetting TextTrackCue::settingName(const String& name) | |
| 921 { | |
| 922 DEFINE_STATIC_LOCAL(const String, verticalKeyword, ("vertical")); | |
| 923 DEFINE_STATIC_LOCAL(const String, lineKeyword, ("line")); | |
| 924 DEFINE_STATIC_LOCAL(const String, positionKeyword, ("position")); | |
| 925 DEFINE_STATIC_LOCAL(const String, sizeKeyword, ("size")); | |
| 926 DEFINE_STATIC_LOCAL(const String, alignKeyword, ("align")); | |
| 927 DEFINE_STATIC_LOCAL(const String, regionIdKeyword, ("region")); | |
| 928 | |
| 929 if (name == verticalKeyword) | |
| 930 return Vertical; | |
| 931 else if (name == lineKeyword) | |
| 932 return Line; | |
| 933 else if (name == positionKeyword) | |
| 934 return Position; | |
| 935 else if (name == sizeKeyword) | |
| 936 return Size; | |
| 937 else if (name == alignKeyword) | |
| 938 return Align; | |
| 939 else if (RuntimeEnabledFeatures::webVTTRegionsEnabled() && name == regionIdK
eyword) | |
| 940 return RegionId; | |
| 941 | |
| 942 return None; | |
| 943 } | |
| 944 | |
| 945 void TextTrackCue::parseSettings(const String& input) | |
| 946 { | |
| 947 unsigned position = 0; | |
| 948 | |
| 949 while (position < input.length()) { | |
| 950 | |
| 951 // The WebVTT cue settings part of a WebVTT cue consists of zero or more
of the following components, in any order, | |
| 952 // separated from each other by one or more U+0020 SPACE characters or U
+0009 CHARACTER TABULATION (tab) characters. | |
| 953 while (position < input.length() && VTTParser::isValidSettingDelimiter(i
nput[position])) | |
| 954 position++; | |
| 955 if (position >= input.length()) | |
| 956 break; | |
| 957 | |
| 958 // When the user agent is to parse the WebVTT settings given by a string
input for a text track cue cue, | |
| 959 // the user agent must run the following steps: | |
| 960 // 1. Let settings be the result of splitting input on spaces. | |
| 961 // 2. For each token setting in the list settings, run the following sub
steps: | |
| 962 // 1. If setting does not contain a U+003A COLON character (:), or if
the first U+003A COLON character (:) | |
| 963 // in setting is either the first or last character of setting, th
en jump to the step labeled next setting. | |
| 964 unsigned endOfSetting = position; | |
| 965 String setting = VTTParser::collectWord(input, &endOfSetting); | |
| 966 CueSetting name; | |
| 967 size_t colonOffset = setting.find(':', 1); | |
| 968 if (colonOffset == kNotFound || !colonOffset || colonOffset == setting.l
ength() - 1) | |
| 969 goto NextSetting; | |
| 970 | |
| 971 // 2. Let name be the leading substring of setting up to and excluding t
he first U+003A COLON character (:) in that string. | |
| 972 name = settingName(setting.substring(0, colonOffset)); | |
| 973 | |
| 974 // 3. Let value be the trailing substring of setting starting from the c
haracter immediately after the first U+003A COLON character (:) in that string. | |
| 975 position += colonOffset + 1; | |
| 976 if (position >= input.length()) | |
| 977 break; | |
| 978 | |
| 979 // 4. Run the appropriate substeps that apply for the value of name, as
follows: | |
| 980 switch (name) { | |
| 981 case Vertical: | |
| 982 { | |
| 983 // If name is a case-sensitive match for "vertical" | |
| 984 // 1. If value is a case-sensitive match for the string "rl", then l
et cue's text track cue writing direction | |
| 985 // be vertical growing left. | |
| 986 String writingDirection = VTTParser::collectWord(input, &position); | |
| 987 if (writingDirection == verticalGrowingLeftKeyword()) | |
| 988 m_writingDirection = VerticalGrowingLeft; | |
| 989 | |
| 990 // 2. Otherwise, if value is a case-sensitive match for the string "
lr", then let cue's text track cue writing | |
| 991 // direction be vertical growing right. | |
| 992 else if (writingDirection == verticalGrowingRightKeyword()) | |
| 993 m_writingDirection = VerticalGrowingRight; | |
| 994 } | |
| 995 break; | |
| 996 case Line: | |
| 997 { | |
| 998 // 1-2 - Collect chars that are either '-', '%', or a digit. | |
| 999 // 1. If value contains any characters other than U+002D HYPHEN-MINU
S characters (-), U+0025 PERCENT SIGN | |
| 1000 // characters (%), and characters in the range U+0030 DIGIT ZERO
(0) to U+0039 DIGIT NINE (9), then jump | |
| 1001 // to the step labeled next setting. | |
| 1002 StringBuilder linePositionBuilder; | |
| 1003 while (position < input.length() && (input[position] == '-' || input
[position] == '%' || isASCIIDigit(input[position]))) | |
| 1004 linePositionBuilder.append(input[position++]); | |
| 1005 if (position < input.length() && !VTTParser::isValidSettingDelimiter
(input[position])) | |
| 1006 break; | |
| 1007 | |
| 1008 // 2. If value does not contain at least one character in the range
U+0030 DIGIT ZERO (0) to U+0039 DIGIT | |
| 1009 // NINE (9), then jump to the step labeled next setting. | |
| 1010 // 3. If any character in value other than the first character is a
U+002D HYPHEN-MINUS character (-), then | |
| 1011 // jump to the step labeled next setting. | |
| 1012 // 4. If any character in value other than the last character is a U
+0025 PERCENT SIGN character (%), then | |
| 1013 // jump to the step labeled next setting. | |
| 1014 String linePosition = linePositionBuilder.toString(); | |
| 1015 if (linePosition.find('-', 1) != kNotFound || linePosition.reverseFi
nd("%", linePosition.length() - 2) != kNotFound) | |
| 1016 break; | |
| 1017 | |
| 1018 // 5. If the first character in value is a U+002D HYPHEN-MINUS chara
cter (-) and the last character in value is a | |
| 1019 // U+0025 PERCENT SIGN character (%), then jump to the step label
ed next setting. | |
| 1020 if (linePosition[0] == '-' && linePosition[linePosition.length() - 1
] == '%') | |
| 1021 break; | |
| 1022 | |
| 1023 // 6. Ignoring the trailing percent sign, if any, interpret value as
a (potentially signed) integer, and | |
| 1024 // let number be that number. | |
| 1025 // NOTE: toInt ignores trailing non-digit characters, such as '%'. | |
| 1026 bool validNumber; | |
| 1027 int number = linePosition.toInt(&validNumber); | |
| 1028 if (!validNumber) | |
| 1029 break; | |
| 1030 | |
| 1031 // 7. If the last character in value is a U+0025 PERCENT SIGN charac
ter (%), but number is not in the range | |
| 1032 // 0 ≤ number ≤ 100, then jump to the step labeled next setting. | |
| 1033 // 8. Let cue's text track cue line position be number. | |
| 1034 // 9. If the last character in value is a U+0025 PERCENT SIGN charac
ter (%), then let cue's text track cue | |
| 1035 // snap-to-lines flag be false. Otherwise, let it be true. | |
| 1036 if (linePosition[linePosition.length() - 1] == '%') { | |
| 1037 if (number < 0 || number > 100) | |
| 1038 break; | |
| 1039 | |
| 1040 // 10 - If '%' then set snap-to-lines flag to false. | |
| 1041 m_snapToLines = false; | |
| 1042 } | |
| 1043 | |
| 1044 m_linePosition = number; | |
| 1045 } | |
| 1046 break; | |
| 1047 case Position: | |
| 1048 { | |
| 1049 // 1. If value contains any characters other than U+0025 PERCENT SIG
N characters (%) and characters in the range | |
| 1050 // U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9), then jump to t
he step labeled next setting. | |
| 1051 // 2. If value does not contain at least one character in the range
U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9), | |
| 1052 // then jump to the step labeled next setting. | |
| 1053 String textPosition = VTTParser::collectDigits(input, &position); | |
| 1054 if (textPosition.isEmpty()) | |
| 1055 break; | |
| 1056 if (position >= input.length()) | |
| 1057 break; | |
| 1058 | |
| 1059 // 3. If any character in value other than the last character is a U
+0025 PERCENT SIGN character (%), then jump | |
| 1060 // to the step labeled next setting. | |
| 1061 // 4. If the last character in value is not a U+0025 PERCENT SIGN ch
aracter (%), then jump to the step labeled | |
| 1062 // next setting. | |
| 1063 if (input[position++] != '%') | |
| 1064 break; | |
| 1065 if (position < input.length() && !VTTParser::isValidSettingDelimiter
(input[position])) | |
| 1066 break; | |
| 1067 | |
| 1068 // 5. Ignoring the trailing percent sign, interpret value as an inte
ger, and let number be that number. | |
| 1069 // 6. If number is not in the range 0 ≤ number ≤ 100, then jump to t
he step labeled next setting. | |
| 1070 // NOTE: toInt ignores trailing non-digit characters, such as '%'. | |
| 1071 bool validNumber; | |
| 1072 int number = textPosition.toInt(&validNumber); | |
| 1073 if (!validNumber) | |
| 1074 break; | |
| 1075 if (number < 0 || number > 100) | |
| 1076 break; | |
| 1077 | |
| 1078 // 7. Let cue's text track cue text position be number. | |
| 1079 m_textPosition = number; | |
| 1080 } | |
| 1081 break; | |
| 1082 case Size: | |
| 1083 { | |
| 1084 // 1. If value contains any characters other than U+0025 PERCENT SIG
N characters (%) and characters in the | |
| 1085 // range U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9), then jum
p to the step labeled next setting. | |
| 1086 // 2. If value does not contain at least one character in the range
U+0030 DIGIT ZERO (0) to U+0039 DIGIT | |
| 1087 // NINE (9), then jump to the step labeled next setting. | |
| 1088 String cueSize = VTTParser::collectDigits(input, &position); | |
| 1089 if (cueSize.isEmpty()) | |
| 1090 break; | |
| 1091 if (position >= input.length()) | |
| 1092 break; | |
| 1093 | |
| 1094 // 3. If any character in value other than the last character is a U
+0025 PERCENT SIGN character (%), | |
| 1095 // then jump to the step labeled next setting. | |
| 1096 // 4. If the last character in value is not a U+0025 PERCENT SIGN ch
aracter (%), then jump to the step | |
| 1097 // labeled next setting. | |
| 1098 if (input[position++] != '%') | |
| 1099 break; | |
| 1100 if (position < input.length() && !VTTParser::isValidSettingDelimiter
(input[position])) | |
| 1101 break; | |
| 1102 | |
| 1103 // 5. Ignoring the trailing percent sign, interpret value as an inte
ger, and let number be that number. | |
| 1104 // 6. If number is not in the range 0 ≤ number ≤ 100, then jump to t
he step labeled next setting. | |
| 1105 bool validNumber; | |
| 1106 int number = cueSize.toInt(&validNumber); | |
| 1107 if (!validNumber) | |
| 1108 break; | |
| 1109 if (number < 0 || number > 100) | |
| 1110 break; | |
| 1111 | |
| 1112 // 7. Let cue's text track cue size be number. | |
| 1113 m_cueSize = number; | |
| 1114 } | |
| 1115 break; | |
| 1116 case Align: | |
| 1117 { | |
| 1118 String cueAlignment = VTTParser::collectWord(input, &position); | |
| 1119 | |
| 1120 // 1. If value is a case-sensitive match for the string "start", the
n let cue's text track cue alignment be start alignment. | |
| 1121 if (cueAlignment == startKeyword()) | |
| 1122 m_cueAlignment = Start; | |
| 1123 | |
| 1124 // 2. If value is a case-sensitive match for the string "middle", th
en let cue's text track cue alignment be middle alignment. | |
| 1125 else if (cueAlignment == middleKeyword()) | |
| 1126 m_cueAlignment = Middle; | |
| 1127 | |
| 1128 // 3. If value is a case-sensitive match for the string "end", then
let cue's text track cue alignment be end alignment. | |
| 1129 else if (cueAlignment == endKeyword()) | |
| 1130 m_cueAlignment = End; | |
| 1131 | |
| 1132 // 4. If value is a case-sensitive match for the string "left", then
let cue's text track cue alignment be left alignment. | |
| 1133 else if (cueAlignment == leftKeyword()) | |
| 1134 m_cueAlignment = Left; | |
| 1135 | |
| 1136 // 5. If value is a case-sensitive match for the string "right", the
n let cue's text track cue alignment be right alignment. | |
| 1137 else if (cueAlignment == rightKeyword()) | |
| 1138 m_cueAlignment = Right; | |
| 1139 } | |
| 1140 break; | |
| 1141 case RegionId: | |
| 1142 m_regionId = VTTParser::collectWord(input, &position); | |
| 1143 break; | |
| 1144 case None: | |
| 1145 break; | |
| 1146 } | |
| 1147 | |
| 1148 NextSetting: | |
| 1149 position = endOfSetting; | |
| 1150 } | |
| 1151 | |
| 1152 // If cue's line position is not auto or cue's size is not 100 or cue's | |
| 1153 // writing direction is not horizontal, but cue's region identifier is not | |
| 1154 // the empty string, let cue's region identifier be the empty string. | |
| 1155 if (m_regionId.isEmpty()) | |
| 1156 return; | |
| 1157 | |
| 1158 if (m_linePosition != undefinedPosition || m_cueSize != 100 || m_writingDire
ction != Horizontal) | |
| 1159 m_regionId = emptyString(); | |
| 1160 } | |
| 1161 | |
| 1162 CSSValueID TextTrackCue::getCSSAlignment() const | |
| 1163 { | |
| 1164 return displayAlignmentMap[m_cueAlignment]; | |
| 1165 } | |
| 1166 | |
| 1167 CSSValueID TextTrackCue::getCSSWritingDirection() const | |
| 1168 { | |
| 1169 return m_displayDirection; | |
| 1170 } | |
| 1171 | |
| 1172 CSSValueID TextTrackCue::getCSSWritingMode() const | |
| 1173 { | |
| 1174 return displayWritingModeMap[m_writingDirection]; | |
| 1175 } | |
| 1176 | |
| 1177 int TextTrackCue::getCSSSize() const | |
| 1178 { | |
| 1179 return m_displaySize; | |
| 1180 } | |
| 1181 | |
| 1182 std::pair<double, double> TextTrackCue::getCSSPosition() const | |
| 1183 { | |
| 1184 if (!m_snapToLines) | |
| 1185 return getPositionCoordinates(); | |
| 1186 | |
| 1187 return m_displayPosition; | |
| 1188 } | |
| 1189 | |
| 1190 const AtomicString& TextTrackCue::interfaceName() const | 176 const AtomicString& TextTrackCue::interfaceName() const |
| 1191 { | 177 { |
| 1192 return EventTargetNames::TextTrackCue; | 178 return EventTargetNames::TextTrackCue; |
| 1193 } | 179 } |
| 1194 | 180 |
| 1195 ExecutionContext* TextTrackCue::executionContext() const | |
| 1196 { | |
| 1197 ASSERT(m_cueBackgroundBox); | |
| 1198 return m_cueBackgroundBox->executionContext(); | |
| 1199 } | |
| 1200 | |
| 1201 Document& TextTrackCue::document() const | |
| 1202 { | |
| 1203 ASSERT(m_cueBackgroundBox); | |
| 1204 return m_cueBackgroundBox->document(); | |
| 1205 } | |
| 1206 | |
| 1207 } // namespace WebCore | 181 } // namespace WebCore |
| OLD | NEW |