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