OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "config.h" |
| 6 #include "core/html/track/AutomaticTrackSelection.h" |
| 7 |
| 8 #include "core/html/track/TextTrack.h" |
| 9 #include "core/html/track/TextTrackList.h" |
| 10 #include "platform/Language.h" |
| 11 |
| 12 namespace blink { |
| 13 |
| 14 class TrackGroup { |
| 15 STACK_ALLOCATED(); |
| 16 public: |
| 17 enum GroupKind { |
| 18 CaptionsAndSubtitles, |
| 19 Description, |
| 20 Chapter, |
| 21 Metadata |
| 22 }; |
| 23 |
| 24 explicit TrackGroup(GroupKind kind) |
| 25 : visibleTrack(nullptr) |
| 26 , defaultTrack(nullptr) |
| 27 , kind(kind) |
| 28 , hasSrcLang(false) |
| 29 { |
| 30 } |
| 31 |
| 32 WillBeHeapVector<RefPtrWillBeMember<TextTrack>> tracks; |
| 33 RefPtrWillBeMember<TextTrack> visibleTrack; |
| 34 RefPtrWillBeMember<TextTrack> defaultTrack; |
| 35 GroupKind kind; |
| 36 bool hasSrcLang; |
| 37 }; |
| 38 |
| 39 static int textTrackLanguageSelectionScore(const TextTrack& track) |
| 40 { |
| 41 if (track.language().isEmpty()) |
| 42 return 0; |
| 43 |
| 44 Vector<AtomicString> languages = userPreferredLanguages(); |
| 45 size_t languageMatchIndex = indexOfBestMatchingLanguageInList(track.language
(), languages); |
| 46 if (languageMatchIndex >= languages.size()) |
| 47 return 0; |
| 48 |
| 49 return languages.size() - languageMatchIndex; |
| 50 } |
| 51 |
| 52 static int textTrackSelectionScore(const TextTrack& track) |
| 53 { |
| 54 if (track.kind() != TextTrack::captionsKeyword() && track.kind() != TextTrac
k::subtitlesKeyword()) |
| 55 return 0; |
| 56 |
| 57 return textTrackLanguageSelectionScore(track); |
| 58 } |
| 59 |
| 60 AutomaticTrackSelection::AutomaticTrackSelection(const Configuration& configurat
ion) |
| 61 : m_configuration(configuration) |
| 62 { |
| 63 } |
| 64 |
| 65 void AutomaticTrackSelection::performAutomaticTextTrackSelection(const TrackGrou
p& group) |
| 66 { |
| 67 ASSERT(group.tracks.size()); |
| 68 |
| 69 // First, find the track in the group that should be enabled (if any). |
| 70 WillBeHeapVector<RefPtrWillBeMember<TextTrack>> currentlyEnabledTracks; |
| 71 RefPtrWillBeRawPtr<TextTrack> trackToEnable = nullptr; |
| 72 RefPtrWillBeRawPtr<TextTrack> defaultTrack = nullptr; |
| 73 RefPtrWillBeRawPtr<TextTrack> fallbackTrack = nullptr; |
| 74 int highestTrackScore = 0; |
| 75 for (size_t i = 0; i < group.tracks.size(); ++i) { |
| 76 RefPtrWillBeRawPtr<TextTrack> textTrack = group.tracks[i]; |
| 77 |
| 78 if (m_configuration.disableCurrentlyEnabledTracks && textTrack->mode() =
= TextTrack::showingKeyword()) |
| 79 currentlyEnabledTracks.append(textTrack); |
| 80 |
| 81 int trackScore = textTrackSelectionScore(*textTrack); |
| 82 if (trackScore) { |
| 83 // * If the text track kind is { [subtitles or captions] [descriptio
ns] } and the user has indicated an interest in having a |
| 84 // track with this text track kind, text track language, and text tr
ack label enabled, and there is no |
| 85 // other text track in the media element's list of text tracks with
a text track kind of either subtitles |
| 86 // or captions whose text track mode is showing |
| 87 // ... |
| 88 // * If the text track kind is chapters and the text track language
is one that the user agent has reason |
| 89 // to believe is appropriate for the user, and there is no other tex
t track in the media element's list of |
| 90 // text tracks with a text track kind of chapters whose text track m
ode is showing |
| 91 // Let the text track mode be showing. |
| 92 if (trackScore > highestTrackScore) { |
| 93 highestTrackScore = trackScore; |
| 94 trackToEnable = textTrack; |
| 95 } |
| 96 |
| 97 if (!defaultTrack && textTrack->isDefault()) |
| 98 defaultTrack = textTrack; |
| 99 if (!defaultTrack && !fallbackTrack) |
| 100 fallbackTrack = textTrack; |
| 101 } else if (!group.visibleTrack && !defaultTrack && textTrack->isDefault(
)) { |
| 102 // * If the track element has a default attribute specified, and the
re is no other text track in the media |
| 103 // element's list of text tracks whose text track mode is showing or
showing by default |
| 104 // Let the text track mode be showing by default. |
| 105 defaultTrack = textTrack; |
| 106 } |
| 107 } |
| 108 |
| 109 if (!trackToEnable && defaultTrack) |
| 110 trackToEnable = defaultTrack; |
| 111 |
| 112 // If no track matches the user's preferred language and non was marked 'def
ault', enable the first track |
| 113 // because the user has explicitly stated a preference for this kind of trac
k. |
| 114 if (!fallbackTrack && m_configuration.forceEnableSubtitleOrCaptionTrack && g
roup.kind == TrackGroup::CaptionsAndSubtitles) |
| 115 fallbackTrack = group.tracks[0]; |
| 116 |
| 117 if (!trackToEnable && fallbackTrack) |
| 118 trackToEnable = fallbackTrack; |
| 119 |
| 120 if (currentlyEnabledTracks.size()) { |
| 121 for (size_t i = 0; i < currentlyEnabledTracks.size(); ++i) { |
| 122 RefPtrWillBeRawPtr<TextTrack> textTrack = currentlyEnabledTracks[i]; |
| 123 if (textTrack != trackToEnable) |
| 124 textTrack->setMode(TextTrack::disabledKeyword()); |
| 125 } |
| 126 } |
| 127 |
| 128 if (trackToEnable) |
| 129 trackToEnable->setMode(TextTrack::showingKeyword()); |
| 130 } |
| 131 |
| 132 void AutomaticTrackSelection::enableDefaultMetadataTextTracks(const TrackGroup&
group) |
| 133 { |
| 134 ASSERT(group.tracks.size()); |
| 135 |
| 136 // https://html.spec.whatwg.org/multipage/embedded-content.html#honor-user-p
references-for-automatic-text-track-selection |
| 137 |
| 138 // 4. If there are any text tracks in the media element's list of text |
| 139 // tracks whose text track kind is metadata that correspond to track |
| 140 // elements with a default attribute set whose text track mode is set to |
| 141 // disabled, then set the text track mode of all such tracks to hidden |
| 142 for (auto& textTrack : group.tracks) { |
| 143 if (textTrack->mode() != TextTrack::disabledKeyword()) |
| 144 continue; |
| 145 if (!textTrack->isDefault()) |
| 146 continue; |
| 147 textTrack->setMode(TextTrack::hiddenKeyword()); |
| 148 } |
| 149 } |
| 150 |
| 151 void AutomaticTrackSelection::perform(TextTrackList& textTracks) |
| 152 { |
| 153 TrackGroup captionAndSubtitleTracks(TrackGroup::CaptionsAndSubtitles); |
| 154 TrackGroup descriptionTracks(TrackGroup::Description); |
| 155 TrackGroup chapterTracks(TrackGroup::Chapter); |
| 156 TrackGroup metadataTracks(TrackGroup::Metadata); |
| 157 |
| 158 for (size_t i = 0; i < textTracks.length(); ++i) { |
| 159 RefPtrWillBeRawPtr<TextTrack> textTrack = textTracks.item(i); |
| 160 if (!textTrack) |
| 161 continue; |
| 162 |
| 163 String kind = textTrack->kind(); |
| 164 TrackGroup* currentGroup; |
| 165 if (kind == TextTrack::subtitlesKeyword() || kind == TextTrack::captions
Keyword()) { |
| 166 currentGroup = &captionAndSubtitleTracks; |
| 167 } else if (kind == TextTrack::descriptionsKeyword()) { |
| 168 currentGroup = &descriptionTracks; |
| 169 } else if (kind == TextTrack::chaptersKeyword()) { |
| 170 currentGroup = &chapterTracks; |
| 171 } else { |
| 172 ASSERT(kind == TextTrack::metadataKeyword()); |
| 173 currentGroup = &metadataTracks; |
| 174 } |
| 175 |
| 176 if (!currentGroup->visibleTrack && textTrack->mode() == TextTrack::showi
ngKeyword()) |
| 177 currentGroup->visibleTrack = textTrack; |
| 178 if (!currentGroup->defaultTrack && textTrack->isDefault()) |
| 179 currentGroup->defaultTrack = textTrack; |
| 180 |
| 181 // Do not add this track to the group if it has already been automatical
ly configured |
| 182 // as we only want to perform selection once per track so that adding an
other track |
| 183 // after the initial configuration doesn't reconfigure every track - onl
y those that |
| 184 // should be changed by the new addition. For example all metadata track
s are |
| 185 // disabled by default, and we don't want a track that has been enabled
by script |
| 186 // to be disabled automatically when a new metadata track is added later
. |
| 187 if (textTrack->hasBeenConfigured()) |
| 188 continue; |
| 189 |
| 190 if (textTrack->language().length()) |
| 191 currentGroup->hasSrcLang = true; |
| 192 currentGroup->tracks.append(textTrack); |
| 193 } |
| 194 |
| 195 if (captionAndSubtitleTracks.tracks.size()) |
| 196 performAutomaticTextTrackSelection(captionAndSubtitleTracks); |
| 197 if (descriptionTracks.tracks.size()) |
| 198 performAutomaticTextTrackSelection(descriptionTracks); |
| 199 if (chapterTracks.tracks.size()) |
| 200 performAutomaticTextTrackSelection(chapterTracks); |
| 201 if (metadataTracks.tracks.size()) |
| 202 enableDefaultMetadataTextTracks(metadataTracks); |
| 203 } |
| 204 |
| 205 } // namespace blink |
OLD | NEW |