OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All rights
reserved. | 2 * Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. 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 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
45 #include "core/html/HTMLMediaSource.h" | 45 #include "core/html/HTMLMediaSource.h" |
46 #include "core/html/HTMLSourceElement.h" | 46 #include "core/html/HTMLSourceElement.h" |
47 #include "core/html/HTMLTrackElement.h" | 47 #include "core/html/HTMLTrackElement.h" |
48 #include "core/html/MediaController.h" | 48 #include "core/html/MediaController.h" |
49 #include "core/html/MediaError.h" | 49 #include "core/html/MediaError.h" |
50 #include "core/html/MediaFragmentURIParser.h" | 50 #include "core/html/MediaFragmentURIParser.h" |
51 #include "core/html/TimeRanges.h" | 51 #include "core/html/TimeRanges.h" |
52 #include "core/html/shadow/MediaControls.h" | 52 #include "core/html/shadow/MediaControls.h" |
53 #include "core/html/track/AudioTrack.h" | 53 #include "core/html/track/AudioTrack.h" |
54 #include "core/html/track/AudioTrackList.h" | 54 #include "core/html/track/AudioTrackList.h" |
| 55 #include "core/html/track/AutomaticTrackSelection.h" |
55 #include "core/html/track/InbandTextTrack.h" | 56 #include "core/html/track/InbandTextTrack.h" |
56 #include "core/html/track/TextTrackCueList.h" | 57 #include "core/html/track/TextTrackCueList.h" |
57 #include "core/html/track/TextTrackList.h" | 58 #include "core/html/track/TextTrackList.h" |
58 #include "core/html/track/VideoTrack.h" | 59 #include "core/html/track/VideoTrack.h" |
59 #include "core/html/track/VideoTrackList.h" | 60 #include "core/html/track/VideoTrackList.h" |
60 #include "core/layout/compositing/LayerCompositor.h" | 61 #include "core/layout/compositing/LayerCompositor.h" |
61 #include "core/loader/FrameLoader.h" | 62 #include "core/loader/FrameLoader.h" |
62 #include "core/rendering/RenderVideo.h" | 63 #include "core/rendering/RenderVideo.h" |
63 #include "core/rendering/RenderView.h" | 64 #include "core/rendering/RenderView.h" |
64 #include "platform/ContentType.h" | 65 #include "platform/ContentType.h" |
65 #include "platform/Language.h" | |
66 #include "platform/Logging.h" | 66 #include "platform/Logging.h" |
67 #include "platform/MIMETypeFromURL.h" | 67 #include "platform/MIMETypeFromURL.h" |
68 #include "platform/MIMETypeRegistry.h" | 68 #include "platform/MIMETypeRegistry.h" |
69 #include "platform/RuntimeEnabledFeatures.h" | 69 #include "platform/RuntimeEnabledFeatures.h" |
70 #include "platform/UserGestureIndicator.h" | 70 #include "platform/UserGestureIndicator.h" |
71 #include "platform/graphics/GraphicsLayer.h" | 71 #include "platform/graphics/GraphicsLayer.h" |
72 #include "platform/weborigin/SecurityOrigin.h" | 72 #include "platform/weborigin/SecurityOrigin.h" |
73 #include "public/platform/Platform.h" | 73 #include "public/platform/Platform.h" |
74 #include "public/platform/WebContentDecryptionModule.h" | 74 #include "public/platform/WebContentDecryptionModule.h" |
75 #include "public/platform/WebInbandTextTrack.h" | 75 #include "public/platform/WebInbandTextTrack.h" |
(...skipping 2760 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2836 // When a track element's parent element changes and the old parent was a me
dia element, | 2836 // When a track element's parent element changes and the old parent was a me
dia element, |
2837 // then the user agent must remove the track element's corresponding text tr
ack from the | 2837 // then the user agent must remove the track element's corresponding text tr
ack from the |
2838 // media element's list of text tracks. | 2838 // media element's list of text tracks. |
2839 removeTextTrack(textTrack.get()); | 2839 removeTextTrack(textTrack.get()); |
2840 | 2840 |
2841 size_t index = m_textTracksWhenResourceSelectionBegan.find(textTrack.get()); | 2841 size_t index = m_textTracksWhenResourceSelectionBegan.find(textTrack.get()); |
2842 if (index != kNotFound) | 2842 if (index != kNotFound) |
2843 m_textTracksWhenResourceSelectionBegan.remove(index); | 2843 m_textTracksWhenResourceSelectionBegan.remove(index); |
2844 } | 2844 } |
2845 | 2845 |
2846 static int textTrackLanguageSelectionScore(const TextTrack& track) | |
2847 { | |
2848 if (track.language().isEmpty()) | |
2849 return 0; | |
2850 | |
2851 Vector<AtomicString> languages = userPreferredLanguages(); | |
2852 size_t languageMatchIndex = indexOfBestMatchingLanguageInList(track.language
(), languages); | |
2853 if (languageMatchIndex >= languages.size()) | |
2854 return 0; | |
2855 | |
2856 return languages.size() - languageMatchIndex; | |
2857 } | |
2858 | |
2859 static int textTrackSelectionScore(const TextTrack& track) | |
2860 { | |
2861 if (track.kind() != TextTrack::captionsKeyword() && track.kind() != TextTrac
k::subtitlesKeyword()) | |
2862 return 0; | |
2863 | |
2864 return textTrackLanguageSelectionScore(track); | |
2865 } | |
2866 | |
2867 void HTMLMediaElement::performAutomaticTextTrackSelection(const TrackGroup& grou
p) | |
2868 { | |
2869 ASSERT(group.tracks.size()); | |
2870 | |
2871 WTF_LOG(Media, "HTMLMediaElement::configureTextTrackGroup(%p, %d)", this, gr
oup.kind); | |
2872 | |
2873 // First, find the track in the group that should be enabled (if any). | |
2874 WillBeHeapVector<RefPtrWillBeMember<TextTrack>> currentlyEnabledTracks; | |
2875 RefPtrWillBeRawPtr<TextTrack> trackToEnable = nullptr; | |
2876 RefPtrWillBeRawPtr<TextTrack> defaultTrack = nullptr; | |
2877 RefPtrWillBeRawPtr<TextTrack> fallbackTrack = nullptr; | |
2878 int highestTrackScore = 0; | |
2879 for (size_t i = 0; i < group.tracks.size(); ++i) { | |
2880 RefPtrWillBeRawPtr<TextTrack> textTrack = group.tracks[i]; | |
2881 | |
2882 if (m_processingPreferenceChange && textTrack->mode() == TextTrack::show
ingKeyword()) | |
2883 currentlyEnabledTracks.append(textTrack); | |
2884 | |
2885 int trackScore = textTrackSelectionScore(*textTrack); | |
2886 if (trackScore) { | |
2887 // * If the text track kind is { [subtitles or captions] [descriptio
ns] } and the user has indicated an interest in having a | |
2888 // track with this text track kind, text track language, and text tr
ack label enabled, and there is no | |
2889 // other text track in the media element's list of text tracks with
a text track kind of either subtitles | |
2890 // or captions whose text track mode is showing | |
2891 // ... | |
2892 // * If the text track kind is chapters and the text track language
is one that the user agent has reason | |
2893 // to believe is appropriate for the user, and there is no other tex
t track in the media element's list of | |
2894 // text tracks with a text track kind of chapters whose text track m
ode is showing | |
2895 // Let the text track mode be showing. | |
2896 if (trackScore > highestTrackScore) { | |
2897 highestTrackScore = trackScore; | |
2898 trackToEnable = textTrack; | |
2899 } | |
2900 | |
2901 if (!defaultTrack && textTrack->isDefault()) | |
2902 defaultTrack = textTrack; | |
2903 if (!defaultTrack && !fallbackTrack) | |
2904 fallbackTrack = textTrack; | |
2905 } else if (!group.visibleTrack && !defaultTrack && textTrack->isDefault(
)) { | |
2906 // * If the track element has a default attribute specified, and the
re is no other text track in the media | |
2907 // element's list of text tracks whose text track mode is showing or
showing by default | |
2908 // Let the text track mode be showing by default. | |
2909 defaultTrack = textTrack; | |
2910 } | |
2911 } | |
2912 | |
2913 if (!trackToEnable && defaultTrack) | |
2914 trackToEnable = defaultTrack; | |
2915 | |
2916 // If no track matches the user's preferred language and non was marked 'def
ault', enable the first track | |
2917 // because the user has explicitly stated a preference for this kind of trac
k. | |
2918 if (!fallbackTrack && m_closedCaptionsVisible && group.kind == TrackGroup::C
aptionsAndSubtitles) | |
2919 fallbackTrack = group.tracks[0]; | |
2920 | |
2921 if (!trackToEnable && fallbackTrack) | |
2922 trackToEnable = fallbackTrack; | |
2923 | |
2924 if (currentlyEnabledTracks.size()) { | |
2925 for (size_t i = 0; i < currentlyEnabledTracks.size(); ++i) { | |
2926 RefPtrWillBeRawPtr<TextTrack> textTrack = currentlyEnabledTracks[i]; | |
2927 if (textTrack != trackToEnable) | |
2928 textTrack->setMode(TextTrack::disabledKeyword()); | |
2929 } | |
2930 } | |
2931 | |
2932 if (trackToEnable) | |
2933 trackToEnable->setMode(TextTrack::showingKeyword()); | |
2934 } | |
2935 | |
2936 void HTMLMediaElement::enableDefaultMetadataTextTracks(const TrackGroup& group) | |
2937 { | |
2938 ASSERT(group.tracks.size()); | |
2939 | |
2940 // https://html.spec.whatwg.org/multipage/embedded-content.html#honor-user-p
references-for-automatic-text-track-selection | |
2941 | |
2942 // 4. If there are any text tracks in the media element's list of text | |
2943 // tracks whose text track kind is metadata that correspond to track | |
2944 // elements with a default attribute set whose text track mode is set to | |
2945 // disabled, then set the text track mode of all such tracks to hidden | |
2946 for (auto& textTrack : group.tracks) { | |
2947 if (textTrack->mode() != TextTrack::disabledKeyword()) | |
2948 continue; | |
2949 if (!textTrack->isDefault()) | |
2950 continue; | |
2951 textTrack->setMode(TextTrack::hiddenKeyword()); | |
2952 } | |
2953 } | |
2954 | |
2955 void HTMLMediaElement::honorUserPreferencesForAutomaticTextTrackSelection() | 2846 void HTMLMediaElement::honorUserPreferencesForAutomaticTextTrackSelection() |
2956 { | 2847 { |
2957 TrackGroup captionAndSubtitleTracks(TrackGroup::CaptionsAndSubtitles); | 2848 if (!m_textTracks || !m_textTracks->length()) |
2958 TrackGroup descriptionTracks(TrackGroup::Description); | |
2959 TrackGroup chapterTracks(TrackGroup::Chapter); | |
2960 TrackGroup metadataTracks(TrackGroup::Metadata); | |
2961 | |
2962 if (!m_textTracks) | |
2963 return; | 2849 return; |
2964 | 2850 |
2965 for (size_t i = 0; i < m_textTracks->length(); ++i) { | 2851 AutomaticTrackSelection::Configuration configuration; |
2966 RefPtrWillBeRawPtr<TextTrack> textTrack = m_textTracks->item(i); | 2852 if (m_processingPreferenceChange) |
2967 if (!textTrack) | 2853 configuration.disableCurrentlyEnabledTracks = true; |
2968 continue; | 2854 if (m_closedCaptionsVisible) |
| 2855 configuration.forceEnableSubtitleOrCaptionTrack = true; |
2969 | 2856 |
2970 String kind = textTrack->kind(); | 2857 AutomaticTrackSelection trackSelection(configuration); |
2971 TrackGroup* currentGroup; | 2858 trackSelection.perform(*m_textTracks); |
2972 if (kind == TextTrack::subtitlesKeyword() || kind == TextTrack::captions
Keyword()) { | |
2973 currentGroup = &captionAndSubtitleTracks; | |
2974 } else if (kind == TextTrack::descriptionsKeyword()) { | |
2975 currentGroup = &descriptionTracks; | |
2976 } else if (kind == TextTrack::chaptersKeyword()) { | |
2977 currentGroup = &chapterTracks; | |
2978 } else { | |
2979 ASSERT(kind == TextTrack::metadataKeyword()); | |
2980 currentGroup = &metadataTracks; | |
2981 } | |
2982 | |
2983 if (!currentGroup->visibleTrack && textTrack->mode() == TextTrack::showi
ngKeyword()) | |
2984 currentGroup->visibleTrack = textTrack; | |
2985 if (!currentGroup->defaultTrack && textTrack->isDefault()) | |
2986 currentGroup->defaultTrack = textTrack; | |
2987 | |
2988 // Do not add this track to the group if it has already been automatical
ly configured | |
2989 // as we only want to perform selection once per track so that adding an
other track | |
2990 // after the initial configuration doesn't reconfigure every track - onl
y those that | |
2991 // should be changed by the new addition. For example all metadata track
s are | |
2992 // disabled by default, and we don't want a track that has been enabled
by script | |
2993 // to be disabled automatically when a new metadata track is added later
. | |
2994 if (textTrack->hasBeenConfigured()) | |
2995 continue; | |
2996 | |
2997 if (textTrack->language().length()) | |
2998 currentGroup->hasSrcLang = true; | |
2999 currentGroup->tracks.append(textTrack); | |
3000 } | |
3001 | |
3002 if (captionAndSubtitleTracks.tracks.size()) | |
3003 performAutomaticTextTrackSelection(captionAndSubtitleTracks); | |
3004 if (descriptionTracks.tracks.size()) | |
3005 performAutomaticTextTrackSelection(descriptionTracks); | |
3006 if (chapterTracks.tracks.size()) | |
3007 performAutomaticTextTrackSelection(chapterTracks); | |
3008 if (metadataTracks.tracks.size()) | |
3009 enableDefaultMetadataTextTracks(metadataTracks); | |
3010 | 2859 |
3011 textTracksChanged(); | 2860 textTracksChanged(); |
3012 } | 2861 } |
3013 | 2862 |
3014 bool HTMLMediaElement::havePotentialSourceChild() | 2863 bool HTMLMediaElement::havePotentialSourceChild() |
3015 { | 2864 { |
3016 // Stash the current <source> node and next nodes so we can restore them aft
er checking | 2865 // Stash the current <source> node and next nodes so we can restore them aft
er checking |
3017 // to see there is another potential. | 2866 // to see there is another potential. |
3018 RefPtrWillBeRawPtr<HTMLSourceElement> currentSourceNode = m_currentSourceNod
e; | 2867 RefPtrWillBeRawPtr<HTMLSourceElement> currentSourceNode = m_currentSourceNod
e; |
3019 RefPtrWillBeRawPtr<Node> nextNode = m_nextChildNodeToConsider; | 2868 RefPtrWillBeRawPtr<Node> nextNode = m_nextChildNodeToConsider; |
(...skipping 711 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3731 m_closedCaptionsVisible = closedCaptionVisible; | 3580 m_closedCaptionsVisible = closedCaptionVisible; |
3732 | 3581 |
3733 markCaptionAndSubtitleTracksAsUnconfigured(); | 3582 markCaptionAndSubtitleTracksAsUnconfigured(); |
3734 m_processingPreferenceChange = true; | 3583 m_processingPreferenceChange = true; |
3735 honorUserPreferencesForAutomaticTextTrackSelection(); | 3584 honorUserPreferencesForAutomaticTextTrackSelection(); |
3736 m_processingPreferenceChange = false; | 3585 m_processingPreferenceChange = false; |
3737 | 3586 |
3738 updateTextTrackDisplay(); | 3587 updateTextTrackDisplay(); |
3739 } | 3588 } |
3740 | 3589 |
| 3590 void HTMLMediaElement::markCaptionAndSubtitleTracksAsUnconfigured() |
| 3591 { |
| 3592 if (!m_textTracks) |
| 3593 return; |
| 3594 |
| 3595 // Mark all tracks as not "configured" so that |
| 3596 // honorUserPreferencesForAutomaticTextTrackSelection() will reconsider |
| 3597 // which tracks to display in light of new user preferences (e.g. default |
| 3598 // tracks should not be displayed if the user has turned off captions and |
| 3599 // non-default tracks should be displayed based on language preferences if |
| 3600 // the user has turned captions on). |
| 3601 for (unsigned i = 0; i < m_textTracks->length(); ++i) { |
| 3602 RefPtrWillBeRawPtr<TextTrack> textTrack = m_textTracks->item(i); |
| 3603 String kind = textTrack->kind(); |
| 3604 |
| 3605 if (kind == TextTrack::subtitlesKeyword() || kind == TextTrack::captions
Keyword()) |
| 3606 textTrack->setHasBeenConfigured(false); |
| 3607 } |
| 3608 } |
| 3609 |
3741 unsigned HTMLMediaElement::webkitAudioDecodedByteCount() const | 3610 unsigned HTMLMediaElement::webkitAudioDecodedByteCount() const |
3742 { | 3611 { |
3743 if (!webMediaPlayer()) | 3612 if (!webMediaPlayer()) |
3744 return 0; | 3613 return 0; |
3745 return webMediaPlayer()->audioDecodedByteCount(); | 3614 return webMediaPlayer()->audioDecodedByteCount(); |
3746 } | 3615 } |
3747 | 3616 |
3748 unsigned HTMLMediaElement::webkitVideoDecodedByteCount() const | 3617 unsigned HTMLMediaElement::webkitVideoDecodedByteCount() const |
3749 { | 3618 { |
3750 if (!webMediaPlayer()) | 3619 if (!webMediaPlayer()) |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3848 if (!m_haveVisibleTextTrack && !hasMediaControls()) | 3717 if (!m_haveVisibleTextTrack && !hasMediaControls()) |
3849 return; | 3718 return; |
3850 | 3719 |
3851 ensureMediaControls(); | 3720 ensureMediaControls(); |
3852 mediaControls()->changedClosedCaptionsVisibility(); | 3721 mediaControls()->changedClosedCaptionsVisibility(); |
3853 | 3722 |
3854 updateActiveTextTrackCues(currentTime()); | 3723 updateActiveTextTrackCues(currentTime()); |
3855 updateTextTrackDisplay(); | 3724 updateTextTrackDisplay(); |
3856 } | 3725 } |
3857 | 3726 |
3858 void HTMLMediaElement::markCaptionAndSubtitleTracksAsUnconfigured() | |
3859 { | |
3860 if (!m_textTracks) | |
3861 return; | |
3862 | |
3863 // Mark all tracks as not "configured" so that | |
3864 // honorUserPreferencesForAutomaticTextTrackSelection() will reconsider | |
3865 // which tracks to display in light of new user preferences (e.g. default | |
3866 // tracks should not be displayed if the user has turned off captions and | |
3867 // non-default tracks should be displayed based on language preferences if | |
3868 // the user has turned captions on). | |
3869 for (unsigned i = 0; i < m_textTracks->length(); ++i) { | |
3870 RefPtrWillBeRawPtr<TextTrack> textTrack = m_textTracks->item(i); | |
3871 String kind = textTrack->kind(); | |
3872 | |
3873 if (kind == TextTrack::subtitlesKeyword() || kind == TextTrack::captions
Keyword()) | |
3874 textTrack->setHasBeenConfigured(false); | |
3875 } | |
3876 } | |
3877 | |
3878 void* HTMLMediaElement::preDispatchEventHandler(Event* event) | 3727 void* HTMLMediaElement::preDispatchEventHandler(Event* event) |
3879 { | 3728 { |
3880 if (event && event->type() == EventTypeNames::webkitfullscreenchange) | 3729 if (event && event->type() == EventTypeNames::webkitfullscreenchange) |
3881 configureMediaControls(); | 3730 configureMediaControls(); |
3882 | 3731 |
3883 return nullptr; | 3732 return nullptr; |
3884 } | 3733 } |
3885 | 3734 |
3886 void HTMLMediaElement::createMediaPlayer() | 3735 void HTMLMediaElement::createMediaPlayer() |
3887 { | 3736 { |
(...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4123 | 3972 |
4124 #if ENABLE(WEB_AUDIO) | 3973 #if ENABLE(WEB_AUDIO) |
4125 void HTMLMediaElement::clearWeakMembers(Visitor* visitor) | 3974 void HTMLMediaElement::clearWeakMembers(Visitor* visitor) |
4126 { | 3975 { |
4127 if (!visitor->isAlive(m_audioSourceNode) && audioSourceProvider()) | 3976 if (!visitor->isAlive(m_audioSourceNode) && audioSourceProvider()) |
4128 audioSourceProvider()->setClient(nullptr); | 3977 audioSourceProvider()->setClient(nullptr); |
4129 } | 3978 } |
4130 #endif | 3979 #endif |
4131 | 3980 |
4132 } | 3981 } |
OLD | NEW |