Use "= default" to denote default constructor or destructor
[WebKit-https.git] / Source / WebCore / page / CaptionUserPreferences.cpp
index 7e2876f..b1cc701 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2017 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  */
 
 #include "config.h"
+#include "CaptionUserPreferences.h"
 
 #if ENABLE(VIDEO_TRACK)
 
-#include "CaptionUserPreferences.h"
+#include "AudioTrackList.h"
 #include "DOMWrapperWorld.h"
+#include "LocalizedStrings.h"
+#include "MediaSelectionOption.h"
 #include "Page.h"
 #include "PageGroup.h"
 #include "Settings.h"
 #include "TextTrackList.h"
+#include "UserContentController.h"
+#include "UserContentTypes.h"
+#include "UserStyleSheet.h"
 #include "UserStyleSheetTypes.h"
+#include <heap/HeapInlines.h>
+#include <runtime/JSCellInlines.h>
+#include <runtime/StructureInlines.h>
+#include <wtf/Language.h>
 
 namespace WebCore {
 
 CaptionUserPreferences::CaptionUserPreferences(PageGroup& group)
     : m_pageGroup(group)
     , m_displayMode(ForcedOnly)
-    , m_timer(this, &CaptionUserPreferences::timerFired)
-    , m_testingMode(false)
-    , m_havePreferences(false)
+    , m_timer(*this, &CaptionUserPreferences::timerFired)
+{
+}
+
+CaptionUserPreferences::~CaptionUserPreferences() = default;
+
+void CaptionUserPreferences::timerFired()
 {
+    captionPreferencesChanged();
 }
 
-CaptionUserPreferences::~CaptionUserPreferences()
+void CaptionUserPreferences::beginBlockingNotifications()
 {
+    ++m_blockNotificationsCounter;
 }
 
-void CaptionUserPreferences::timerFired(Timer<CaptionUserPreferences>*)
+void CaptionUserPreferences::endBlockingNotifications()
 {
-    captionPreferencesChanged();
+    ASSERT(m_blockNotificationsCounter);
+    --m_blockNotificationsCounter;
 }
 
 void CaptionUserPreferences::notify()
 {
+    if (m_blockNotificationsCounter)
+        return;
+
     m_havePreferences = true;
     if (!m_timer.isActive())
-        m_timer.startOneShot(0);
+        m_timer.startOneShot(0_s);
 }
 
 CaptionUserPreferences::CaptionDisplayMode CaptionUserPreferences::captionDisplayMode() const
@@ -77,9 +97,17 @@ void CaptionUserPreferences::setCaptionDisplayMode(CaptionUserPreferences::Capti
     notify();
 }
 
+Page* CaptionUserPreferences::currentPage() const
+{
+    if (m_pageGroup.pages().isEmpty())
+        return nullptr;
+
+    return *(m_pageGroup.pages().begin());
+}
+
 bool CaptionUserPreferences::userPrefersCaptions() const
 {
-    Page* page = *(m_pageGroup.pages().begin());
+    Page* page = currentPage();
     if (!page)
         return false;
 
@@ -88,7 +116,7 @@ bool CaptionUserPreferences::userPrefersCaptions() const
 
 void CaptionUserPreferences::setUserPrefersCaptions(bool preference)
 {
-    Page* page = *(m_pageGroup.pages().begin());
+    Page* page = currentPage();
     if (!page)
         return;
 
@@ -98,7 +126,7 @@ void CaptionUserPreferences::setUserPrefersCaptions(bool preference)
 
 bool CaptionUserPreferences::userPrefersSubtitles() const
 {
-    Page* page = *(pageGroup().pages().begin());
+    Page* page = currentPage();
     if (!page)
         return false;
 
@@ -107,7 +135,7 @@ bool CaptionUserPreferences::userPrefersSubtitles() const
 
 void CaptionUserPreferences::setUserPrefersSubtitles(bool preference)
 {
-    Page* page = *(m_pageGroup.pages().begin());
+    Page* page = currentPage();
     if (!page)
         return;
 
@@ -117,7 +145,7 @@ void CaptionUserPreferences::setUserPrefersSubtitles(bool preference)
 
 bool CaptionUserPreferences::userPrefersTextDescriptions() const
 {
-    Page* page = *(m_pageGroup.pages().begin());
+    Page* page = currentPage();
     if (!page)
         return false;
     
@@ -126,7 +154,7 @@ bool CaptionUserPreferences::userPrefersTextDescriptions() const
 
 void CaptionUserPreferences::setUserPrefersTextDescriptions(bool preference)
 {
-    Page* page = *(m_pageGroup.pages().begin());
+    Page* page = currentPage();
     if (!page)
         return;
     
@@ -154,6 +182,20 @@ void CaptionUserPreferences::setPreferredLanguage(const String& language)
     notify();
 }
 
+void CaptionUserPreferences::setPreferredAudioCharacteristic(const String& characteristic)
+{
+    m_userPreferredAudioCharacteristic = characteristic;
+    notify();
+}
+
+Vector<String> CaptionUserPreferences::preferredAudioCharacteristics() const
+{
+    Vector<String> characteristics;
+    if (!m_userPreferredAudioCharacteristic.isEmpty())
+        characteristics.append(m_userPreferredAudioCharacteristic);
+    return characteristics;
+}
+
 static String trackDisplayName(TextTrack* track)
 {
     if (track == TextTrack::captionMenuOffItem())
@@ -161,17 +203,27 @@ static String trackDisplayName(TextTrack* track)
     if (track == TextTrack::captionMenuAutomaticItem())
         return textTrackAutomaticMenuItemText();
 
-    if (track->label().isEmpty() && track->language().isEmpty())
+    if (track->label().isEmpty() && track->validBCP47Language().isEmpty())
         return textTrackNoLabelText();
     if (!track->label().isEmpty())
         return track->label();
-    return track->language();
+    return track->validBCP47Language();
 }
 
 String CaptionUserPreferences::displayNameForTrack(TextTrack* track) const
 {
     return trackDisplayName(track);
 }
+
+MediaSelectionOption CaptionUserPreferences::mediaSelectionOptionForTrack(TextTrack* track) const
+{
+    auto type = MediaSelectionOption::Type::Regular;
+    if (track == TextTrack::captionMenuOffItem())
+        type = MediaSelectionOption::Type::LegibleOff;
+    else if (track == TextTrack::captionMenuAutomaticItem())
+        type = MediaSelectionOption::Type::LegibleAuto;
+    return { displayNameForTrack(track), type };
+}
     
 Vector<RefPtr<TextTrack>> CaptionUserPreferences::sortedTrackListForMenu(TextTrackList* trackList)
 {
@@ -181,12 +233,12 @@ Vector<RefPtr<TextTrack>> CaptionUserPreferences::sortedTrackListForMenu(TextTra
 
     for (unsigned i = 0, length = trackList->length(); i < length; ++i) {
         TextTrack* track = trackList->item(i);
-        const AtomicString& kind = track->kind();
-        if (kind == TextTrack::captionsKeyword() || kind == TextTrack::descriptionsKeyword() || kind == TextTrack::subtitlesKeyword())
+        auto kind = track->kind();
+        if (kind == TextTrack::Kind::Captions || kind == TextTrack::Kind::Descriptions || kind == TextTrack::Kind::Subtitles)
             tracksForMenu.append(track);
     }
 
-    std::sort(tracksForMenu.begin(), tracksForMenu.end(), [](const RefPtr<TextTrack>& a, const RefPtr<TextTrack>& b) {
+    std::sort(tracksForMenu.begin(), tracksForMenu.end(), [](auto& a, auto& b) {
         return codePointCompare(trackDisplayName(a.get()), trackDisplayName(b.get())) < 0;
     });
 
@@ -196,57 +248,81 @@ Vector<RefPtr<TextTrack>> CaptionUserPreferences::sortedTrackListForMenu(TextTra
     return tracksForMenu;
 }
 
-int CaptionUserPreferences::textTrackSelectionScore(TextTrack* track, HTMLMediaElement*) const
+static String trackDisplayName(AudioTrack* track)
+{
+    if (track->label().isEmpty() && track->validBCP47Language().isEmpty())
+        return audioTrackNoLabelText();
+    if (!track->label().isEmpty())
+        return track->label();
+    return track->validBCP47Language();
+}
+
+String CaptionUserPreferences::displayNameForTrack(AudioTrack* track) const
+{
+    return trackDisplayName(track);
+}
+
+MediaSelectionOption CaptionUserPreferences::mediaSelectionOptionForTrack(AudioTrack* track) const
 {
-    int trackScore = 0;
+    return { displayNameForTrack(track), MediaSelectionOption::Type::Regular };
+}
 
-    if (track->kind() != TextTrack::captionsKeyword() && track->kind() != TextTrack::subtitlesKeyword())
-        return trackScore;
+Vector<RefPtr<AudioTrack>> CaptionUserPreferences::sortedTrackListForMenu(AudioTrackList* trackList)
+{
+    ASSERT(trackList);
+
+    Vector<RefPtr<AudioTrack>> tracksForMenu;
+
+    for (unsigned i = 0, length = trackList->length(); i < length; ++i) {
+        AudioTrack* track = trackList->item(i);
+        tracksForMenu.append(track);
+    }
+
+    std::sort(tracksForMenu.begin(), tracksForMenu.end(), [](auto& a, auto& b) {
+        return codePointCompare(trackDisplayName(a.get()), trackDisplayName(b.get())) < 0;
+    });
+
+    return tracksForMenu;
+}
+
+int CaptionUserPreferences::textTrackSelectionScore(TextTrack* track, HTMLMediaElement*) const
+{
+    if (track->kind() != TextTrack::Kind::Captions && track->kind() != TextTrack::Kind::Subtitles)
+        return 0;
     
     if (!userPrefersSubtitles() && !userPrefersCaptions())
-        return trackScore;
-    
-    if (track->kind() == TextTrack::subtitlesKeyword() && userPrefersSubtitles())
-        trackScore = 1;
-    else if (track->kind() == TextTrack::captionsKeyword() && userPrefersCaptions())
-        trackScore = 1;
+        return 0;
     
-    return trackScore + textTrackLanguageSelectionScore(track, preferredLanguages());
+    return textTrackLanguageSelectionScore(track, preferredLanguages()) + 1;
 }
 
 int CaptionUserPreferences::textTrackLanguageSelectionScore(TextTrack* track, const Vector<String>& preferredLanguages) const
 {
-    if (track->language().isEmpty())
+    if (track->validBCP47Language().isEmpty())
         return 0;
 
-    size_t languageMatchIndex = indexOfBestMatchingLanguageInList(track->language(), preferredLanguages);
+    bool exactMatch;
+    size_t languageMatchIndex = indexOfBestMatchingLanguageInList(track->validBCP47Language(), preferredLanguages, exactMatch);
     if (languageMatchIndex >= preferredLanguages.size())
         return 0;
 
     // Matching a track language is more important than matching track type, so this multiplier must be
     // greater than the maximum value returned by textTrackSelectionScore.
-    return (preferredLanguages.size() - languageMatchIndex) * 10;
+    int bonus = exactMatch ? 1 : 0;
+    return (preferredLanguages.size() + bonus - languageMatchIndex) * 10;
 }
 
 void CaptionUserPreferences::setCaptionsStyleSheetOverride(const String& override)
 {
     m_captionsStyleSheetOverride = override;
-    updateCaptionStyleSheetOveride();
+    updateCaptionStyleSheetOverride();
 }
 
-void CaptionUserPreferences::updateCaptionStyleSheetOveride()
+void CaptionUserPreferences::updateCaptionStyleSheetOverride()
 {
-    // Identify our override style sheet with a unique URL - a new scheme and a UUID.
-    DEFINE_STATIC_LOCAL(URL, captionsStyleSheetURL, (ParsedURLString, "user-captions-override:01F6AF12-C3B0-4F70-AF5E-A3E00234DC23"));
-
-    m_pageGroup.removeUserStyleSheetFromWorld(mainThreadNormalWorld(), captionsStyleSheetURL);
-
     String captionsOverrideStyleSheet = captionsStyleSheetOverride();
-    if (captionsOverrideStyleSheet.isEmpty())
-        return;
-
-    m_pageGroup.addUserStyleSheetToWorld(mainThreadNormalWorld(), captionsOverrideStyleSheet, captionsStyleSheetURL, Vector<String>(),
-        Vector<String>(), InjectInAllFrames, UserStyleAuthorLevel, InjectInExistingDocuments);
+    for (auto& page : m_pageGroup.pages())
+        page->setCaptionUserPreferencesStyleSheet(captionsOverrideStyleSheet);
 }
 
 String CaptionUserPreferences::primaryAudioTrackLanguageOverride() const