Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(126)

Side by Side Diff: Source/core/html/track/vtt/VTTCue.cpp

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

Powered by Google App Engine
This is Rietveld 408576698