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