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" | 35 #include "RuntimeEnabledFeatures.h" |
38 #include "bindings/v8/ExceptionStatePlaceholder.h" | 36 #include "bindings/v8/ExceptionStatePlaceholder.h" |
39 #include "core/dom/DocumentFragment.h" | 37 #include "core/dom/DocumentFragment.h" |
40 #include "core/events/Event.h" | 38 #include "core/events/Event.h" |
41 #include "core/dom/NodeTraversal.h" | 39 #include "core/dom/NodeTraversal.h" |
42 #include "core/html/HTMLDivElement.h" | 40 #include "core/html/HTMLDivElement.h" |
43 #include "core/html/track/TextTrack.h" | 41 #include "core/html/track/TextTrack.h" |
44 #include "core/html/track/TextTrackCueList.h" | 42 #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" | 43 #include "core/rendering/RenderTextTrackCue.h" |
49 #include "wtf/MathExtras.h" | |
50 #include "wtf/text/StringBuilder.h" | |
51 | 44 |
52 namespace WebCore { | 45 namespace WebCore { |
53 | 46 |
54 static const int invalidCueIndex = -1; | 47 static const int invalidCueIndex = -1; |
55 static const int undefinedPosition = -1; | |
56 | 48 |
57 static const CSSValueID displayWritingModeMap[] = { | 49 // ---------------------------- |
58 CSSValueHorizontalTb, CSSValueVerticalRl, CSSValueVerticalLr | |
59 }; | |
60 COMPILE_ASSERT(WTF_ARRAY_LENGTH(displayWritingModeMap) == TextTrackCue::NumberOf
WritingDirections, | |
61 displayWritingModeMap_has_wrong_size); | |
62 | 50 |
63 static const CSSValueID displayAlignmentMap[] = { | 51 TextTrackCueBox::TextTrackCueBox(Document& document) |
64 CSSValueStart, CSSValueCenter, CSSValueEnd, CSSValueLeft, CSSValueRight | 52 : 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 { | 53 { |
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 } | 54 } |
115 | 55 |
116 // ---------------------------- | 56 // ---------------------------- |
117 | 57 |
118 TextTrackCueBox::TextTrackCueBox(Document& document, TextTrackCue* cue) | 58 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) | 59 : m_startTime(start) |
208 , m_endTime(end) | 60 , 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) | 61 , m_cueIndex(invalidCueIndex) |
215 , m_writingDirection(Horizontal) | |
216 , m_cueAlignment(Middle) | |
217 , m_webVTTNodeTree(0) | |
218 , m_track(0) | 62 , m_track(0) |
219 , m_isActive(false) | 63 , m_isActive(false) |
220 , m_pauseOnExit(false) | 64 , 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 { | 65 { |
227 } | 66 } |
228 | 67 |
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() | 68 void TextTrackCue::cueWillChange() |
242 { | 69 { |
243 if (m_track) | 70 if (m_track) |
244 m_track->cueWillChange(this); | 71 m_track->cueWillChange(this); |
245 } | 72 } |
246 | 73 |
247 void TextTrackCue::cueDidChange() | 74 void TextTrackCue::cueDidChange() |
248 { | 75 { |
249 if (m_track) | 76 if (m_track) |
250 m_track->cueDidChange(this); | 77 m_track->cueDidChange(this); |
251 | |
252 m_displayTreeShouldChange = true; | |
253 } | 78 } |
254 | 79 |
255 TextTrack* TextTrackCue::track() const | 80 TextTrack* TextTrackCue::track() const |
256 { | 81 { |
257 return m_track; | 82 return m_track; |
258 } | 83 } |
259 | 84 |
260 void TextTrackCue::setTrack(TextTrack* track) | 85 void TextTrackCue::setTrack(TextTrack* track) |
261 { | 86 { |
262 m_track = track; | 87 m_track = track; |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
309 void TextTrackCue::setPauseOnExit(bool value) | 134 void TextTrackCue::setPauseOnExit(bool value) |
310 { | 135 { |
311 if (m_pauseOnExit == value) | 136 if (m_pauseOnExit == value) |
312 return; | 137 return; |
313 | 138 |
314 cueWillChange(); | 139 cueWillChange(); |
315 m_pauseOnExit = value; | 140 m_pauseOnExit = value; |
316 cueDidChange(); | 141 cueDidChange(); |
317 } | 142 } |
318 | 143 |
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() | 144 int TextTrackCue::cueIndex() |
491 { | 145 { |
492 if (m_cueIndex == invalidCueIndex) | 146 if (m_cueIndex == invalidCueIndex) |
493 m_cueIndex = track()->cues()->getCueIndex(this); | 147 m_cueIndex = track()->cues()->getCueIndex(this); |
494 | 148 |
495 return m_cueIndex; | 149 return m_cueIndex; |
496 } | 150 } |
497 | 151 |
498 void TextTrackCue::invalidateCueIndex() | 152 void TextTrackCue::invalidateCueIndex() |
499 { | 153 { |
500 m_cueIndex = invalidCueIndex; | 154 m_cueIndex = invalidCueIndex; |
501 } | 155 } |
502 | 156 |
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) | 157 bool TextTrackCue::dispatchEvent(PassRefPtr<Event> event) |
541 { | 158 { |
542 // When a TextTrack's mode is disabled: no cues are active, no events fired. | 159 // When a TextTrack's mode is disabled: no cues are active, no events fired. |
543 if (!track() || track()->mode() == TextTrack::disabledKeyword()) | 160 if (!track() || track()->mode() == TextTrack::disabledKeyword()) |
544 return false; | 161 return false; |
545 | 162 |
546 return EventTarget::dispatchEvent(event); | 163 return EventTarget::dispatchEvent(event); |
547 } | 164 } |
548 | 165 |
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() | 166 bool TextTrackCue::isActive() |
565 { | 167 { |
566 return m_isActive && track() && track()->mode() != TextTrack::disabledKeywor
d(); | 168 return m_isActive && track() && track()->mode() != TextTrack::disabledKeywor
d(); |
567 } | 169 } |
568 | 170 |
569 void TextTrackCue::setIsActive(bool active) | 171 void TextTrackCue::setIsActive(bool active) |
570 { | 172 { |
571 m_isActive = active; | 173 m_isActive = active; |
572 | 174 |
573 // Remove the display tree as soon as the cue becomes inactive. | 175 // Remove the display tree as soon as the cue becomes inactive. |
574 if (!active) | 176 if (!active) |
575 removeDisplayTree(); | 177 removeDisplayTree(); |
576 } | 178 } |
577 | 179 |
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 | 180 const AtomicString& TextTrackCue::interfaceName() const |
1191 { | 181 { |
1192 return EventTargetNames::TextTrackCue; | 182 return EventTargetNames::TextTrackCue; |
1193 } | 183 } |
1194 | 184 |
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 | 185 } // namespace WebCore |
OLD | NEW |