Add UI to customization caption styling
Allow Chrome users on platform that do not have system caption
styling to provide a default styling for WebVTT captions displayed
by Blink. This should affect Chrome OS and Linux as Windows, macOS
and Android have system settings.
Design doc: https://docs.google.com/document/d/1wgKMbvP8nJkUKXkwnh5iEajSa4GHxDURL8kHIyHEO4s/edit?hl=en#
Bug: 976966
Change-Id: I41282753305b81f76e6b3f565516160cd63d69f9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1656714
Reviewed-by: Avi Drissman <avi@chromium.org>
Reviewed-by: Mounir Lamouri <mlamouri@chromium.org>
Reviewed-by: Esmael El-Moslimany <aee@chromium.org>
Commit-Queue: Evan Liu <evliu@google.com>
Cr-Commit-Position: refs/heads/master@{#672706}
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index 92654cb7..e696de8 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -162,6 +162,78 @@
</if>
<!-- Accessibility Page -->
+ <message name="IDS_SETTINGS_CAPTIONS" desc="Name of the settings page which displays caption preferences.">
+ Captions
+ </message>
+ <message name="IDS_SETTINGS_CAPTIONS_TEXT_SIZE" desc="Name of the settings page which displays caption text size preferences.">
+ Text size
+ </message>
+ <message name="IDS_SETTINGS_CAPTIONS_TEXT_FONT" desc="Name of the settings page which displays caption text font preferences.">
+ Text font
+ </message>
+ <message name="IDS_SETTINGS_CAPTIONS_TEXT_COLOR" desc="Name of the settings page which displays caption text color preferences.">
+ Text color
+ </message>
+ <message name="IDS_SETTINGS_CAPTIONS_TEXT_OPACITY" desc="Name of the settings page which displays caption text opacity preferences.">
+ Text opacity
+ </message>
+ <message name="IDS_SETTINGS_CAPTIONS_BACKGROUND_OPACITY" desc="Name of the settings page which displays caption background opacity preferences.">
+ Background opacity
+ </message>
+ <message name="IDS_SETTINGS_CAPTIONS_OPACITY_MIN" desc="Value of the minimum captions text opacity setting.">
+ 0
+ </message>
+ <message name="IDS_SETTINGS_CAPTIONS_OPACITY_MAX" desc="Value of the maximum captions text opacity setting.">
+ 100
+ </message>
+ <message name="IDS_SETTINGS_CAPTIONS_TEXT_SHADOW" desc="Name of the settings page which displays caption text shadow preferences.">
+ Text shadow
+ </message>
+ <message name="IDS_SETTINGS_CAPTIONS_TEXT_SHADOW_NONE" desc="Name of the None option for the caption text shadow.">
+ None
+ </message>
+ <message name="IDS_SETTINGS_CAPTIONS_TEXT_SHADOW_RAISED" desc="Name of the Raised option for the caption text shadow.">
+ Raised
+ </message>
+ <message name="IDS_SETTINGS_CAPTIONS_TEXT_SHADOW_DEPRESSED" desc="Name of the Depressed option for the caption text shadow.">
+ Depressed
+ </message>
+ <message name="IDS_SETTINGS_CAPTIONS_TEXT_SHADOW_UNIFORM" desc="Name of the Uniform option for the caption text shadow.">
+ Uniform
+ </message>
+ <message name="IDS_SETTINGS_CAPTIONS_TEXT_SHADOW_DROP_SHADOW" desc="Name of the Drop shadow option for the caption text shadow.">
+ Drop shadow
+ </message>
+ <message name="IDS_SETTINGS_CAPTIONS_BACKGROUND_COLOR" desc="Name of the settings page which displays caption background color preferences.">
+ Background color
+ </message>
+ <message name="IDS_SETTINGS_CAPTIONS_COLOR_BLACK" desc="Name of the Black color for the caption text or background.">
+ Black
+ </message>
+ <message name="IDS_SETTINGS_CAPTIONS_COLOR_WHITE" desc="Name of the White color for the caption text or background.">
+ White
+ </message>
+ <message name="IDS_SETTINGS_CAPTIONS_COLOR_RED" desc="Name of the Red color for the caption text or background.">
+ Red
+ </message>
+ <message name="IDS_SETTINGS_CAPTIONS_COLOR_GREEN" desc="Name of the Green color for the caption text or background.">
+ Green
+ </message>
+ <message name="IDS_SETTINGS_CAPTIONS_COLOR_BLUE" desc="Name of the Blue color for the caption text or background.">
+ Blue
+ </message>
+ <message name="IDS_SETTINGS_CAPTIONS_COLOR_YELLOW" desc="Name of the Yellow color for the caption text or background.">
+ Yellow
+ </message>
+ <message name="IDS_SETTINGS_CAPTIONS_COLOR_CYAN" desc="Name of the Cyan color for the caption text or background.">
+ Cyan
+ </message>
+ <message name="IDS_SETTINGS_CAPTIONS_COLOR_MAGENTA" desc="Name of the Magenta color for the caption text or background.">
+ Magenta
+ </message>
+ <message name="IDS_SETTINGS_CAPTIONS_DEFAULT_SETTING" desc="Name of the default setting for the caption text.">
+ Default
+ </message>
<message name="IDS_SETTINGS_ACCESSIBILITY" desc="Name of the settings page which displays accessibility preferences.">
Accessibility
</message>
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_CAPTIONS.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_CAPTIONS.png.sha1
new file mode 100644
index 0000000..4ba1991
--- /dev/null
+++ b/chrome/app/settings_strings_grdp/IDS_SETTINGS_CAPTIONS.png.sha1
@@ -0,0 +1 @@
+3e05aa8562cd7a68d00d313431aca4dfe7effc5e
\ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 2ca9d3aa..b0b8605 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -3840,6 +3840,20 @@
]
}
+ if (is_mac) {
+ sources += [
+ "accessibility/caption_settings_dialog.h",
+ "accessibility/caption_settings_dialog_mac.mm",
+ ]
+ }
+
+ if (is_win) {
+ sources += [
+ "accessibility/caption_settings_dialog.h",
+ "accessibility/caption_settings_dialog_win.cc",
+ ]
+ }
+
if (is_win || is_mac || is_desktop_linux) {
sources += [
"browser_switcher/alternative_browser_driver.h",
diff --git a/chrome/browser/accessibility/caption_settings_dialog.h b/chrome/browser/accessibility/caption_settings_dialog.h
new file mode 100644
index 0000000..d6f08fa
--- /dev/null
+++ b/chrome/browser/accessibility/caption_settings_dialog.h
@@ -0,0 +1,25 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_ACCESSIBILITY_CAPTION_SETTINGS_DIALOG_H_
+#define CHROME_BROWSER_ACCESSIBILITY_CAPTION_SETTINGS_DIALOG_H_
+
+#include "base/macros.h"
+
+namespace captions {
+
+// An abstraction of a caption settings dialog. This is used for the captions
+// sub-section of Settings.
+class CaptionSettingsDialog {
+ public:
+ // Displays the native captions manager dialog.
+ static void ShowCaptionSettingsDialog();
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(CaptionSettingsDialog);
+};
+
+} // namespace captions
+
+#endif // CHROME_BROWSER_ACCESSIBILITY_CAPTION_SETTINGS_DIALOG_H_
diff --git a/chrome/browser/accessibility/caption_settings_dialog_mac.mm b/chrome/browser/accessibility/caption_settings_dialog_mac.mm
new file mode 100644
index 0000000..ae9c4aa
--- /dev/null
+++ b/chrome/browser/accessibility/caption_settings_dialog_mac.mm
@@ -0,0 +1,20 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/accessibility/caption_settings_dialog.h"
+
+#import <AppKit/AppKit.h>
+
+namespace captions {
+
+static NSString* kCaptionSettingsUrlString =
+ @"x-apple.systempreferences:com.apple.preference.universalaccess?"
+ @"Captioning";
+
+void CaptionSettingsDialog::ShowCaptionSettingsDialog() {
+ [[NSWorkspace sharedWorkspace]
+ openURL:[NSURL URLWithString:kCaptionSettingsUrlString]];
+}
+
+} // namespace captions
diff --git a/chrome/browser/accessibility/caption_settings_dialog_win.cc b/chrome/browser/accessibility/caption_settings_dialog_win.cc
new file mode 100644
index 0000000..aef787a
--- /dev/null
+++ b/chrome/browser/accessibility/caption_settings_dialog_win.cc
@@ -0,0 +1,34 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/accessibility/caption_settings_dialog.h"
+
+#include <windows.h>
+#include <shellapi.h>
+
+#include "base/bind.h"
+#include "base/task/post_task.h"
+#include "base/win/windows_version.h"
+
+namespace {
+
+// A helper callback that opens the caption settings dialog.
+void CaptionSettingsDialogCallback() {
+ if (base::win::GetVersion() >= base::win::Version::WIN10) {
+ ShellExecute(NULL, L"open", L"ms-settings:easeofaccess-closedcaptioning",
+ NULL, NULL, SW_SHOWNORMAL);
+ }
+}
+
+} // namespace
+
+namespace captions {
+
+void CaptionSettingsDialog::ShowCaptionSettingsDialog() {
+ base::PostTaskWithTraits(
+ FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_BLOCKING},
+ base::BindOnce(CaptionSettingsDialogCallback));
+}
+
+} // namespace captions
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 5c2288a..0faee1f7 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -3154,19 +3154,25 @@
style.text_size = prefs->GetString(prefs::kAccessibilityCaptionsTextSize);
style.font_family = prefs->GetString(prefs::kAccessibilityCaptionsTextFont);
- style.text_color = base::StringPrintf(
- "rgba(%s,%s)",
- prefs->GetString(prefs::kAccessibilityCaptionsTextColor).c_str(),
- base::NumberToString(
- prefs->GetInteger(prefs::kAccessibilityCaptionsTextOpacity) / 100.0)
- .c_str());
- style.background_color = base::StringPrintf(
- "rgba(%s,%s)",
- prefs->GetString(prefs::kAccessibilityCaptionsBackgroundColor).c_str(),
- base::NumberToString(
- prefs->GetInteger(prefs::kAccessibilityCaptionsBackgroundOpacity) /
- 100.0)
- .c_str());
+ if (!prefs->GetString(prefs::kAccessibilityCaptionsTextColor).empty()) {
+ style.text_color = base::StringPrintf(
+ "rgba(%s,%s)",
+ prefs->GetString(prefs::kAccessibilityCaptionsTextColor).c_str(),
+ base::NumberToString(
+ prefs->GetInteger(prefs::kAccessibilityCaptionsTextOpacity) / 100.0)
+ .c_str());
+ }
+
+ if (!prefs->GetString(prefs::kAccessibilityCaptionsBackgroundColor).empty()) {
+ style.background_color = base::StringPrintf(
+ "rgba(%s,%s)",
+ prefs->GetString(prefs::kAccessibilityCaptionsBackgroundColor).c_str(),
+ base::NumberToString(
+ prefs->GetInteger(prefs::kAccessibilityCaptionsBackgroundOpacity) /
+ 100.0)
+ .c_str());
+ }
+
style.text_shadow = prefs->GetString(prefs::kAccessibilityCaptionsTextShadow);
return style;
diff --git a/chrome/browser/resources/settings/a11y_page/BUILD.gn b/chrome/browser/resources/settings/a11y_page/BUILD.gn
index 0be94d4..cb0f25da 100644
--- a/chrome/browser/resources/settings/a11y_page/BUILD.gn
+++ b/chrome/browser/resources/settings/a11y_page/BUILD.gn
@@ -7,6 +7,8 @@
js_type_check("closure_compile") {
deps = [
":a11y_page",
+ ":captions_browser_proxy",
+ ":captions_subpage",
]
if (is_chromeos) {
@@ -19,6 +21,16 @@
}
}
+js_library("captions_subpage") {
+ deps = [
+ "../appearance_page:fonts_browser_proxy",
+ "../controls:settings_dropdown_menu",
+ "//ui/webui/resources/cr_elements/cr_slider:cr_slider",
+ "//ui/webui/resources/js:i18n_behavior",
+ "//ui/webui/resources/js:web_ui_listener_behavior",
+ ]
+}
+
js_library("a11y_page") {
deps = [
"..:route",
@@ -61,3 +73,9 @@
js_library("externs") {
}
+
+js_library("captions_browser_proxy") {
+ deps = [
+ "//ui/webui/resources/js:cr",
+ ]
+}
diff --git a/chrome/browser/resources/settings/a11y_page/a11y_page.html b/chrome/browser/resources/settings/a11y_page/a11y_page.html
index c13d604..a4acf13 100644
--- a/chrome/browser/resources/settings/a11y_page/a11y_page.html
+++ b/chrome/browser/resources/settings/a11y_page/a11y_page.html
@@ -1,5 +1,7 @@
<link rel="import" href="chrome://resources/html/polymer.html">
+<link rel="import" href="captions_browser_proxy.html">
+<link rel="import" href="captions_subpage.html">
<link rel="import" href="chrome://resources/cr_elements/cr_link_row/cr_link_row.html">
<link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html">
<link rel="import" href="../i18n_setup.html">
@@ -17,76 +19,100 @@
<dom-module id="settings-a11y-page">
<template>
<style include="settings-shared"></style>
-<if expr="chromeos">
- <template is="dom-if" if="[[pageVisibility.webstoreLink]]">
- <settings-animated-pages id="pages" current-route="{{currentRoute}}"
- section="a11y" focus-config="[[focusConfig_]]">
+ <settings-animated-pages id="pages" current-route="{{currentRoute}}"
+ section="a11y" focus-config="[[focusConfig_]]">
+ <if expr="not chromeos">
<div route-path="default">
- <settings-toggle-button
- id="a11yImageLabels"
- hidden$="[[!showAccessibilityLabelsSetting_]]"
- pref="{{prefs.settings.a11y.enable_accessibility_image_labels}}"
- on-change="onToggleAccessibilityImageLabels_"
- label="$i18n{accessibleImageLabelsTitle}"
- sub-label="$i18n{accessibleImageLabelsSubtitle}">
- </settings-toggle-button>
- <settings-toggle-button id="optionsInMenuToggle"
- label="$i18n{optionsInMenuLabel}"
- pref="{{prefs.settings.a11y.enable_menu}}">
- </settings-toggle-button>
- <cr-link-row class="hr" id="subpage-trigger"
- label="$i18n{manageAccessibilityFeatures}"
- on-click="onManageAccessibilityFeaturesTap_"
- sub-label="$i18n{moreFeaturesLinkDescription}">
- </cr-link-row>
+ <template is="dom-if" if="[[showCaptionSettings_]]">
+ <cr-link-row class="hr" id="captions" label="$i18n{captionsTitle}"
+ on-click="onTapCaptions_">
+ </cr-link-row>
+ </template>
+ <if expr="not chromeos">
+ <settings-toggle-button id="a11yImageLabels"
+ hidden$="[[!showAccessibilityLabelsSetting_]]"
+ pref="{{prefs.settings.a11y.enable_accessibility_image_labels}}"
+ on-change="onToggleAccessibilityImageLabels_"
+ label="$i18n{accessibleImageLabelsTitle}"
+ sub-label="$i18n{accessibleImageLabelsSubtitle}">
+ </settings-toggle-button>
+ <cr-link-row class="hr" label="$i18n{moreFeaturesLink}"
+ on-click="onMoreFeaturesLinkClick_"
+ sub-label="$i18n{a11yWebStore}" external></cr-link-row>
+ </if>
</div>
-
- <template is="dom-if" route-path="/manageAccessibility">
- <settings-subpage
- associated-control="[[$$('#subpage-trigger')]]"
- page-title="$i18n{manageAccessibilityFeatures}">
- <settings-manage-a11y-page prefs="{{prefs}}">
- </settings-manage-a11y-page>
- </settings-subpage>
- </template>
- <template is="dom-if" route-path="/manageAccessibility/tts">
- <settings-subpage
- associated-control="[[$$('#subpage-trigger')]]"
- page-title="$i18n{manageTtsSettings}">
- <settings-tts-subpage prefs="{{prefs}}">
- </settings-tts-subpage>
- </settings-subpage>
- </template>
- <template is="dom-if" if="[[showExperimentalSwitchAccess_]]">
- <template is="dom-if" route-path="/manageAccessibility/switchAccess">
+ </if>
+ <if expr="chromeos">
+ <template is="dom-if" if="[[pageVisibility.webstoreLink]]">
+ <div route-path="default">
+ <template is="dom-if" if="[[showCaptionSettings_]]">
+ <cr-link-row class="hr" id="captions"
+ label="$i18n{captionsTitle}"
+ on-click="onTapCaptions_">
+ </cr-link-row>
+ </template>
+ <settings-toggle-button id="a11yImageLabels"
+ hidden$="[[!showAccessibilityLabelsSetting_]]"
+ pref="{{prefs.settings.a11y.enable_accessibility_image_labels}}"
+ on-change="onToggleAccessibilityImageLabels_"
+ label="$i18n{accessibleImageLabelsTitle}"
+ sub-label="$i18n{accessibleImageLabelsSubtitle}">
+ </settings-toggle-button>
+ <settings-toggle-button id="optionsInMenuToggle"
+ label="$i18n{optionsInMenuLabel}"
+ pref="{{prefs.settings.a11y.enable_menu}}">
+ </settings-toggle-button>
+ <cr-link-row class="hr" id="subpage-trigger"
+ label="$i18n{manageAccessibilityFeatures}"
+ on-click="onManageAccessibilityFeaturesTap_"
+ sub-label="$i18n{moreFeaturesLinkDescription}">
+ </cr-link-row>
+ </div>
+ <template is="dom-if" route-path="/manageAccessibility">
<settings-subpage associated-control="[[$$('#subpage-trigger')]]"
- page-title="$i18n{manageSwitchAccessSettings}">
- <settings-switch-access-subpage prefs="{{prefs.settings.a11y}}">
- </settings-switch-access-subpage>
+ page-title="$i18n{manageAccessibilityFeatures}">
+ <settings-manage-a11y-page prefs="{{prefs}}">
+ </settings-manage-a11y-page>
+ </settings-subpage>
+ </template>
+ <template is="dom-if" route-path="/manageAccessibility/tts">
+ <settings-subpage
+ associated-control="[[$$('#subpage-trigger')]]"
+ page-title="$i18n{manageTtsSettings}">
+ <settings-tts-subpage prefs="{{prefs}}">
+ </settings-tts-subpage>
+ </settings-subpage>
+ </template>
+ <template is="dom-if" if="[[showExperimentalSwitchAccess_]]">
+ <template is="dom-if"
+ route-path="/manageAccessibility/switchAccess">
+ <settings-subpage associated-control="[[$$('#subpage-trigger')]]"
+ page-title="$i18n{manageSwitchAccessSettings}">
+ <settings-switch-access-subpage prefs="{{prefs.settings.a11y}}">
+ </settings-switch-access-subpage>
+ </settings-subpage>
+ </template>
+ </template>
+ </template>
+ <cr-link-row class="hr"
+ label="$i18n{moreFeaturesLink}"
+ on-click="onMoreFeaturesLinkClick_"
+ sub-label="$i18n{a11yWebStore}"
+ hidden="[[pageVisibility.webstoreLink]]" external></cr-link-row>
+ </if>
+
+ <if expr="chromeos or is_linux or is_win">
+ <template is="dom-if" if="[[showCaptionSettings_]]">
+ <template is="dom-if" route-path="/captions">
+ <settings-subpage
+ associated-control="[[$$('#captions')]]"
+ page-title="$i18n{captionsTitle}">
+ <settings-captions prefs="{{prefs}}"></settings-captions>
</settings-subpage>
</template>
</template>
- </settings-animated-pages>
- </template>
- <cr-link-row class="hr" label="$i18n{moreFeaturesLink}"
- on-click="onMoreFeaturesLinkClick_" sub-label="$i18n{a11yWebStore}"
- hidden="[[pageVisibility.webstoreLink]]"
- external></cr-link-row>
-</if>
-
-<if expr="not chromeos">
- <settings-toggle-button
- id="a11yImageLabels"
- hidden$="[[!showAccessibilityLabelsSetting_]]"
- pref="{{prefs.settings.a11y.enable_accessibility_image_labels}}"
- on-change="onToggleAccessibilityImageLabels_"
- label="$i18n{accessibleImageLabelsTitle}"
- sub-label="$i18n{accessibleImageLabelsSubtitle}">
- </settings-toggle-button>
- <cr-link-row class="hr" label="$i18n{moreFeaturesLink}"
- on-click="onMoreFeaturesLinkClick_" sub-label="$i18n{a11yWebStore}"
- external></cr-link-row>
-</if>
+ </if>
+ </settings-animated-pages>
</template>
<script src="a11y_page.js"></script>
diff --git a/chrome/browser/resources/settings/a11y_page/a11y_page.js b/chrome/browser/resources/settings/a11y_page/a11y_page.js
index 9f0a574..e1cfc426 100644
--- a/chrome/browser/resources/settings/a11y_page/a11y_page.js
+++ b/chrome/browser/resources/settings/a11y_page/a11y_page.js
@@ -43,6 +43,9 @@
type: Object,
value: function() {
const map = new Map();
+ if (settings.routes.CAPTIONS) {
+ map.set(settings.routes.CAPTIONS.path, '#captions');
+ }
// <if expr="chromeos">
if (settings.routes.MANAGE_ACCESSIBILITY) {
map.set(
@@ -53,6 +56,17 @@
},
},
+ /**
+ * Whether to show the link to caption settings.
+ * @private {boolean}
+ */
+ showCaptionSettings_: {
+ type: Boolean,
+ value: function() {
+ return loadTimeData.getBoolean('enableCaptionSettings');
+ },
+ },
+
// <if expr="chromeos">
/**
* Whether to show experimental accessibility features.
@@ -121,4 +135,29 @@
window.open(
'https://chrome.google.com/webstore/category/collection/accessibility');
},
+
+ /** @private */
+ onTapCaptions_: function() {
+ // Open the system captions dialog for Mac.
+ // <if expr="is_macosx">
+ settings.CaptionsBrowserProxyImpl.getInstance().openSystemCaptionsDialog();
+ // </if>
+
+ // Open the system captions dialog for Windows 10+ or navigate to the
+ // caption settings page for older versions of Windows
+ // <if expr="is_win">
+ if (loadTimeData.getBoolean('isWindows10OrNewer')) {
+ settings.CaptionsBrowserProxyImpl.getInstance()
+ .openSystemCaptionsDialog();
+ } else {
+ settings.navigateTo(settings.routes.CAPTIONS);
+ }
+ // </if>
+
+ // Navigate to the caption settings page for ChromeOS and Linux as they
+ // do not have system caption settings.
+ // <if expr="chromeos or is_linux">
+ settings.navigateTo(settings.routes.CAPTIONS);
+ // </if>
+ },
});
diff --git a/chrome/browser/resources/settings/a11y_page/captions_browser_proxy.html b/chrome/browser/resources/settings/a11y_page/captions_browser_proxy.html
new file mode 100644
index 0000000..92b4cd1
--- /dev/null
+++ b/chrome/browser/resources/settings/a11y_page/captions_browser_proxy.html
@@ -0,0 +1,2 @@
+<link rel="import" href="chrome://resources/html/cr.html">
+<script src="captions_browser_proxy.js"></script>
diff --git a/chrome/browser/resources/settings/a11y_page/captions_browser_proxy.js b/chrome/browser/resources/settings/a11y_page/captions_browser_proxy.js
new file mode 100644
index 0000000..bf86a7e
--- /dev/null
+++ b/chrome/browser/resources/settings/a11y_page/captions_browser_proxy.js
@@ -0,0 +1,35 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview A helper object used from the Chrome captions section to
+ * interact with the browser. Used on operating system that is not Chrome OS.
+ */
+
+cr.define('settings', function() {
+ /** @interface */
+ class CaptionsBrowserProxy {
+ /**
+ * Open the native captions system dialog.
+ */
+ openSystemCaptionsDialog() {}
+ }
+
+ /**
+ * @implements {settings.CaptionsBrowserProxy}
+ */
+ class CaptionsBrowserProxyImpl {
+ /** @override */
+ openSystemCaptionsDialog() {
+ chrome.send('openSystemCaptionsDialog');
+ }
+ }
+
+ cr.addSingletonGetter(CaptionsBrowserProxyImpl);
+
+ return {
+ CaptionsBrowserProxy: CaptionsBrowserProxy,
+ CaptionsBrowserProxyImpl: CaptionsBrowserProxyImpl,
+ };
+});
diff --git a/chrome/browser/resources/settings/a11y_page/captions_subpage.html b/chrome/browser/resources/settings/a11y_page/captions_subpage.html
new file mode 100644
index 0000000..31146eb
--- /dev/null
+++ b/chrome/browser/resources/settings/a11y_page/captions_subpage.html
@@ -0,0 +1,89 @@
+<link rel="import" href="chrome://resources/html/i18n_behavior.html">
+<link rel="import" href="chrome://resources/html/polymer.html">
+<link rel="import" href="../appearance_page/fonts_browser_proxy.html">
+<link rel="import" href="../controls/settings_dropdown_menu.html">
+<link rel="import" href="../controls/settings_slider.html">
+<link rel="import" href="../settings_shared_css.html">
+
+<dom-module id="settings-captions">
+ <template>
+ <style include="settings-shared"></style>
+ <div class="settings-box">
+ <div class="start">$i18n{captionsTextSize}</div>
+ <settings-dropdown-menu id="captionsTextSize"
+ label="$i18n{captionsTextSize}"
+ pref="{{prefs.accessibility.captions.text_size}}"
+ menu-options="[[textSizeOptions_]]">
+ </settings-dropdown-menu>
+ </div>
+ <div class="settings-box">
+ <div class="start">$i18n{captionsTextFont}</div>
+ <settings-dropdown-menu id="captionsTextFont"
+ label="$i18n{captionsTextFont}"
+ pref="{{prefs.accessibility.captions.text_font}}"
+ menu-options="[[textFontOptions_]]">
+ </settings-dropdown-menu>
+ </div>
+ <div class="settings-box">
+ <div class="start">$i18n{captionsTextColor}</div>
+ <settings-dropdown-menu id="captionsTextColor"
+ label="$i18n{captionsTextColor}"
+ pref="{{prefs.accessibility.captions.text_color}}"
+ menu-options="[[colorOptions_]]">
+ </settings-dropdown-menu>
+ </div>
+ <div class="settings-box">
+ <div class="start">$i18n{captionsTextOpacity}</div>
+ <settings-slider id="captionsTextOpacity"
+ ticks="[[textOpacityRange_]]"
+ label-min="$i18n{captionsOpacityMin}"
+ label-max="$i18n{captionsOpacityMax}"
+ pref="{{prefs.accessibility.captions.text_opacity}}">
+ </settings-slider>
+ </div>
+ <div class="settings-box">
+ <div class="start">$i18n{captionsTextShadow}</div>
+ <settings-dropdown-menu id="captionsTextShadow"
+ label="$i18n{captionsTextShadow}"
+ pref="{{prefs.accessibility.captions.text_shadow}}"
+ menu-options="[[textShadowOptions_]]">
+ </settings-dropdown-menu>
+ </div>
+ <div class="settings-box">
+ <div class="start">$i18n{captionsBackgroundColor}</div>
+ <settings-dropdown-menu id="captionsBackgroundColor"
+ label="$i18n{captionsBackgroundColor}"
+ pref="{{prefs.accessibility.captions.background_color}}"
+ menu-options="[[colorOptions_]]">
+ </settings-dropdown-menu>
+ </div>
+ <div class="settings-box">
+ <div class="start">$i18n{captionsBackgroundOpacity}</div>
+ <settings-slider id="captionsBackgroundOpacity"
+ ticks="[[textOpacityRange_]]"
+ label-min="$i18n{captionsOpacityMin}"
+ label-max="$i18n{captionsOpacityMax}"
+ pref="{{prefs.accessibility.captions.background_opacity}}">
+ </settings-slider>
+ </div>
+ <div class="list-frame">
+ <div class="list-item">
+ <span style="
+ font-size:[[prefs.accessibility.captions.text_size.value]];
+ font-family:[[prefs.accessibility.captions.text_font.value]];
+ background-color: [[computeBackgroundColor_(
+ prefs.accessibility.captions.background_opacity.value,
+ prefs.accessibility.captions.background_color.value)]];
+ color: [[computeTextColor_(
+ prefs.accessibility.captions.text_opacity.value,
+ prefs.accessibility.captions.text_color.value)]];
+ text-shadow: [[prefs.accessibility.captions.text_shadow.value]];
+ padding: [[computePadding_(
+ prefs.accessibility.captions.text_size.value)]]">
+ $i18n{quickBrownFox}
+ </span>
+ </div>
+ </div>
+ </template>
+ <script src="captions_subpage.js"></script>
+</dom-module>
diff --git a/chrome/browser/resources/settings/a11y_page/captions_subpage.js b/chrome/browser/resources/settings/a11y_page/captions_subpage.js
new file mode 100644
index 0000000..df973af
--- /dev/null
+++ b/chrome/browser/resources/settings/a11y_page/captions_subpage.js
@@ -0,0 +1,217 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview 'settings-captions' is a component for showing captions
+ * settings subpage (chrome://settings/captions).
+ */
+(function() {
+'use strict';
+
+
+/** @type {!Array<number>} */
+const TEXT_OPACITY_RANGE = [
+ 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50,
+ 55, 60, 65, 70, 75, 80, 85, 90, 95, 100
+];
+
+/**
+ * @param {!Array<number>} ticks
+ * @return {!Array<!cr_slider.SliderTick>}
+ */
+function ticksWithLabels(ticks) {
+ return ticks.map(x => ({label: `${x}`, value: x}));
+}
+
+Polymer({
+ is: 'settings-captions',
+
+ behaviors: [I18nBehavior, WebUIListenerBehavior],
+
+ properties: {
+ prefs: {
+ type: Object,
+ notify: true,
+ },
+
+ /**
+ * List of fonts populated by the fonts browser proxy.
+ * @private {!DropdownMenuOptionList} */
+ textFontOptions_: Object,
+
+ /**
+ * Reasonable, text opacity range.
+ * @private {!Array<!cr_slider.SliderTick>}
+ */
+ textOpacityRange_: {
+ readOnly: true,
+ type: Array,
+ value: ticksWithLabels(TEXT_OPACITY_RANGE),
+ },
+
+ /**
+ * List of options for the text size drop-down menu.
+ * @type {!DropdownMenuOptionList}
+ */
+ textSizeOptions_: {
+ readOnly: true,
+ type: Array,
+ value: function() {
+ return [
+ {value: '50%', name: loadTimeData.getString('verySmall')},
+ {value: '75%', name: loadTimeData.getString('small')},
+ {value: '', name: loadTimeData.getString('medium')}, // Default = 100%
+ {value: '150%', name: loadTimeData.getString('large')},
+ {value: '200%', name: loadTimeData.getString('veryLarge')},
+ ];
+ },
+ },
+
+ /**
+ * List of options for the color drop-down menu.
+ * @type {!DropdownMenuOptionList}
+ */
+ colorOptions_: {
+ readOnly: true,
+ type: Array,
+ value: function() {
+ return [
+ {value: '', name: loadTimeData.getString('captionsDefaultSetting')},
+ {value: '0,0,0', name: loadTimeData.getString('captionsColorBlack')},
+ {
+ value: '255,255,255',
+ name: loadTimeData.getString('captionsColorWhite')
+ },
+ {value: '255,0,0', name: loadTimeData.getString('captionsColorRed')},
+ {
+ value: '0,255,0',
+ name: loadTimeData.getString('captionsColorGreen')
+ },
+ {value: '0,0,255', name: loadTimeData.getString('captionsColorBlue')},
+ {
+ value: '255,255,0',
+ name: loadTimeData.getString('captionsColorYellow')
+ },
+ {
+ value: '0,255,255',
+ name: loadTimeData.getString('captionsColorCyan')
+ },
+ {
+ value: '255,0,255',
+ name: loadTimeData.getString('captionsColorMagenta')
+ },
+ ];
+ },
+ },
+
+ /**
+ * List of options for the text shadow drop-down menu.
+ * @type {!DropdownMenuOptionList}
+ */
+ textShadowOptions_: {
+ readOnly: true,
+ type: Array,
+ value: function() {
+ return [
+ {value: '', name: loadTimeData.getString('captionsTextShadowNone')},
+ {
+ value: '-2px -2px 4px rgba(0, 0, 0, 0.5)',
+ name: loadTimeData.getString('captionsTextShadowRaised')
+ },
+ {
+ value: '2px 2px 4px rgba(0, 0, 0, 0.5)',
+ name: loadTimeData.getString('captionsTextShadowDepressed')
+ },
+ {
+ value: '-1px 0px 0px black, ' +
+ '0px -1px 0px black, 1px 0px 0px black, 0px 1px 0px black',
+ name: loadTimeData.getString('captionsTextShadowUniform')
+ },
+ {
+ value: '0px 0px 2px rgba(0, 0, 0, 0.5), 2px 2px 2px black',
+ name: loadTimeData.getString('captionsTextShadowDropShadow')
+ },
+ ];
+ },
+ },
+ },
+
+ /** @private {?settings.FontsBrowserProxy} */
+ browserProxy_: null,
+
+ /** @override */
+ created: function() {
+ this.browserProxy_ = settings.FontsBrowserProxyImpl.getInstance();
+ },
+
+ /** @override */
+ ready: function() {
+ this.browserProxy_.observeAdvancedFontExtensionAvailable();
+
+ this.browserProxy_.fetchFontsData().then(this.setFontsData_.bind(this));
+ },
+
+ /**
+ * @param {!FontsData} response A list of fonts.
+ * @private
+ */
+ setFontsData_: function(response) {
+ const fontMenuOptions =
+ [{value: '', name: loadTimeData.getString('captionsDefaultSetting')}];
+ for (const fontData of response.fontList) {
+ fontMenuOptions.push({value: fontData[0], name: fontData[1]});
+ }
+ this.textFontOptions_ = fontMenuOptions;
+ },
+
+ /**
+ * Get the background color as a RGBA string.
+ * @return {string}
+ * @private
+ */
+ computeBackgroundColor_: function() {
+ return this.formatRGAString_(
+ 'prefs.accessibility.captions.background_color.value',
+ 'prefs.accessibility.captions.background_opacity.value');
+ },
+
+ /**
+ * Get the text color as a RGBA string.
+ * @return {string}
+ * @private
+ */
+ computeTextColor_: function() {
+ return this.formatRGAString_(
+ 'prefs.accessibility.captions.text_color.value',
+ 'prefs.accessibility.captions.text_opacity.value');
+ },
+
+ /**
+ * Formats the color as an RGBA string.
+ * @param {string} colorPreference The name of the preference containing the
+ * RGB values as a comma-separated string.
+ * @param {string} opacityPreference The name of the preference containing
+ * the opacity value as a percentage.
+ * @return {string} The formatted RGBA string.
+ * @private
+ */
+ formatRGAString_: function(colorPreference, opacityPreference) {
+ return 'rgba(' + this.get(colorPreference) + ',' +
+ parseInt(this.get(opacityPreference), 10) / 100.0 + ')';
+ },
+
+ /**
+ * @param {string} size The font size of the captions text as a percentage.
+ * @return {string} The padding around the captions text as a percentage.
+ * @private
+ */
+ computePadding_: function(size) {
+ if (size == '') {
+ return '1%';
+ }
+
+ return `${+size.slice(0, -1) / 100}%`;
+ }
+});
+})();
diff --git a/chrome/browser/resources/settings/route.js b/chrome/browser/resources/settings/route.js
index ba363d6..afa2d17 100644
--- a/chrome/browser/resources/settings/route.js
+++ b/chrome/browser/resources/settings/route.js
@@ -26,6 +26,7 @@
* BASIC: (undefined|!settings.Route),
* BLUETOOTH: (undefined|!settings.Route),
* BLUETOOTH_DEVICES: (undefined|!settings.Route),
+ * CAPTIONS: (undefined|!settings.Route),
* CERTIFICATES: (undefined|!settings.Route),
* CHANGE_PICTURE: (undefined|!settings.Route),
* CHROME_CLEANUP: (undefined|!settings.Route),
@@ -463,6 +464,20 @@
// </if>
r.ACCESSIBILITY = r.ADVANCED.createSection('/accessibility', 'a11y');
+
+ // <if expr="chromeos or is_linux">
+ if (loadTimeData.getBoolean('enableCaptionSettings')) {
+ r.CAPTIONS = r.ACCESSIBILITY.createChild('/captions');
+ }
+ // </if>
+
+ // <if expr="is_win">
+ if (loadTimeData.getBoolean('enableCaptionSettings') &&
+ !loadTimeData.getBoolean('isWindows10OrNewer')) {
+ r.CAPTIONS = r.ACCESSIBILITY.createChild('/captions');
+ }
+ // </if>
+
// <if expr="chromeos">
r.MANAGE_ACCESSIBILITY =
r.ACCESSIBILITY.createChild('/manageAccessibility');
diff --git a/chrome/browser/resources/settings/settings_resources.grd b/chrome/browser/resources/settings/settings_resources.grd
index 6e6b2c12..beae2b9 100644
--- a/chrome/browser/resources/settings/settings_resources.grd
+++ b/chrome/browser/resources/settings/settings_resources.grd
@@ -21,6 +21,18 @@
type="chrome_html"
preprocess="true"
allowexternalscript="true" />
+ <structure name="IDR_SETTINGS_CAPTIONS_SUBPAGE_HTML"
+ file="a11y_page/captions_subpage.html"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_CAPTIONS_SUBPAGE_JS"
+ file="a11y_page/captions_subpage.js"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_CAPTIONS_BROWSER_PROXY_HTML"
+ file="a11y_page/captions_browser_proxy.html"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_CAPTIONS_BROWSER_PROXY_JS"
+ file="a11y_page/captions_browser_proxy.js"
+ type="chrome_html" />
<if expr="chromeos">
<structure name="IDR_SETTINGS_MANAGE_A11Y_PAGE_JS"
file="a11y_page/manage_a11y_page.js"
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index c34eab4b..9ba3f91e 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -335,6 +335,13 @@
"webui/webui_util.h",
]
+ if (is_win || is_mac) {
+ sources += [
+ "webui/settings/captions_handler.cc",
+ "webui/settings/captions_handler.h",
+ ]
+ }
+
if (enable_vr) {
if (is_win) {
sources += [
diff --git a/chrome/browser/ui/prefs/pref_watcher.cc b/chrome/browser/ui/prefs/pref_watcher.cc
index adec473..44cffec 100644
--- a/chrome/browser/ui/prefs/pref_watcher.cc
+++ b/chrome/browser/ui/prefs/pref_watcher.cc
@@ -30,6 +30,13 @@
prefs::kWebKitDefaultFixedFontSize,
prefs::kWebKitDefaultFontSize,
prefs::kWebKitDomPasteEnabled,
+ prefs::kAccessibilityCaptionsTextSize,
+ prefs::kAccessibilityCaptionsTextFont,
+ prefs::kAccessibilityCaptionsTextColor,
+ prefs::kAccessibilityCaptionsTextOpacity,
+ prefs::kAccessibilityCaptionsBackgroundColor,
+ prefs::kAccessibilityCaptionsTextShadow,
+ prefs::kAccessibilityCaptionsBackgroundOpacity,
#if defined(OS_ANDROID)
prefs::kWebKitFontScaleFactor,
prefs::kWebKitForceDarkModeEnabled,
diff --git a/chrome/browser/ui/webui/settings/captions_handler.cc b/chrome/browser/ui/webui/settings/captions_handler.cc
new file mode 100644
index 0000000..f91f2fdd
--- /dev/null
+++ b/chrome/browser/ui/webui/settings/captions_handler.cc
@@ -0,0 +1,34 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/settings/captions_handler.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "chrome/browser/accessibility/caption_settings_dialog.h"
+#include "content/public/browser/web_ui.h"
+
+namespace settings {
+
+CaptionsHandler::CaptionsHandler() {}
+
+CaptionsHandler::~CaptionsHandler() {}
+
+void CaptionsHandler::RegisterMessages() {
+ web_ui()->RegisterMessageCallback(
+ "openSystemCaptionsDialog",
+ base::BindRepeating(&CaptionsHandler::HandleOpenSystemCaptionsDialog,
+ base::Unretained(this)));
+}
+
+void CaptionsHandler::OnJavascriptAllowed() {}
+
+void CaptionsHandler::OnJavascriptDisallowed() {}
+
+void CaptionsHandler::HandleOpenSystemCaptionsDialog(
+ const base::ListValue* args) {
+ captions::CaptionSettingsDialog::ShowCaptionSettingsDialog();
+}
+
+} // namespace settings
diff --git a/chrome/browser/ui/webui/settings/captions_handler.h b/chrome/browser/ui/webui/settings/captions_handler.h
new file mode 100644
index 0000000..28ea30d
--- /dev/null
+++ b/chrome/browser/ui/webui/settings/captions_handler.h
@@ -0,0 +1,34 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_CAPTIONS_HANDLER_H_
+#define CHROME_BROWSER_UI_WEBUI_SETTINGS_CAPTIONS_HANDLER_H_
+
+#include "base/macros.h"
+#include "build/build_config.h"
+#include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
+
+namespace settings {
+
+// UI handler for Chrome caption settings subpage on operating systems other
+// than Chrome OS and Linux.
+class CaptionsHandler : public SettingsPageUIHandler {
+ public:
+ CaptionsHandler();
+ ~CaptionsHandler() override;
+
+ // SettingsPageUIHandler overrides:
+ void RegisterMessages() override;
+ void OnJavascriptAllowed() override;
+ void OnJavascriptDisallowed() override;
+
+ private:
+ void HandleOpenSystemCaptionsDialog(const base::ListValue* args);
+
+ DISALLOW_COPY_AND_ASSIGN(CaptionsHandler);
+};
+
+} // namespace settings
+
+#endif // CHROME_BROWSER_UI_WEBUI_SETTINGS_CAPTIONS_HANDLER_H_
diff --git a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
index eb52546..10ac391 100644
--- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
@@ -12,6 +12,7 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/win/windows_version.h"
#include "build/build_config.h"
#include "build/buildflag.h"
#include "chrome/browser/autofill/personal_data_manager_factory.h"
@@ -191,6 +192,32 @@
{"moreFeaturesLink", IDS_SETTINGS_MORE_FEATURES_LINK},
{"moreFeaturesLinkDescription",
IDS_SETTINGS_MORE_FEATURES_LINK_DESCRIPTION},
+ {"captionsTitle", IDS_SETTINGS_CAPTIONS},
+ {"captionsTextSize", IDS_SETTINGS_CAPTIONS_TEXT_SIZE},
+ {"captionsTextFont", IDS_SETTINGS_CAPTIONS_TEXT_FONT},
+ {"captionsTextColor", IDS_SETTINGS_CAPTIONS_TEXT_COLOR},
+ {"captionsTextOpacity", IDS_SETTINGS_CAPTIONS_TEXT_OPACITY},
+ {"captionsBackgroundOpacity", IDS_SETTINGS_CAPTIONS_BACKGROUND_OPACITY},
+ {"captionsOpacityMin", IDS_SETTINGS_CAPTIONS_OPACITY_MIN},
+ {"captionsOpacityMax", IDS_SETTINGS_CAPTIONS_OPACITY_MAX},
+ {"captionsTextShadow", IDS_SETTINGS_CAPTIONS_TEXT_SHADOW},
+ {"captionsTextShadowNone", IDS_SETTINGS_CAPTIONS_TEXT_SHADOW_NONE},
+ {"captionsTextShadowRaised", IDS_SETTINGS_CAPTIONS_TEXT_SHADOW_RAISED},
+ {"captionsTextShadowDepressed",
+ IDS_SETTINGS_CAPTIONS_TEXT_SHADOW_DEPRESSED},
+ {"captionsTextShadowUniform", IDS_SETTINGS_CAPTIONS_TEXT_SHADOW_UNIFORM},
+ {"captionsTextShadowDropShadow",
+ IDS_SETTINGS_CAPTIONS_TEXT_SHADOW_DROP_SHADOW},
+ {"captionsBackgroundColor", IDS_SETTINGS_CAPTIONS_BACKGROUND_COLOR},
+ {"captionsColorBlack", IDS_SETTINGS_CAPTIONS_COLOR_BLACK},
+ {"captionsColorWhite", IDS_SETTINGS_CAPTIONS_COLOR_WHITE},
+ {"captionsColorRed", IDS_SETTINGS_CAPTIONS_COLOR_RED},
+ {"captionsColorGreen", IDS_SETTINGS_CAPTIONS_COLOR_GREEN},
+ {"captionsColorBlue", IDS_SETTINGS_CAPTIONS_COLOR_BLUE},
+ {"captionsColorYellow", IDS_SETTINGS_CAPTIONS_COLOR_YELLOW},
+ {"captionsColorCyan", IDS_SETTINGS_CAPTIONS_COLOR_CYAN},
+ {"captionsColorMagenta", IDS_SETTINGS_CAPTIONS_COLOR_MAGENTA},
+ {"captionsDefaultSetting", IDS_SETTINGS_CAPTIONS_DEFAULT_SETTING},
#if defined(OS_CHROMEOS)
{"optionsInMenuLabel", IDS_SETTINGS_OPTIONS_IN_MENU_LABEL},
{"largeMouseCursorLabel", IDS_SETTINGS_LARGE_MOUSE_CURSOR_LABEL},
@@ -344,6 +371,15 @@
"showExperimentalA11yLabels",
base::FeatureList::IsEnabled(features::kExperimentalAccessibilityLabels));
+ html_source->AddBoolean(
+ "enableCaptionSettings",
+ base::FeatureList::IsEnabled(features::kCaptionSettings));
+
+#if defined(OS_WIN)
+ html_source->AddBoolean("isWindows10OrNewer",
+ base::win::GetVersion() >= base::win::Version::WIN10);
+#endif
+
#if defined(OS_CHROMEOS)
html_source->AddString("accountManagerLearnMoreUrl",
chrome::kAccountManagerLearnMoreURL);
diff --git a/chrome/browser/ui/webui/settings/settings_ui.cc b/chrome/browser/ui/webui/settings/settings_ui.cc
index fe76537..c5a2b951 100644
--- a/chrome/browser/ui/webui/settings/settings_ui.cc
+++ b/chrome/browser/ui/webui/settings/settings_ui.cc
@@ -26,6 +26,7 @@
#include "chrome/browser/ui/webui/settings/accessibility_main_handler.h"
#include "chrome/browser/ui/webui/settings/appearance_handler.h"
#include "chrome/browser/ui/webui/settings/browser_lifetime_handler.h"
+#include "chrome/browser/ui/webui/settings/captions_handler.h"
#include "chrome/browser/ui/webui/settings/downloads_handler.h"
#include "chrome/browser/ui/webui/settings/extension_control_handler.h"
#include "chrome/browser/ui/webui/settings/font_handler.h"
@@ -226,6 +227,10 @@
AddSettingsPageUIHandler(std::make_unique<StartupPagesHandler>(web_ui));
AddSettingsPageUIHandler(std::make_unique<SecurityKeysHandler>());
+#if defined(OS_WIN) || defined(OS_MACOSX)
+ AddSettingsPageUIHandler(std::make_unique<CaptionsHandler>());
+#endif
+
#if defined(OS_CHROMEOS)
// TODO(950007): Remove this when SplitSettings is the default and there are
// no Chrome OS settings in the browser settings page.