Add prefers-reduced-transparency emulation to dev tools

This is guarded behind a support check while this
media feature is still behind the experimental flag

Bug: 1424879
Change-Id: I9b9195f62ed92ba1e840b18671cb8c84578b9e22
Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/4701064
Reviewed-by: Changhao Han <[email protected]>
Reviewed-by: Mathias Bynens <[email protected]>
Commit-Queue: Philip Rogers <[email protected]>
diff --git a/AUTHORS b/AUTHORS
index 41353dd..9e7d8f7 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -45,6 +45,7 @@
 Kohei Ueno <[email protected]>
 Krishnal Ciccolella <[email protected]>
 Luke Swiderski <[email protected]>
+Luke Warlow <[email protected]>
 Marijn Haverbeke <[email protected]>
 Michael Brüning <[email protected]>
 Michael Rienstra <[email protected]>
diff --git a/front_end/core/i18n/locales/en-GB.json b/front_end/core/i18n/locales/en-GB.json
index 8be957b..1d36011 100644
--- a/front_end/core/i18n/locales/en-GB.json
+++ b/front_end/core/i18n/locales/en-GB.json
@@ -902,6 +902,9 @@
   "entrypoints/inspector_main/RenderingOptions.ts | forcesCssPrefersreducedmotion": {
     "message": "Forces CSS prefers-reduced-motion media feature"
   },
+  "entrypoints/inspector_main/RenderingOptions.ts | forcesCssPrefersreducedtransparencyMedia": {
+    "message": "Forces CSS prefers-reduced-transparency media feature"
+  },
   "entrypoints/inspector_main/RenderingOptions.ts | forcesMediaTypeForTestingPrint": {
     "message": "Forces media type for testing print and screen styles"
   },
diff --git a/front_end/core/sdk/EmulationModel.ts b/front_end/core/sdk/EmulationModel.ts
index f0ab4f5..613461a 100644
--- a/front_end/core/sdk/EmulationModel.ts
+++ b/front_end/core/sdk/EmulationModel.ts
@@ -81,6 +81,8 @@
         Common.Settings.Settings.instance().moduleSetting<string>('emulatedCSSMediaFeaturePrefersContrast');
     const mediaFeaturePrefersReducedDataSetting =
         Common.Settings.Settings.instance().moduleSetting<string>('emulatedCSSMediaFeaturePrefersReducedData');
+    const mediaFeaturePrefersReducedTransparencySetting =
+        Common.Settings.Settings.instance().moduleSetting<string>('emulatedCSSMediaFeaturePrefersReducedTransparency');
     const mediaFeaturePrefersReducedMotionSetting =
         Common.Settings.Settings.instance().moduleSetting<string>('emulatedCSSMediaFeaturePrefersReducedMotion');
     // Note: this uses a different format than what the CDP API expects,
@@ -95,6 +97,7 @@
       ['prefers-contrast', mediaFeaturePrefersContrastSetting.get()],
       ['prefers-reduced-data', mediaFeaturePrefersReducedDataSetting.get()],
       ['prefers-reduced-motion', mediaFeaturePrefersReducedMotionSetting.get()],
+      ['prefers-reduced-transparency', mediaFeaturePrefersReducedTransparencySetting.get()],
     ]);
     mediaTypeSetting.addChangeListener(() => {
       this.#mediaConfiguration.set('type', mediaTypeSetting.get());
@@ -124,6 +127,10 @@
       this.#mediaConfiguration.set('prefers-reduced-motion', mediaFeaturePrefersReducedMotionSetting.get());
       void this.updateCssMedia();
     });
+    mediaFeaturePrefersReducedTransparencySetting.addChangeListener(() => {
+      this.#mediaConfiguration.set('prefers-reduced-transparency', mediaFeaturePrefersReducedTransparencySetting.get());
+      void this.updateCssMedia();
+    });
     void this.updateCssMedia();
 
     const autoDarkModeSetting = Common.Settings.Settings.instance().moduleSetting('emulateAutoDarkMode');
@@ -395,6 +402,10 @@
         name: 'prefers-reduced-motion',
         value: this.#mediaConfiguration.get('prefers-reduced-motion') ?? '',
       },
+      {
+        name: 'prefers-reduced-transparency',
+        value: this.#mediaConfiguration.get('prefers-reduced-transparency') ?? '',
+      },
     ];
     return this.emulateCSSMedia(type, features);
   }
