Remove NonCopyableSort.h from WTF
[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 static bool textTrackCompare(const RefPtr<TextTrack>& a, const RefPtr<TextTrack>& b)
177 {
178     return codePointCompare(trackDisplayName(a.get()), trackDisplayName(b.get())) < 0;
179 }
180
181 Vector<RefPtr<TextTrack>> CaptionUserPreferences::sortedTrackListForMenu(TextTrackList* trackList)
182 {
183     ASSERT(trackList);
184
185     Vector<RefPtr<TextTrack>> tracksForMenu;
186
187     for (unsigned i = 0, length = trackList->length(); i < length; ++i)
188         tracksForMenu.append(trackList->item(i));
189
190     std::sort(tracksForMenu.begin(), tracksForMenu.end(), textTrackCompare);
191
192     tracksForMenu.insert(0, TextTrack::captionMenuOffItem());
193     tracksForMenu.insert(1, TextTrack::captionMenuAutomaticItem());
194
195     return tracksForMenu;
196 }
197
198 int CaptionUserPreferences::textTrackSelectionScore(TextTrack* track, HTMLMediaElement*) const
199 {
200     int trackScore = 0;
201
202     if (track->kind() != TextTrack::captionsKeyword() && track->kind() != TextTrack::subtitlesKeyword())
203         return trackScore;
204     
205     if (!userPrefersSubtitles() && !userPrefersCaptions())
206         return trackScore;
207     
208     if (track->kind() == TextTrack::subtitlesKeyword() && userPrefersSubtitles())
209         trackScore = 1;
210     else if (track->kind() == TextTrack::captionsKeyword() && userPrefersCaptions())
211         trackScore = 1;
212     
213     return trackScore + textTrackLanguageSelectionScore(track, preferredLanguages());
214 }
215
216 int CaptionUserPreferences::textTrackLanguageSelectionScore(TextTrack* track, const Vector<String>& preferredLanguages) const
217 {
218     if (track->language().isEmpty())
219         return 0;
220
221     size_t languageMatchIndex = indexOfBestMatchingLanguageInList(track->language(), preferredLanguages);
222     if (languageMatchIndex >= preferredLanguages.size())
223         return 0;
224
225     // Matching a track language is more important than matching track type, so this multiplier must be
226     // greater than the maximum value returned by textTrackSelectionScore.
227     return (preferredLanguages.size() - languageMatchIndex) * 10;
228 }
229
230 void CaptionUserPreferences::setCaptionsStyleSheetOverride(const String& override)
231 {
232     m_captionsStyleSheetOverride = override;
233     updateCaptionStyleSheetOveride();
234 }
235
236 void CaptionUserPreferences::updateCaptionStyleSheetOveride()
237 {
238     // Identify our override style sheet with a unique URL - a new scheme and a UUID.
239     DEFINE_STATIC_LOCAL(KURL, captionsStyleSheetURL, (ParsedURLString, "user-captions-override:01F6AF12-C3B0-4F70-AF5E-A3E00234DC23"));
240
241     pageGroup()->removeUserStyleSheetFromWorld(mainThreadNormalWorld(), captionsStyleSheetURL);
242
243     String captionsOverrideStyleSheet = captionsStyleSheetOverride();
244     if (captionsOverrideStyleSheet.isEmpty())
245         return;
246
247     pageGroup()->addUserStyleSheetToWorld(mainThreadNormalWorld(), captionsOverrideStyleSheet, captionsStyleSheetURL, Vector<String>(),
248         Vector<String>(), InjectInAllFrames, UserStyleAuthorLevel, InjectInExistingDocuments);
249 }
250
251 String CaptionUserPreferences::primaryAudioTrackLanguageOverride() const
252 {
253     if (!m_primaryAudioTrackLanguageOverride.isEmpty())
254         return m_primaryAudioTrackLanguageOverride;
255     return defaultLanguage();
256 }
257     
258 }
259
260 #endif // ENABLE(VIDEO_TRACK)