From 52578181758e980fe406e5fcd49d02606995b4cc Mon Sep 17 00:00:00 2001 From: "eric.carlson@apple.com" Date: Thu, 2 Feb 2012 05:10:31 +0000 Subject: [PATCH] Consider user's preferred language when choosing text tracks https://bugs.webkit.org/show_bug.cgi?id=74121 Reviewed by Alexey Proskuryakov. Source/WebCore: Tests: media/track/track-language-preference.html media/track/track-prefer-captions.html * html/HTMLMediaElement.cpp: (WebCore::HTMLMediaElement::loadTimerFired): configureTextTracks -> configureNewTextTracks. (WebCore::HTMLMediaElement::textTracksAreReady): Add more comments. (WebCore::HTMLMediaElement::textTrackModeChanged): Ditto. (WebCore::HTMLMediaElement::showingTrackWithSameKind): Minor restructuring. (WebCore::HTMLMediaElement::userIsInterestedInThisTrackKind): Renamed from userIsInterestedInThisTrack, don't consider user's language preference. (WebCore::HTMLMediaElement::configureTextTrackGroup): New, configure all tracks in a group, considering user's kind and language preferences. (WebCore::HTMLMediaElement::configureNewTextTracks): New, configure all newly added tracks. * html/HTMLMediaElement.h: (WebCore::HTMLMediaElement::TrackGroup::TrackGroup): (TrackGroup): * platform/Language.cpp: (WebCore::canonicalLanguageIdentifier): New, create a canonicalized version of a language string. (WebCore::bestMatchingLanguage): New, return the language from the list that best matches the specified language. (WebCore::preferredLanguageFromList): New, return the language in the specified list that best matches the user's language preference. * platform/Language.h: * testing/Internals.cpp: (WebCore::Internals::setShouldDisplayTrackType): New, allow DRT to set the track type preference. (WebCore::Internals::shouldDisplayTrackType): New, allow DRT to read the track type preference. * testing/Internals.h: * testing/Internals.idl: LayoutTests: * media/track/track-language-preference-expected.txt: Added. * media/track/track-language-preference.html: Added. * media/track/track-prefer-captions-expected.txt: Added. * media/track/track-prefer-captions.html: Added. * platform/mac/Skipped: git-svn-id: http://svn.webkit.org/repository/webkit/trunk@106531 268f45cc-cd09-0410-ab3c-d52691b4dbfc --- LayoutTests/ChangeLog | 13 ++ .../track/track-language-preference-expected.txt | 32 +++ .../media/track/track-language-preference.html | 117 ++++++++++ .../media/track/track-prefer-captions-expected.txt | 25 +++ LayoutTests/media/track/track-prefer-captions.html | 87 ++++++++ Source/WebCore/ChangeLog | 38 ++++ Source/WebCore/html/HTMLMediaElement.cpp | 238 ++++++++++++--------- Source/WebCore/html/HTMLMediaElement.h | 26 ++- Source/WebCore/platform/Language.cpp | 58 +++++ Source/WebCore/platform/Language.h | 1 + Source/WebCore/testing/Internals.cpp | 49 +++++ Source/WebCore/testing/Internals.h | 3 + Source/WebCore/testing/Internals.idl | 4 + 13 files changed, 592 insertions(+), 99 deletions(-) create mode 100644 LayoutTests/media/track/track-language-preference-expected.txt create mode 100644 LayoutTests/media/track/track-language-preference.html create mode 100644 LayoutTests/media/track/track-prefer-captions-expected.txt create mode 100644 LayoutTests/media/track/track-prefer-captions.html diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog index caf31e3..cfc7adc 100644 --- a/LayoutTests/ChangeLog +++ b/LayoutTests/ChangeLog @@ -1,3 +1,16 @@ +2012-02-01 Eric Carlson + + Consider user's preferred language when choosing text tracks + https://bugs.webkit.org/show_bug.cgi?id=74121 + + Reviewed by Alexey Proskuryakov. + + * media/track/track-language-preference-expected.txt: Added. + * media/track/track-language-preference.html: Added. + * media/track/track-prefer-captions-expected.txt: Added. + * media/track/track-prefer-captions.html: Added. + * platform/mac/Skipped: + 2012-02-01 Shinya Kawanaka Select attribute of HTMLContentElement should be able be changed dynamically. diff --git a/LayoutTests/media/track/track-language-preference-expected.txt b/LayoutTests/media/track/track-language-preference-expected.txt new file mode 100644 index 0000000..a4eb724 --- /dev/null +++ b/LayoutTests/media/track/track-language-preference-expected.txt @@ -0,0 +1,32 @@ +Tests that the user's preferred languages are honored. + +**Set track preferences and user preferred languages +RUN(internals.setShouldDisplayTrackKind(document, 'Captions', true)) +RUN(internals.userPreferredLanguages = ['jp', 'es-ES', 'en', 'fr']) + +Test: a track language matches one of the user's preferred languages exactly. +- creating tracks for: [fr,en,jp]. +EVENT(load) +EXPECTED (track.readyState == '2') OK +EXPECTED (track.srclang == 'jp') OK + +Test: a track language without locale exactly matches one of the user's preferred languages. +- creating tracks for: [fr-CH,da]. +EVENT(load) +EXPECTED (track.readyState == '2') OK +EXPECTED (track.srclang == 'fr-CH') OK + +Test: a track language without locale matches one of the user's preferred languages without locale. +- creating tracks for: [fr,es-MX]. +EVENT(load) +EXPECTED (track.readyState == '2') OK +EXPECTED (track.srclang == 'es-MX') OK + +Test: no track language matches any of the user's preferred languages. +- creating tracks for: [fa,ru,no]. +EVENT(load) +EXPECTED (track.readyState == '2') OK +EXPECTED (track.srclang == 'fa') OK + +END OF TEST + diff --git a/LayoutTests/media/track/track-language-preference.html b/LayoutTests/media/track/track-language-preference.html new file mode 100644 index 0000000..1777343 --- /dev/null +++ b/LayoutTests/media/track/track-language-preference.html @@ -0,0 +1,117 @@ + + + + + + + + + + + +