diff --git a/front_end/core/sdk/sdk-meta.ts b/front_end/core/sdk/sdk-meta.ts
index 9ff5b99..58fb249 100644
--- a/front_end/core/sdk/sdk-meta.ts
+++ b/front_end/core/sdk/sdk-meta.ts
@@ -858,6 +858,26 @@
 });
 
 Common.Settings.registerSettingExtension({
+  settingName: 'emulatedCSSMediaFeaturePrefersReducedTransparency',
+  settingType: Common.Settings.SettingType.ENUM,
+  storageType: Common.Settings.SettingStorageType.Session,
+  defaultValue: '',
+  options: [
+    {
+      title: i18nLazyString(UIStrings.doNotEmulateCss, {PH1: 'prefers-reduced-transparency'}),
+      text: i18nLazyString(UIStrings.noEmulation),
+      value: '',
+    },
+    {
+      title: i18nLazyString(UIStrings.emulateCss, {PH1: 'prefers-reduced-transparency: reduce'}),
+      text: i18n.i18n.lockedLazyString('prefers-reduced-transparency: reduce'),
+      value: 'reduce',
+    },
+  ],
+  title: i18nLazyString(UIStrings.emulateCssMediaFeature, {PH1: 'prefers-reduced-transparency'}),
+});
+
+Common.Settings.registerSettingExtension({
   settingName: 'emulatedCSSMediaFeatureColorGamut',
   settingType: Common.Settings.SettingType.ENUM,
   storageType: Common.Settings.SettingStorageType.Session,
diff --git a/front_end/entrypoints/inspector_main/RenderingOptions.ts b/front_end/entrypoints/inspector_main/RenderingOptions.ts
index 1df1717..18522a3 100644
--- a/front_end/entrypoints/inspector_main/RenderingOptions.ts
+++ b/front_end/entrypoints/inspector_main/RenderingOptions.ts
@@ -154,6 +154,10 @@
    */
   forcesCssPrefersreduceddataMedia: 'Forces CSS `prefers-reduced-data` media feature',
   /**
+   * @description Explanation text for the 'Forces CSS prefers-reduced-transparency media' setting in the Rendering tool.
+   */
+  forcesCssPrefersreducedtransparencyMedia: 'Forces CSS `prefers-reduced-transparency` media feature',
+  /**
    * @description Explanation text for the 'Forces CSS color-gamut media' setting in the Rendering tool.
    */
   forcesCssColorgamutMediaFeature: 'Forces CSS `color-gamut` media feature',
@@ -195,6 +199,14 @@
   return window.matchMedia(query).media === query;
 };
 
+// TODO(1424879): remove this feature detection and expose the UI
+// unconditionally once prefers-reduced-transparency ships unflagged.
+const supportsPrefersReducedTransparency = (): boolean => {
+  const query = '(prefers-reduced-transparency)';
+  // Note: `media` serializes to `'not all'` for unsupported queries.
+  return window.matchMedia(query).media === query;
+};
+
 const supportsPrefersContrast = (): boolean => {
   const query = '(prefers-contrast)';
   return window.matchMedia(query).media === query;
@@ -261,6 +273,11 @@
           i18nString(UIStrings.forcesCssPrefersreduceddataMedia),
           Common.Settings.Settings.instance().moduleSetting('emulatedCSSMediaFeaturePrefersReducedData'));
     }
+    if (supportsPrefersReducedTransparency()) {
+      this.#appendSelect(
+          i18nString(UIStrings.forcesCssPrefersreducedtransparencyMedia),
+          Common.Settings.Settings.instance().moduleSetting('emulatedCSSMediaFeaturePrefersReducedTransparency'));
+    }
     this.#appendSelect(
         i18nString(UIStrings.forcesCssColorgamutMediaFeature),
         Common.Settings.Settings.instance().moduleSetting('emulatedCSSMediaFeatureColorGamut'));
diff --git a/test/unittests/front_end/helpers/EnvironmentHelpers.ts b/test/unittests/front_end/helpers/EnvironmentHelpers.ts
index 49f57b4..4becb7a 100644
--- a/test/unittests/front_end/helpers/EnvironmentHelpers.ts
+++ b/test/unittests/front_end/helpers/EnvironmentHelpers.ts
@@ -166,6 +166,9 @@
         Common.Settings.SettingCategory.RENDERING, 'emulatedCSSMediaFeaturePrefersReducedData', '',
         Common.Settings.SettingType.ENUM),
     createSettingValue(
+        Common.Settings.SettingCategory.RENDERING, 'emulatedCSSMediaFeaturePrefersReducedTransparency', '',
+        Common.Settings.SettingType.ENUM),
+    createSettingValue(
         Common.Settings.SettingCategory.RENDERING, 'emulatedCSSMediaFeatureColorGamut', '',
         Common.Settings.SettingType.ENUM),
     createSettingValue(