OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (C) 2008, 2009, 2010, 2011 Apple Inc. All rights reserved. | 2 * Copyright (C) 2008, 2009, 2010, 2011 Apple Inc. All rights reserved. |
3 * Copyright (C) 2012 Google Inc. All rights reserved. | 3 * Copyright (C) 2012 Google 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 | 6 * modification, are permitted provided that the following conditions |
7 * are met: | 7 * are met: |
8 * | 8 * |
9 * 1. Redistributions of source code must retain the above copyright | 9 * 1. 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 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
28 */ | 28 */ |
29 | 29 |
30 #include "core/html/shadow/MediaControlElements.h" | 30 #include "core/html/shadow/MediaControlElements.h" |
31 | 31 |
32 #include "bindings/core/v8/ExceptionStatePlaceholder.h" | 32 #include "bindings/core/v8/ExceptionStatePlaceholder.h" |
33 #include "core/InputTypeNames.h" | 33 #include "core/InputTypeNames.h" |
34 #include "core/dom/ClientRect.h" | 34 #include "core/dom/ClientRect.h" |
35 #include "core/dom/Text.h" | |
35 #include "core/dom/shadow/ShadowRoot.h" | 36 #include "core/dom/shadow/ShadowRoot.h" |
36 #include "core/events/MouseEvent.h" | 37 #include "core/events/MouseEvent.h" |
37 #include "core/frame/LocalFrame.h" | 38 #include "core/frame/LocalFrame.h" |
39 #include "core/html/HTMLLabelElement.h" | |
38 #include "core/html/HTMLMediaSource.h" | 40 #include "core/html/HTMLMediaSource.h" |
41 #include "core/html/HTMLSpanElement.h" | |
39 #include "core/html/HTMLVideoElement.h" | 42 #include "core/html/HTMLVideoElement.h" |
40 #include "core/html/TimeRanges.h" | 43 #include "core/html/TimeRanges.h" |
41 #include "core/html/shadow/MediaControls.h" | 44 #include "core/html/shadow/MediaControls.h" |
45 #include "core/html/track/TextTrackList.h" | |
42 #include "core/input/EventHandler.h" | 46 #include "core/input/EventHandler.h" |
43 #include "core/layout/LayoutTheme.h" | 47 #include "core/layout/LayoutTheme.h" |
44 #include "core/layout/LayoutVideo.h" | 48 #include "core/layout/LayoutVideo.h" |
45 #include "core/layout/api/LayoutSliderItem.h" | 49 #include "core/layout/api/LayoutSliderItem.h" |
50 #include "platform/EventDispatchForbiddenScope.h" | |
46 #include "platform/Histogram.h" | 51 #include "platform/Histogram.h" |
47 #include "platform/RuntimeEnabledFeatures.h" | 52 #include "platform/RuntimeEnabledFeatures.h" |
53 #include "platform/text/PlatformLocale.h" | |
54 #include "public/platform/Platform.h" | |
48 | 55 |
49 namespace blink { | 56 namespace blink { |
50 | 57 |
51 using namespace HTMLNames; | 58 using namespace HTMLNames; |
52 | 59 |
53 namespace { | 60 namespace { |
54 | 61 |
55 // This is the duration from mediaControls.css | 62 // This is the duration from mediaControls.css |
56 const double fadeOutDuration = 0.3; | 63 const double fadeOutDuration = 0.3; |
57 | 64 |
65 const QualifiedName& trackIndexAttrName() | |
66 { | |
67 // Save the track index in an attribute to avoid holding a pointer to the te xt track. | |
68 DEFINE_STATIC_LOCAL(QualifiedName, trackIndexAttr, (nullAtom, "data-track-in dex", nullAtom)); | |
69 return trackIndexAttr; | |
70 } | |
71 | |
72 // When specified as trackIndex, disable text tracks. | |
73 const int trackIndexOffValue = -1; | |
74 | |
58 bool isUserInteractionEvent(Event* event) | 75 bool isUserInteractionEvent(Event* event) |
59 { | 76 { |
60 const AtomicString& type = event->type(); | 77 const AtomicString& type = event->type(); |
61 return type == EventTypeNames::mousedown | 78 return type == EventTypeNames::mousedown |
62 || type == EventTypeNames::mouseup | 79 || type == EventTypeNames::mouseup |
63 || type == EventTypeNames::click | 80 || type == EventTypeNames::click |
64 || type == EventTypeNames::dblclick | 81 || type == EventTypeNames::dblclick |
65 || event->isKeyboardEvent() | 82 || event->isKeyboardEvent() |
66 || event->isTouchEvent(); | 83 || event->isTouchEvent(); |
67 } | 84 } |
(...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
351 RawPtr<MediaControlToggleClosedCaptionsButtonElement> button = new MediaCont rolToggleClosedCaptionsButtonElement(mediaControls); | 368 RawPtr<MediaControlToggleClosedCaptionsButtonElement> button = new MediaCont rolToggleClosedCaptionsButtonElement(mediaControls); |
352 button->ensureUserAgentShadowRoot(); | 369 button->ensureUserAgentShadowRoot(); |
353 button->setType(InputTypeNames::button); | 370 button->setType(InputTypeNames::button); |
354 button->setShadowPseudoId(AtomicString("-webkit-media-controls-toggle-closed -captions-button")); | 371 button->setShadowPseudoId(AtomicString("-webkit-media-controls-toggle-closed -captions-button")); |
355 button->setIsWanted(false); | 372 button->setIsWanted(false); |
356 return button.release(); | 373 return button.release(); |
357 } | 374 } |
358 | 375 |
359 void MediaControlToggleClosedCaptionsButtonElement::updateDisplayType() | 376 void MediaControlToggleClosedCaptionsButtonElement::updateDisplayType() |
360 { | 377 { |
361 bool captionsVisible = mediaElement().closedCaptionsVisible(); | 378 bool captionsVisible = mediaElement().textTracksVisible(); |
362 setDisplayType(captionsVisible ? MediaHideClosedCaptionsButton : MediaShowCl osedCaptionsButton); | 379 setDisplayType(captionsVisible ? MediaHideClosedCaptionsButton : MediaShowCl osedCaptionsButton); |
363 setChecked(captionsVisible); | |
364 } | 380 } |
365 | 381 |
366 void MediaControlToggleClosedCaptionsButtonElement::defaultEventHandler(Event* e vent) | 382 void MediaControlToggleClosedCaptionsButtonElement::defaultEventHandler(Event* e vent) |
367 { | 383 { |
368 if (event->type() == EventTypeNames::click) { | 384 if (event->type() == EventTypeNames::click) { |
369 mediaElement().setClosedCaptionsVisible(!mediaElement().closedCaptionsVi sible()); | 385 mediaControls().toggleTextTrackList(); |
370 setChecked(mediaElement().closedCaptionsVisible()); | |
371 updateDisplayType(); | 386 updateDisplayType(); |
372 event->setDefaultHandled(); | 387 event->setDefaultHandled(); |
373 } | 388 } |
374 | 389 |
375 HTMLInputElement::defaultEventHandler(event); | 390 HTMLInputElement::defaultEventHandler(event); |
376 } | 391 } |
377 | 392 |
378 // ---------------------------- | 393 // ---------------------------- |
379 | 394 |
395 MediaControlTextTrackListElement::MediaControlTextTrackListElement(MediaControls & mediaControls) | |
396 : MediaControlDivElement(mediaControls, MediaTextTrackList) | |
397 { | |
398 } | |
399 | |
400 RawPtr<MediaControlTextTrackListElement> MediaControlTextTrackListElement::creat e(MediaControls& mediaControls) | |
401 { | |
402 RawPtr<MediaControlTextTrackListElement> element = new MediaControlTextTrack ListElement(mediaControls); | |
403 element->setShadowPseudoId(AtomicString("-internal-media-controls-text-track -list")); | |
404 element->setIsWanted(false); | |
405 return element.release(); | |
406 } | |
407 | |
408 void MediaControlTextTrackListElement::defaultEventHandler(Event* event) | |
409 { | |
410 if (event->type() == EventTypeNames::change) { | |
411 // Identify which input element was selected and set track to showing | |
412 Node* target = event->target()->toNode(); | |
413 if (!target || !target->isElementNode()) | |
414 return; | |
415 | |
416 disableShowingTextTracks(); | |
417 int trackIndex = toElement(target)->getIntegralAttribute(trackIndexAttrN ame()); | |
418 if (trackIndex != trackIndexOffValue) { | |
419 ASSERT(trackIndex >= 0); | |
420 showTextTrackAtIndex(trackIndex); | |
421 mediaElement().disableAutomaticTextTrackSelection(); | |
422 } | |
423 | |
424 mediaControls().toggleTextTrackList(); | |
425 event->setDefaultHandled(); | |
426 } | |
427 MediaControlDivElement::defaultEventHandler(event); | |
428 } | |
429 | |
430 void MediaControlTextTrackListElement::setVisible(bool visible) | |
431 { | |
432 if (visible) { | |
433 setIsWanted(true); | |
434 refreshTextTrackListMenu(); | |
435 } else { | |
436 setIsWanted(false); | |
437 } | |
438 } | |
439 | |
440 void MediaControlTextTrackListElement::showTextTrackAtIndex(unsigned indexToEnab le) | |
441 { | |
442 TextTrackList* trackList = mediaElement().textTracks(); | |
443 if (indexToEnable >= trackList->length()) | |
444 return; | |
445 TextTrack* track = trackList->anonymousIndexedGetter(indexToEnable); | |
446 if (track && track->canBeRendered()) | |
447 track->setMode(TextTrack::showingKeyword()); | |
448 } | |
449 | |
450 void MediaControlTextTrackListElement::disableShowingTextTracks() | |
451 { | |
452 TextTrackList* trackList = mediaElement().textTracks(); | |
453 for (unsigned i = 0; i < trackList->length(); ++i) { | |
454 TextTrack* track = trackList->anonymousIndexedGetter(i); | |
455 if (track->mode() == TextTrack::showingKeyword()) | |
456 track->setMode(TextTrack::disabledKeyword()); | |
457 } | |
458 } | |
459 | |
460 String MediaControlTextTrackListElement::getTextTrackLabel(TextTrack* track) | |
461 { | |
462 if (!track) | |
463 return mediaElement().locale().queryString(WebLocalizedString::TextTrack sOff); | |
464 | |
465 String trackLabel = track->label(); | |
466 | |
467 if (trackLabel.isEmpty()) | |
468 trackLabel = String(mediaElement().locale().queryString(WebLocalizedStri ng::TextTracksNoLabel)); | |
469 | |
470 return trackLabel; | |
471 } | |
472 | |
473 bool MediaControlTextTrackListElement::shouldDisplayTrackKindMarker(TextTrack* c urrentTrack, String currentTrackLabel) | |
philipj_slow
2016/04/19 15:21:09
How about just a free helper function hasDuplicate
srivats
2016/04/19 23:19:02
Done.
| |
474 { | |
475 if (currentTrackLabel == String(mediaElement().locale().queryString(WebLocal izedString::TextTracksNoLabel))) | |
476 return true; | |
477 TextTrackList* trackList = mediaElement().textTracks(); | |
478 for (unsigned i = 0; i < trackList->length(); i++) { | |
philipj_slow
2016/04/19 15:21:09
This will be O(n^2) in the number of tracks which
srivats
2016/04/19 23:19:02
Done.
| |
479 TextTrack* track = trackList->anonymousIndexedGetter(i); | |
480 if (currentTrack == track) | |
481 continue; | |
482 if (currentTrackLabel == track->label()) | |
483 return true; | |
484 } | |
485 return false; | |
486 } | |
487 | |
488 // TextTrack parameter when passed in as a nullptr, creates the "Off" list item in the track list. | |
489 RawPtr<Element> MediaControlTextTrackListElement::createTextTrackListItem(TextTr ack* track) | |
490 { | |
491 int trackIndex = track ? track->trackIndex() : trackIndexOffValue; | |
492 RawPtr<HTMLLabelElement> trackItem = HTMLLabelElement::create(document(), nu llptr); | |
493 trackItem->setShadowPseudoId(AtomicString("-internal-media-controls-text-tra ck-list-item")); | |
494 RawPtr<HTMLInputElement> trackItemInput = HTMLInputElement::create(document( ), nullptr, false); | |
495 trackItemInput->setShadowPseudoId(AtomicString("-internal-media-controls-tex t-track-list-item-input")); | |
496 trackItemInput->setType(InputTypeNames::checkbox); | |
497 trackItemInput->setIntegralAttribute(trackIndexAttrName(), trackIndex); | |
498 if (!mediaElement().textTracksVisible()) { | |
499 if (!track) | |
500 trackItemInput->setChecked(true); | |
501 } else { | |
502 // If there are multiple text tracks set to showing, they must all have | |
503 // checkmarks displayed. | |
504 if (track && track->mode() == TextTrack::showingKeyword()) | |
505 trackItemInput->setChecked(true); | |
506 } | |
507 | |
508 trackItem->appendChild(trackItemInput); | |
509 String trackLabel = getTextTrackLabel(track); | |
510 trackItem->appendChild(Text::create(document(), trackLabel)); | |
511 // Add a track kind marker icon if there are multiple tracks with the same l abel. | |
512 if (track && shouldDisplayTrackKindMarker(track, trackLabel)) { | |
513 RawPtr<HTMLSpanElement> trackKindMarker = HTMLSpanElement::create(docume nt()); | |
514 if (track->kind() == track->captionsKeyword()) { | |
515 trackKindMarker->setShadowPseudoId(AtomicString("-internal-media-con trols-text-track-list-kind-captions")); | |
516 } else { | |
517 ASSERT(track->kind() == track->subtitlesKeyword()); | |
518 trackKindMarker->setShadowPseudoId(AtomicString("-internal-media-con trols-text-track-list-kind-subtitles")); | |
519 } | |
520 trackItem->appendChild(trackKindMarker); | |
521 } | |
522 return trackItem; | |
523 } | |
524 | |
525 void MediaControlTextTrackListElement::refreshTextTrackListMenu() | |
526 { | |
527 if (!mediaElement().hasClosedCaptions() || !mediaElement().textTracksAreRead y()) | |
528 return; | |
529 | |
530 EventDispatchForbiddenScope::AllowUserAgentEvents allowEvents; | |
531 removeChildren(OmitSubtreeModifiedEvent); | |
532 | |
533 // Construct a menu for subtitles and captions | |
534 // Pass in a nullptr to createTextTrackListItem to create the "Off" track it em. | |
535 appendChild(createTextTrackListItem(nullptr)); | |
536 | |
537 TextTrackList* trackList = mediaElement().textTracks(); | |
538 for (unsigned i = 0; i < trackList->length(); i++) { | |
539 TextTrack* track = trackList->anonymousIndexedGetter(i); | |
540 if (!track->canBeRendered()) | |
541 continue; | |
542 appendChild(createTextTrackListItem(track)); | |
543 } | |
544 } | |
545 | |
546 // ---------------------------- | |
547 | |
380 MediaControlTimelineElement::MediaControlTimelineElement(MediaControls& mediaCon trols) | 548 MediaControlTimelineElement::MediaControlTimelineElement(MediaControls& mediaCon trols) |
381 : MediaControlInputElement(mediaControls, MediaSlider) | 549 : MediaControlInputElement(mediaControls, MediaSlider) |
382 { | 550 { |
383 } | 551 } |
384 | 552 |
385 RawPtr<MediaControlTimelineElement> MediaControlTimelineElement::create(MediaCon trols& mediaControls) | 553 RawPtr<MediaControlTimelineElement> MediaControlTimelineElement::create(MediaCon trols& mediaControls) |
386 { | 554 { |
387 RawPtr<MediaControlTimelineElement> timeline = new MediaControlTimelineEleme nt(mediaControls); | 555 RawPtr<MediaControlTimelineElement> timeline = new MediaControlTimelineEleme nt(mediaControls); |
388 timeline->ensureUserAgentShadowRoot(); | 556 timeline->ensureUserAgentShadowRoot(); |
389 timeline->setType(InputTypeNames::range); | 557 timeline->setType(InputTypeNames::range); |
(...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
656 } | 824 } |
657 | 825 |
658 RawPtr<MediaControlCurrentTimeDisplayElement> MediaControlCurrentTimeDisplayElem ent::create(MediaControls& mediaControls) | 826 RawPtr<MediaControlCurrentTimeDisplayElement> MediaControlCurrentTimeDisplayElem ent::create(MediaControls& mediaControls) |
659 { | 827 { |
660 RawPtr<MediaControlCurrentTimeDisplayElement> element = new MediaControlCurr entTimeDisplayElement(mediaControls); | 828 RawPtr<MediaControlCurrentTimeDisplayElement> element = new MediaControlCurr entTimeDisplayElement(mediaControls); |
661 element->setShadowPseudoId(AtomicString("-webkit-media-controls-current-time -display")); | 829 element->setShadowPseudoId(AtomicString("-webkit-media-controls-current-time -display")); |
662 return element.release(); | 830 return element.release(); |
663 } | 831 } |
664 | 832 |
665 } // namespace blink | 833 } // namespace blink |
OLD | NEW |