Tests that the user's preferred languages are honored.

+ + + diff --git a/LayoutTests/media/track/track-prefer-captions-expected.txt b/LayoutTests/media/track/track-prefer-captions-expected.txt new file mode 100644 index 0000000..9a8a9e6 --- /dev/null +++ b/LayoutTests/media/track/track-prefer-captions-expected.txt @@ -0,0 +1,25 @@ +Tests that the user preferences for track kind are honored. + +**Set preferences so subtitles and descriptions load, but captions do not +RUN(internals.setShouldDisplayTrackKind(document, 'Subtitles', true)) +EXPECTED (internals.shouldDisplayTrackKind(document, 'Subtitles') == 'true') OK +RUN(internals.setShouldDisplayTrackKind(document, 'Captions', false)) +EXPECTED (internals.shouldDisplayTrackKind(document, 'Captions') == 'false') OK +RUN(internals.setShouldDisplayTrackKind(document, 'TextDescriptions', true)) +EXPECTED (internals.shouldDisplayTrackKind(document, 'TextDescriptions') == 'true') OK + +**Create track elements dynamically so they aren't processed by the media element until after preferences have been configured. +- creating 'subtitles' track. +- creating 'captions' track. +- creating 'descriptions' track. + +EVENT(load) +EXPECTED (track.readyState == '2') OK +EXPECTED (track.kind != 'captions') OK + +EVENT(load) +EXPECTED (track.readyState == '2') OK +EXPECTED (track.kind != 'captions') OK + +END OF TEST + diff --git a/LayoutTests/media/track/track-prefer-captions.html b/LayoutTests/media/track/track-prefer-captions.html new file mode 100644 index 0000000..ec012d4 --- /dev/null +++ b/LayoutTests/media/track/track-prefer-captions.html @@ -0,0 +1,87 @@ + + + + + + + + + + + +

Tests that the user preferences for track kind are honored.

+ + + diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog index 1a4116c..2a4ca69 100644 --- a/Source/WebCore/ChangeLog +++ b/Source/WebCore/ChangeLog @@ -1,3 +1,41 @@ +2012-02-01 Eric Carlson + + Consider user's preferred language when choosing text tracks + https://bugs.webkit.org/show_bug.cgi?id=74121 + + Reviewed by Alexey Proskuryakov. + + Tests: media/track/track-language-preference.html + media/track/track-prefer-captions.html + + * html/HTMLMediaElement.cpp: + (WebCore::HTMLMediaElement::loadTimerFired): configureTextTracks -> configureNewTextTracks. + (WebCore::HTMLMediaElement::textTracksAreReady): Add more comments. + (WebCore::HTMLMediaElement::textTrackModeChanged): Ditto. + (WebCore::HTMLMediaElement::showingTrackWithSameKind): Minor restructuring. + (WebCore::HTMLMediaElement::userIsInterestedInThisTrackKind): Renamed from userIsInterestedInThisTrack, + don't consider user's language preference. + (WebCore::HTMLMediaElement::configureTextTrackGroup): New, configure all tracks in a group, + considering user's kind and language preferences. + (WebCore::HTMLMediaElement::configureNewTextTracks): New, configure all newly added tracks. + * html/HTMLMediaElement.h: + (WebCore::HTMLMediaElement::TrackGroup::TrackGroup): + (TrackGroup): + + * platform/Language.cpp: + (WebCore::canonicalLanguageIdentifier): New, create a canonicalized version of a language string. + (WebCore::bestMatchingLanguage): New, return the language from the list that best matches the + specified language. + (WebCore::preferredLanguageFromList): New, return the language in the specified list that best + matches the user's language preference. + * platform/Language.h: + + * testing/Internals.cpp: + (WebCore::Internals::setShouldDisplayTrackType): New, allow DRT to set the track type preference. + (WebCore::Internals::shouldDisplayTrackType): New, allow DRT to read the track type preference. + * testing/Internals.h: + * testing/Internals.idl: + 2012-02-01 Hayato Ito Change class hierarycy so that ShadowRoot can inherit DocumentFragment. diff --git a/Source/WebCore/html/HTMLMediaElement.cpp b/Source/WebCore/html/HTMLMediaElement.cpp index 23ce7e4..e8bb788 100644 --- a/Source/WebCore/html/HTMLMediaElement.cpp +++ b/Source/WebCore/html/HTMLMediaElement.cpp @@ -51,6 +51,7 @@ #include "HTMLNames.h" #include "HTMLSourceElement.h" #include "HTMLVideoElement.h" +#include "Language.h" #include "Logging.h" #include "MediaController.h" #include "MediaControls.h" @@ -557,7 +558,7 @@ void HTMLMediaElement::loadTimerFired(Timer*) #if ENABLE(VIDEO_TRACK) if (m_pendingLoadFlags & TextTrackResource) - configureTextTracks(); + configureNewTextTracks(); #endif m_pendingLoadFlags = 0; @@ -965,6 +966,8 @@ void HTMLMediaElement::updateActiveTextTrackCues(float movieTime) bool HTMLMediaElement::textTracksAreReady() const { + // 4.8.10.12.1 Text track model + // ... // The text tracks of a media element are ready if all the text tracks whose mode was not // in the disabled state when the element's resource selection algorithm last started now // have a text track readiness state of loaded or failed to load. @@ -1000,7 +1003,7 @@ void HTMLMediaElement::textTrackModeChanged(TextTrack* track) if (trackElement->track() != track) continue; - // Mark this track as "configured" so configureTextTrack won't change the mode again. + // Mark this track as "configured" so configureNewTextTracks won't change the mode again. trackElement->setHasBeenConfigured(true); if (track->mode() != TextTrack::DISABLED && trackElement->readyState() == HTMLTrackElement::NONE) trackElement->scheduleLoad(); @@ -2240,15 +2243,13 @@ TextTrackList* HTMLMediaElement::textTracks() HTMLTrackElement* HTMLMediaElement::showingTrackWithSameKind(HTMLTrackElement* trackElement) const { - HTMLTrackElement* showingTrack = 0; - for (Node* node = firstChild(); node; node = node->nextSibling()) { if (trackElement == node) continue; if (!node->hasTagName(trackTag)) continue; - showingTrack = static_cast(node); + HTMLTrackElement* showingTrack = static_cast(node); if (showingTrack->kind() == trackElement->kind() && showingTrack->track()->mode() == TextTrack::SHOWING) return showingTrack; } @@ -2315,131 +2316,176 @@ bool HTMLMediaElement::userIsInterestedInThisLanguage(const String&) const return true; } -bool HTMLMediaElement::userIsInterestedInThisTrack(HTMLTrackElement* trackElement) const +bool HTMLMediaElement::userIsInterestedInThisTrackKind(String kind) const { - RefPtr textTrack = trackElement->track(); - if (!textTrack) - return false; - - String kind = textTrack->kind(); - if (!TextTrack::isValidKindKeyword(kind)) - return false; - // If ... the user has indicated an interest in having a track with this text track kind, text track language, ... Settings* settings = document()->settings(); if (!settings) return false; - if (kind == TextTrack::subtitlesKeyword() || kind == TextTrack::captionsKeyword()) { - if (kind == TextTrack::subtitlesKeyword() && !settings->shouldDisplaySubtitles()) - return false; - if (kind == TextTrack::captionsKeyword() && !settings->shouldDisplayCaptions()) - return false; - return userIsInterestedInThisLanguage(trackElement->srclang()); - } + if (kind == TextTrack::subtitlesKeyword()) + return settings->shouldDisplaySubtitles(); + if (kind == TextTrack::captionsKeyword()) + return settings->shouldDisplayCaptions(); + if (kind == TextTrack::descriptionsKeyword()) + return settings->shouldDisplayTextDescriptions(); - if (kind == TextTrack::descriptionsKeyword()) { - if (!settings->shouldDisplayTextDescriptions()) - return false; - return userIsInterestedInThisLanguage(trackElement->srclang()); - } - return false; } -void HTMLMediaElement::configureTextTrack(HTMLTrackElement* trackElement) +void HTMLMediaElement::configureTextTrackGroup(const TrackGroup& group) const { -#if !LOG_DISABLED - if (trackElement->hasTagName(trackTag)) { - KURL url = trackElement->getNonEmptyURLAttribute(srcAttr); - LOG(Media, "HTMLMediaElement::configureTextTrack - 'src' is %s", urlForLogging(url).utf8().data()); + ASSERT(group.tracks.size()); + + String bestMatchingLanguage; + if (group.hasSrcLang) { + Vector languages; + languages.reserveInitialCapacity(group.tracks.size()); + for (size_t i = 0; i < group.tracks.size(); ++i) { + String srcLanguage = group.tracks[i]->track()->language(); + if (srcLanguage.length()) + languages.append(srcLanguage); + } + bestMatchingLanguage = preferredLanguageFromList(languages); } -#endif - // 4.8.10.12.3 Sourcing out-of-band text tracks - - // When a text track corresponding to a track element is added to a media element's list of text tracks, - // the user agent must set the text track mode appropriately, as determined by the following conditions: - RefPtr textTrack = trackElement->track(); - if (!textTrack) - return; - - TextTrack::Mode mode = TextTrack::HIDDEN; - HTMLTrackElement* trackElementCurrentlyShowing = showingTrackWithSameKind(trackElement); - String kind = textTrack->kind(); - bool hideDefaultTrack = false; - - if (userIsInterestedInThisTrack(trackElement)) { - if (kind == TextTrack::subtitlesKeyword() || kind == TextTrack::captionsKeyword()) { - // * If the text track kind is subtitles or captions and the user has indicated an interest in having a + // First, find the track in the group that should be enabled (if any). + HTMLTrackElement* trackElementToEnable = 0; + HTMLTrackElement* defaultTrack = 0; + HTMLTrackElement* fallbackTrack = 0; + for (size_t i = 0; !trackElementToEnable && i < group.tracks.size(); ++i) { + HTMLTrackElement* trackElement = group.tracks[i]; + RefPtr textTrack = trackElement->track(); + + if (userIsInterestedInThisTrackKind(textTrack->kind())) { + // * If the text track kind is { [subtitles or captions] [descriptions] } and the user has indicated an interest in having a // track with this text track kind, text track language, and text track label enabled, and there is no // other text track in the media element's list of text tracks with a text track kind of either subtitles // or captions whose text track mode is showing - hideDefaultTrack = trackElementCurrentlyShowing && trackElementCurrentlyShowing->track()->showingByDefault(); - if (!trackElementCurrentlyShowing || hideDefaultTrack) { - // Let the text track mode be showing. - // If there is a text track in the media element's list of text tracks whose text track mode is showing - // by default, the user agent must furthermore change that text track's text track mode to hidden. - mode = TextTrack::SHOWING; - } - } else if (kind == TextTrack::descriptionsKeyword()) { - // * If the text track kind is descriptions and the user has indicated an interest in having text - // descriptions with this text track language and text track label enabled, and there is no other text - // track in the media element's list of text tracks with a text track kind of descriptions whose text - // track mode is showing - hideDefaultTrack = trackElementCurrentlyShowing && trackElementCurrentlyShowing->track()->showingByDefault(); - if (!trackElementCurrentlyShowing || hideDefaultTrack) { - // Let the text track mode be showing. - // If there is a text track in the media element's list of text tracks whose text track mode is showing - // by default, the user agent must furthermore change that text track's text track mode to hidden. - mode = TextTrack::SHOWING; - } - } else if (kind == TextTrack::chaptersKeyword()) { + // ... // * If the text track kind is chapters and the text track language is one that the user agent has reason // to believe is appropriate for the user, and there is no other text track in the media element's list of // text tracks with a text track kind of chapters whose text track mode is showing // Let the text track mode be showing. - if (!trackElementCurrentlyShowing) - mode = TextTrack::SHOWING; + if (bestMatchingLanguage.length()) { + if (textTrack->language() == bestMatchingLanguage) + trackElementToEnable = trackElement; + } else if (trackElement->isDefault()) { + // The user is interested in this type of track, but their language preference doesn't match any track so we will + // enable the 'default' track. + defaultTrack = trackElement; + } + + // Remember the first track that doesn't match language or have 'default' to potentially use as fallback. + if (!fallbackTrack) + fallbackTrack = trackElement; + } else if (!group.visibleTrack && !defaultTrack && trackElement->isDefault()) { + // * If the track element has a default attribute specified, and there is no other text track in the media + // element's list of text tracks whose text track mode is showing or showing by default + // Let the text track mode be showing by default. + defaultTrack = trackElement; } - } else if (!trackElementCurrentlyShowing && trackElement->isDefault()) { - // * If the track element has a default attribute specified, and there is no other text track in the media - // element's list of text tracks whose text track mode is showing or showing by default - // Let the text track mode be showing by default. - mode = TextTrack::SHOWING; - textTrack->setShowingByDefault(false); - } else { - // Otherwise - // Let the text track mode be disabled. - mode = TextTrack::DISABLED; } - ExceptionCode unusedException; - if (hideDefaultTrack) { - trackElementCurrentlyShowing->track()->setMode(TextTrack::HIDDEN, unusedException); - trackElementCurrentlyShowing->track()->setShowingByDefault(false); + if (!trackElementToEnable && defaultTrack) + trackElementToEnable = defaultTrack; + + // If no track matches the user's preferred language and non was marked 'default', enable the first track + // because the user has explicitly stated a preference for this kind of track. + if (!trackElementToEnable && fallbackTrack) + trackElementToEnable = fallbackTrack; + + for (size_t i = 0; i < group.tracks.size(); ++i) { + HTMLTrackElement* trackElement = group.tracks[i]; + RefPtr textTrack = trackElement->track(); + ExceptionCode unusedException; + + if (trackElementToEnable == trackElement) { + textTrack->setMode(TextTrack::SHOWING, unusedException); + if (defaultTrack == trackElement) + textTrack->setShowingByDefault(true); + } else { + if (textTrack->showingByDefault()) { + // If there is a text track in the media element's list of text tracks whose text track + // mode is showing by default, the user agent must furthermore change that text track's + // text track mode to hidden. + textTrack->setShowingByDefault(false); + textTrack->setMode(TextTrack::HIDDEN, unusedException); + } else + textTrack->setMode(TextTrack::DISABLED, unusedException); + } } - textTrack->setMode(mode, unusedException); + if (trackElementToEnable && group.defaultTrack && group.defaultTrack != trackElementToEnable) { + RefPtr textTrack = group.defaultTrack->track(); + if (textTrack && textTrack->showingByDefault()) { + ExceptionCode unusedException; + textTrack->setShowingByDefault(false); + textTrack->setMode(TextTrack::HIDDEN, unusedException); + } + } } - -void HTMLMediaElement::configureTextTracks() + +void HTMLMediaElement::configureNewTextTracks() { + TrackGroup captionAndSubtitleTracks(TrackGroup::CaptionsAndSubtitles); + TrackGroup descriptionTracks(TrackGroup::Description); + TrackGroup chapterTracks(TrackGroup::Chapter); + TrackGroup metadataTracks(TrackGroup::Metadata); + TrackGroup otherTracks(TrackGroup::Other); + for (Node* node = firstChild(); node; node = node->nextSibling()) { if (!node->hasTagName(trackTag)) continue; + HTMLTrackElement* trackElement = static_cast(node); + RefPtr textTrack = trackElement->track(); + if (!textTrack) + continue; + + String kind = textTrack->kind(); + TrackGroup* currentGroup; + if (kind == TextTrack::subtitlesKeyword() || kind == TextTrack::captionsKeyword()) + currentGroup = &captionAndSubtitleTracks; + else if (kind == TextTrack::descriptionsKeyword()) + currentGroup = &descriptionTracks; + else if (kind == TextTrack::chaptersKeyword()) + currentGroup = &chapterTracks; + else if (kind == TextTrack::metadataKeyword()) + currentGroup = &metadataTracks; + else + currentGroup = &otherTracks; + + if (!currentGroup->visibleTrack && textTrack->mode() == TextTrack::SHOWING) + currentGroup->visibleTrack = trackElement; + if (!currentGroup->defaultTrack && trackElement->isDefault()) + currentGroup->defaultTrack = trackElement; + + // Do not add this track to the group if it has already been automatically configured + // as we only want to call configureTextTrack once per track so that adding another + // track after the initial configuration doesn't reconfigure every track - only those + // that should be changed by the new addition. For example all metadata tracks are + // disabled by default, and we don't want a track that has been enabled by script + // to be disabled automatically when a new metadata track is added later. + if (trackElement->hasBeenConfigured()) + continue; - // Only call configureTextTrack once per track so that adding another track after - // the initial configuration doesn't reconfigure every track, only those that should - // be changed by the new addition. For example all metadata tracks are disabled by - // default, and we don't want a track that has been enabled by script to be disabled - // automatically when a new track element is added later. - if (!trackElement->hasBeenConfigured()) - configureTextTrack(trackElement); + if (textTrack->language().length()) + currentGroup->hasSrcLang = true; + currentGroup->tracks.append(trackElement); } + + if (captionAndSubtitleTracks.tracks.size()) + configureTextTrackGroup(captionAndSubtitleTracks); + if (descriptionTracks.tracks.size()) + configureTextTrackGroup(descriptionTracks); + if (chapterTracks.tracks.size()) + configureTextTrackGroup(chapterTracks); + if (metadataTracks.tracks.size()) + configureTextTrackGroup(metadataTracks); + if (otherTracks.tracks.size()) + configureTextTrackGroup(otherTracks); } - #endif bool HTMLMediaElement::havePotentialSourceChild() diff --git a/Source/WebCore/html/HTMLMediaElement.h b/Source/WebCore/html/HTMLMediaElement.h index 59143a6..98fdf5a 100644 --- a/Source/WebCore/html/HTMLMediaElement.h +++ b/Source/WebCore/html/HTMLMediaElement.h @@ -207,8 +207,29 @@ public: virtual void trackWasAdded(HTMLTrackElement*); virtual void trackWasRemoved(HTMLTrackElement*); - void configureTextTrack(HTMLTrackElement*); - void configureTextTracks(); + struct TrackGroup { + enum GroupKind { CaptionsAndSubtitles, Description, Chapter, Metadata, Other }; + + TrackGroup(GroupKind kind) + : visibleTrack(0) + , defaultTrack(0) + , kind(kind) + , hasSrcLang(false) + { + } + + Vector tracks; + HTMLTrackElement* visibleTrack; + HTMLTrackElement* defaultTrack; + GroupKind kind; + bool hasSrcLang; + }; + + void configureTextTrackGroupForLanguage(const TrackGroup&) const; + void configureNewTextTracks(); + void configureTextTrackGroup(const TrackGroup&) const; + + bool userIsInterestedInThisTrackKind(String) const; bool textTracksAreReady() const; void configureTextTrackDisplay(); @@ -401,7 +422,6 @@ private: #if ENABLE(VIDEO_TRACK) void updateActiveTextTrackCues(float); bool userIsInterestedInThisLanguage(const String&) const; - bool userIsInterestedInThisTrack(HTMLTrackElement*) const; HTMLTrackElement* showingTrackWithSameKind(HTMLTrackElement*) const; bool ignoreTrackDisplayUpdateRequests() const { return m_ignoreTrackDisplayUpdate > 0; } diff --git a/Source/WebCore/platform/Language.cpp b/Source/WebCore/platform/Language.cpp index 03de916..47f09f6 100644 --- a/Source/WebCore/platform/Language.cpp +++ b/Source/WebCore/platform/Language.cpp @@ -85,4 +85,62 @@ Vector userPreferredLanguages() return platformUserPreferredLanguages(); } +static String canonicalLanguageIdentifier(const String& languageCode) +{ + String lowercaseLanguageCode = languageCode.lower(); + + if (lowercaseLanguageCode.length() >= 3 && lowercaseLanguageCode[2] == '_') + lowercaseLanguageCode.replace(2, 1, "-"); + + return lowercaseLanguageCode; +} + +static String bestMatchingLanguage(const String& language, const Vector& languageList) +{ + bool canMatchLanguageOnly = (language.length() == 2 || (language.length() >= 3 && language[2] == '-')); + String languageWithoutLocaleMatch; + String languageMatchButNotLocale; + + for (size_t i = 0; i < languageList.size(); ++i) { + String canonicalizedLanguageFromList = canonicalLanguageIdentifier(languageList[i]); + + if (language == canonicalizedLanguageFromList) + return languageList[i]; + + if (canMatchLanguageOnly && canonicalizedLanguageFromList.length() >= 2) { + if (language[0] == canonicalizedLanguageFromList[0] && language[1] == canonicalizedLanguageFromList[1]) { + if (!languageWithoutLocaleMatch.length() && canonicalizedLanguageFromList.length() == 2) + languageWithoutLocaleMatch = languageList[i]; + if (!languageMatchButNotLocale.length() && canonicalizedLanguageFromList.length() >= 3) + languageMatchButNotLocale = languageList[i]; + } + } + } + + // If we have both a language-only match and a languge-but-not-locale match, return the + // languge-only match as is considered a "better" match. For example, if the list + // provided has both "en-GB" and "en" and the user prefers "en-US" we will return "en". + if (languageWithoutLocaleMatch.length()) + return languageWithoutLocaleMatch; + + if (languageMatchButNotLocale.length()) + return languageMatchButNotLocale; + + return emptyString(); +} + +String preferredLanguageFromList(const Vector& languageList) +{ + Vector preferredLanguages = userPreferredLanguages(); + + for (size_t i = 0; i < preferredLanguages.size(); ++i) { + String bestMatch = bestMatchingLanguage(canonicalLanguageIdentifier(preferredLanguages[i]), languageList); + + if (bestMatch.length()) + return bestMatch; + } + + return emptyString(); +} + } diff --git a/Source/WebCore/platform/Language.h b/Source/WebCore/platform/Language.h index b148be0..411615c 100644 --- a/Source/WebCore/platform/Language.h +++ b/Source/WebCore/platform/Language.h @@ -34,6 +34,7 @@ namespace WebCore { String defaultLanguage(); Vector userPreferredLanguages(); void overrideUserPreferredLanguages(const Vector&); +String preferredLanguageFromList(const Vector&); // The observer function will be called when system language changes. typedef void (*LanguageChangeObserverFunction)(void* context); diff --git a/Source/WebCore/testing/Internals.cpp b/Source/WebCore/testing/Internals.cpp index 1709a9f..16447fc 100644 --- a/Source/WebCore/testing/Internals.cpp +++ b/Source/WebCore/testing/Internals.cpp @@ -491,4 +491,53 @@ void Internals::setUserPreferredLanguages(const Vector& languages) WebCore::overrideUserPreferredLanguages(languages); } +void Internals::setShouldDisplayTrackKind(Document* document, const String& kind, bool enabled, ExceptionCode& ec) +{ + if (!document || !document->frame() || !document->frame()->settings()) { + ec = INVALID_ACCESS_ERR; + return; + } + +#if ENABLE(VIDEO_TRACK) + Settings* settings = document->frame()->settings(); + + if (equalIgnoringCase(kind, "Subtitles")) + settings->setShouldDisplaySubtitles(enabled); + else if (equalIgnoringCase(kind, "Captions")) + settings->setShouldDisplayCaptions(enabled); + else if (equalIgnoringCase(kind, "TextDescriptions")) + settings->setShouldDisplayTextDescriptions(enabled); + else + ec = SYNTAX_ERR; +#else + UNUSED_PARAM(kind); + UNUSED_PARAM(enabled); +#endif +} + +bool Internals::shouldDisplayTrackKind(Document* document, const String& kind, ExceptionCode& ec) +{ + if (!document || !document->frame() || !document->frame()->settings()) { + ec = INVALID_ACCESS_ERR; + return false; + } + +#if ENABLE(VIDEO_TRACK) + Settings* settings = document->frame()->settings(); + + if (equalIgnoringCase(kind, "Subtitles")) + return settings->shouldDisplaySubtitles(); + if (equalIgnoringCase(kind, "Captions")) + return settings->shouldDisplayCaptions(); + if (equalIgnoringCase(kind, "TextDescriptions")) + return settings->shouldDisplayTextDescriptions(); + + ec = SYNTAX_ERR; + return false; +#else + UNUSED_PARAM(kind); + return false; +#endif +} + } diff --git a/Source/WebCore/testing/Internals.h b/Source/WebCore/testing/Internals.h index f1d2fb2..b872531 100644 --- a/Source/WebCore/testing/Internals.h +++ b/Source/WebCore/testing/Internals.h @@ -102,6 +102,9 @@ public: Vector userPreferredLanguages() const; void setUserPreferredLanguages(const Vector&); + void setShouldDisplayTrackKind(Document*, const String& kind, bool, ExceptionCode&); + bool shouldDisplayTrackKind(Document*, const String& kind, ExceptionCode&); + static const char* internalsId; InternalSettings* settings() const { return m_settings.get(); } diff --git a/Source/WebCore/testing/Internals.idl b/Source/WebCore/testing/Internals.idl index 145aa6e..da081f5 100644 --- a/Source/WebCore/testing/Internals.idl +++ b/Source/WebCore/testing/Internals.idl @@ -73,6 +73,10 @@ module window { long lastSpellCheckRequestSequence(in Document document) raises (DOMException); long lastSpellCheckProcessedSequence(in Document document) raises (DOMException); +#if defined(ENABLE_VIDEO_TRACK) && ENABLE_VIDEO_TRACK + void setShouldDisplayTrackKind(in Document document, in DOMString kind, in boolean enabled) raises (DOMException); + boolean shouldDisplayTrackKind(in Document document, in DOMString trackKind) raises (DOMException); +#endif attribute [Custom] Array userPreferredLanguages; readonly attribute InternalSettings settings; -- 2.7.4