f8c4d096d85d5fc39afd6b57af6898be88eaf061
[WebKit-https.git] / Source / WebCore / page / CaptionUserPreferences.cpp
1 /*
2  * Copyright (C) 2013 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "config.h"
27
28 #if ENABLE(VIDEO_TRACK)
29
30 #include "CaptionUserPreferences.h"
31 #include "DOMWrapperWorld.h"
32 #include "Page.h"
33 #include "PageGroup.h"
34 #include "Settings.h"
35 #include "TextTrackList.h"
36 #include "UserStyleSheetTypes.h"
37
38 namespace WebCore {
39
40 CaptionUserPreferences::CaptionUserPreferences(PageGroup* group)
41     : m_pageGroup(group)
42     , m_displayMode(ForcedOnly)
43     , m_timer(this, &CaptionUserPreferences::timerFired)
44     , m_testingMode(false)
45     , m_havePreferences(false)
46 {
47 }
48
49 CaptionUserPreferences::~CaptionUserPreferences()
50 {
51 }
52
53 void CaptionUserPreferences::timerFired(Timer<CaptionUserPreferences>*)
54 {
55     captionPreferencesChanged();
56 }
57
58 void CaptionUserPreferences::notify()
59 {
60     m_havePreferences = true;
61     if (!m_timer.isActive())
62         m_timer.startOneShot(0);
63 }
64
65 CaptionUserPreferences::CaptionDisplayMode CaptionUserPreferences::captionDisplayMode() const
66 {
67     return m_displayMode;
68 }
69
70 void CaptionUserPreferences::setCaptionDisplayMode(CaptionUserPreferences::CaptionDisplayMode mode)
71 {
72     m_displayMode = mode;
73     if (m_testingMode && mode != AlwaysOn) {
74         setUserPrefersCaptions(false);
75         setUserPrefersSubtitles(false);
76     }
77     notify();
78 }
79
80 bool CaptionUserPreferences::userPrefersCaptions() const
81 {
82     Page* page = *(pageGroup()->pages().begin());
83     if (!page)
84         return false;
85
86     return page->settings().shouldDisplayCaptions();
87 }
88
89 void CaptionUserPreferences::setUserPrefersCaptions(bool preference)
90 {
91     Page* page = *(pageGroup()->pages().begin());
92     if (!page)
93         return;
94
95     page->settings().setShouldDisplayCaptions(preference);
96     notify();
97 }
98
99 bool CaptionUserPreferences::userPrefersSubtitles() const
100 {
101     Page* page = *(pageGroup()->pages().begin());
102     if (!page)
103         return false;
104
105     return page->settings().shouldDisplaySubtitles();
106 }
107
108 void CaptionUserPreferences::setUserPrefersSubtitles(bool preference)
109 {
110     Page* page = *(pageGroup()->pages().begin());
111     if (!page)
112         return;
113
114     page->settings().setShouldDisplaySubtitles(preference);
115     notify();
116 }
117
118 bool CaptionUserPreferences::userPrefersTextDescriptions() const
119 {
120     Page* page = *(pageGroup()->pages().begin());
121     if (!page)
122         return false;
123     
124     return page->settings().shouldDisplayTextDescriptions();
125 }
126
127 void CaptionUserPreferences::setUserPrefersTextDescriptions(bool preference)
128 {
129     Page* page = *(pageGroup()->pages().begin());
130     if (!page)
131         return;
132     
133     page->settings().setShouldDisplayTextDescriptions(preference);
134     notify();
135 }
136
137 void CaptionUserPreferences::captionPreferencesChanged()
138 {
139     m_pageGroup->captionPreferencesChanged();
140 }
141
142 Vector<String> CaptionUserPreferences::preferredLanguages() const
143 {
144     Vector<String> languages = userPreferredLanguages();
145     if (m_testingMode && !m_userPreferredLanguage.isEmpty())
146         languages.insert(0, m_userPreferredLanguage);
147
148     return languages;
149 }
150
151 void CaptionUserPreferences::setPreferredLanguage(const String& language)
152 {
153     m_userPreferredLanguage = language;
154     notify();
155 }
156
157 static String trackDisplayName(TextTrack* track)
158 {
159     if (track == TextTrack::captionMenuOffItem())
160         return textTrackOffMenuItemText();
161     if (track == TextTrack::captionMenuAutomaticItem())
162         return textTrackAutomaticMenuItemText();
163
164     if (track->label().isEmpty() && track->language().isEmpty())
165         return textTrackNoLabelText();
166     if (!track->label().isEmpty())
167         return track->label();
168     return track->language();
169 }
170
171 String CaptionUserPreferences::displayNameForTrack(TextTrack* track) const
172 {
173     return trackDisplayName(track);
174 }
175     
176 Vector<RefPtr<TextTrack>> CaptionUserPreferences::sortedTrackListForMenu(TextTrackList* trackList)
177 {
178     ASSERT(trackList);
179
180     Vector<RefPtr<TextTrack>> tracksForMenu;
181
182     for (unsigned i = 0, length = trackList->length(); i < length; ++i)
183         tracksForMenu.append(trackList->item(i));
184
185     std::sort(tracksForMenu.begin(), tracksForMenu.end(), [](const RefPtr<TextTrack>& a, const RefPtr<TextTrack>& b) {
186         return codePointCompare(trackDisplayName(a.get()), trackDisplayName(b.get())) < 0;
187     });
188
189     tracksForMenu.insert(0, TextTrack::captionMenuOffItem());
190     tracksForMenu.insert(1, TextTrack::captionMenuAutomaticItem());
191
192     return tracksForMenu;
193 }
194
195 int CaptionUserPreferences::textTrackSelectionScore(TextTrack* track, HTMLMediaElement*) const
196 {
197     int trackScore = 0;
198
199     if (track->kind() != TextTrack::captionsKeyword() && track->kind() != TextTrack::subtitlesKeyword())
200         return trackScore;
201     
202     if (!userPrefersSubtitles() && !userPrefersCaptions())
203         return trackScore;
204     
205     if (track->kind() == TextTrack::subtitlesKeyword() && userPrefersSubtitles())
206         trackScore = 1;
207     else if (track->kind() == TextTrack::captionsKeyword() && userPrefersCaptions())
208         trackScore = 1;
209     
210     return trackScore + textTrackLanguageSelectionScore(track, preferredLanguages());
211 }
212
213 int CaptionUserPreferences::textTrackLanguageSelectionScore(TextTrack* track, const Vector<String>& preferredLanguages) const
214 {
215     if (track->language().isEmpty())
216         return 0;
217
218     size_t languageMatchIndex = indexOfBestMatchingLanguageInList(track->language(), preferredLanguages);
219     if (languageMatchIndex >= preferredLanguages.size())
220         return 0;
221
222     // Matching a track language is more important than matching track type, so this multiplier must be
223     // greater than the maximum value returned by textTrackSelectionScore.
224     return (preferredLanguages.size() - languageMatchIndex) * 10;
225 }
226
227 void CaptionUserPreferences::setCaptionsStyleSheetOverride(const String& override)
228 {
229     m_captionsStyleSheetOverride = override;
230     updateCaptionStyleSheetOveride();
231 }
232
233 void CaptionUserPreferences::updateCaptionStyleSheetOveride()
234 {
235     // Identify our override style sheet with a unique URL - a new scheme and a UUID.
236     DEFINE_STATIC_LOCAL(KURL, captionsStyleSheetURL, (ParsedURLString, "user-captions-override:01F6AF12-C3B0-4F70-AF5E-A3E00234DC23"));
237
238     pageGroup()->removeUserStyleSheetFromWorld(mainThreadNormalWorld(), captionsStyleSheetURL);
239
240     String captionsOverrideStyleSheet = captionsStyleSheetOverride();
241     if (captionsOverrideStyleSheet.isEmpty())
242         return;
243
244     pageGroup()->addUserStyleSheetToWorld(mainThreadNormalWorld(), captionsOverrideStyleSheet, captionsStyleSheetURL, Vector<String>(),
245         Vector<String>(), InjectInAllFrames, UserStyleAuthorLevel, InjectInExistingDocuments);
246 }
247
248 String CaptionUserPreferences::primaryAudioTrackLanguageOverride() const
249 {
250     if (!m_primaryAudioTrackLanguageOverride.isEmpty())
251         return m_primaryAudioTrackLanguageOverride;
252     return defaultLanguage();
253 }
254     
255 }
256
257 #endif // ENABLE(VIDEO_TRACK)