public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
* [rpms/chromium] epel9-next: - Update to 148.0.7778.178
@ 2026-08-07 16:09 Than Ngo
0 siblings, 0 replies; only message in thread
From: Than Ngo @ 2026-08-07 16:09 UTC (permalink / raw)
To: git-commits
A new commit has been pushed.
Repo : rpms/chromium
Branch : epel9-next
Commit : caa17821fede48a341a05a80386cdab1732b3e7d
Author : Than Ngo <than@redhat.com>
Date : 2026-05-20T16:28:36+02:00
Stats : +1332/-23 in 8 file(s)
URL : https://src.fedoraproject.org/rpms/chromium/c/caa17821fede48a341a05a80386cdab1732b3e7d?branch=epel9-next
Log:
- Update to 148.0.7778.178
- Backport upstream patches to improve auto dark image inversion logic
- Update default chromium browser config
---
diff --git a/chromium-148-Add-AutoDarkModeSkipImages-flag-to-bypass-image-dark-mode.patch b/chromium-148-Add-AutoDarkModeSkipImages-flag-to-bypass-image-dark-mode.patch
new file mode 100644
index 0000000..65f2cd3
--- /dev/null
+++ b/chromium-148-Add-AutoDarkModeSkipImages-flag-to-bypass-image-dark-mode.patch
@@ -0,0 +1,65 @@
+commit 59996c3a87e7a332247f053a34125ea8eb7e351a
+Author: Prashant Nevase <pnevase@microsoft.com>
+Date: Fri May 15 08:01:49 2026 -0700
+
+ Add AutoDarkModeSkipImages flag to bypass image dark mode
+
+ When the AutoDarkModeSkipImages flag is enabled, the dark mode filter
+ (Auto Dark / force-dark) skips applying dark mode to images entirely;
+ all images are kept untouched as if they are in light mode.
+
+ This is a stop gap solution till default dark mode works as expected.
+ Users will have to use following command for using it.
+ chrome.exe --enable-blink-features="AutoDarkModeSkipImages"
+
+ Bug: 449909524
+ Change-Id: Ib4af9253d9e65f8e517994be661a15d3fb4f9083
+ Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7849600
+ Reviewed-by: Stephen Chenney <schenney@chromium.org>
+ Commit-Queue: Prashant Nevase <pnevase@microsoft.com>
+ Cr-Commit-Position: refs/heads/main@{#1631280}
+
+diff --git a/third_party/blink/renderer/platform/graphics/dark_mode_filter.cc b/third_party/blink/renderer/platform/graphics/dark_mode_filter.cc
+index 6bc23ce40786..414fb95a44db 100644
+--- a/third_party/blink/renderer/platform/graphics/dark_mode_filter.cc
++++ b/third_party/blink/renderer/platform/graphics/dark_mode_filter.cc
+@@ -19,6 +19,7 @@
+ #include "third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.h"
+ #include "third_party/blink/renderer/platform/graphics/dark_mode_settings.h"
+ #include "third_party/blink/renderer/platform/graphics/image.h"
++#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
+ #include "third_party/blink/renderer/platform/wtf/hash_functions.h"
+ #include "third_party/skia/include/core/SkBitmap.h"
+ #include "third_party/skia/include/core/SkColor.h"
+@@ -201,6 +202,12 @@ void DarkModeFilter::ApplyFilterToImage(Image* image,
+ DCHECK(image);
+ DCHECK(flags);
+
++ // When the `AutoDarkModeSkipImages` feature is enabled, never apply dark mode
++ // to images bypassing classification entirely.
++ if (RuntimeEnabledFeatures::AutoDarkModeSkipImagesEnabled()) {
++ return;
++ }
++
+ // Raster-side dark mode path - Just set the dark mode on flags and dark
+ // mode will be applied at compositor side during rasterization.
+ if (ShouldUseRasterSidePath(image)) {
+diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
+index 16316a0e0ce9..ad7b29a2a47d 100644
+--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
++++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
+@@ -749,6 +749,14 @@
+ base_feature: "none",
+ origin_trial_feature_name: "AutoDarkMode",
+ },
++ {
++ // When enabled, the dark mode filter (Auto Dark / force-dark) skips
++ // applying dark mode to images entirely; all images are kept untouched
++ // as if they are in light mode.
++ // P.N. `AutoDarkMode` needs to be applied separately.
++ name: "AutoDarkModeSkipImages",
++ base_feature: "AutoDarkModeSkipImages",
++ },
+ {
+ name: "Autofill",
+ public: true,
diff --git a/chromium-148-Add-luminance-ratio-feature-for-dark-mode-image-classification.patch b/chromium-148-Add-luminance-ratio-feature-for-dark-mode-image-classification.patch
new file mode 100644
index 0000000..bf9b9f8
--- /dev/null
+++ b/chromium-148-Add-luminance-ratio-feature-for-dark-mode-image-classification.patch
@@ -0,0 +1,311 @@
+commit a207a12457397aebd0ef0898b645c62345c160ce
+Author: Prashant Nevase <pnevase@microsoft.com>
+Date: Thu May 7 00:03:47 2026 -0700
+
+ Add luminance ratio feature for dark mode image classification.
+
+ Image with a transparent background and light foreground (e.g.
+ a logo with light color lettering on transparent PNG) was getting
+ inverted by the dark mode filter, turning the foreground dark and
+ making it merge with dark background.
+
+ This cl adds a luminance ratio feature to skip filtering when both
+ transparency ratio and luminance ratio exceed their thresholds. Here
+ only high luminance ratio is considered.
+
+ This new feature corrects existing tests having images with transparent
+ background and light foreground.
+
+ Bug: 449909524
+ Change-Id: Ia84137ad9af2c9d253a3ba46b255147e356b542f
+ Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7806455
+ Commit-Queue: Prashant Nevase <pnevase@microsoft.com>
+ Reviewed-by: Stephen Chenney <schenney@chromium.org>
+ Cr-Commit-Position: refs/heads/main@{#1626754}
+
+diff --git a/third_party/blink/renderer/platform/blink_platform_unittests_bundle_data.filelist b/third_party/blink/renderer/platform/blink_platform_unittests_bundle_data.filelist
+index 6c6bf1fbda07..acb3f240d841 100644
+--- a/third_party/blink/renderer/platform/blink_platform_unittests_bundle_data.filelist
++++ b/third_party/blink/renderer/platform/blink_platform_unittests_bundle_data.filelist
+@@ -693,6 +693,9 @@
+ ../../web_tests/images/resources/small-square-with-colorspin-profile.jpg
+ ../../web_tests/images/resources/sprite_all_fragments_same.png
+ ../../web_tests/images/resources/sprite_alternate_fragments_same.png
++../../web_tests/images/resources/sprite_dark_background.png
++../../web_tests/images/resources/sprite_light_background.png
++../../web_tests/images/resources/sprite_transparent_background.png
+ ../../web_tests/images/resources/stripes-large.png
+ ../../web_tests/images/resources/stripes-small.png
+ ../../web_tests/images/resources/test-load.jpg
+diff --git a/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.cc b/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.cc
+index cf923b9493fd..8151543ee33f 100644
+--- a/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.cc
++++ b/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.cc
+@@ -21,6 +21,20 @@ namespace {
+ constexpr std::array<float, 2> kLowColorCountThreshold = {0.8125, 0.015137};
+ constexpr std::array<float, 2> kHighColorCountThreshold = {1, 0.025635};
+
++// Color is considered light if its luma is above this threshold.
++constexpr int kHighLightnessThreshold = 96;
++
++// Luminance ratio threshold above which the image is classified as light.
++constexpr float kHighLuminanceThreshold = 0.5f;
++
++// Transparency ratio threshold above which the image is classified as
++// transparent, meaning most of the background pixels are transparent.
++constexpr float kTransparencyRatioThreshold = 0.4f;
++
++const int kMaxSampledPixels = 1000;
++const int kMaxBlocks = 10;
++const float kMinOpaquePixelPercentageForForeground = 0.2;
++
+ bool IsColorGray(const SkColor& color) {
+ return abs(static_cast<int>(SkColorGetR(color)) -
+ static_cast<int>(SkColorGetG(color))) +
+@@ -33,9 +47,13 @@ bool IsColorTransparent(const SkColor& color) {
+ return (SkColorGetA(color) < 128);
+ }
+
+-const int kMaxSampledPixels = 1000;
+-const int kMaxBlocks = 10;
+-const float kMinOpaquePixelPercentageForForeground = 0.2;
++bool IsColorLight(const SkColor& color) {
++ // ITU-R BT.601 Y'CbCr based luma calculation.
++ int luma = (SkColorGetR(color) * 299 + SkColorGetG(color) * 587 +
++ SkColorGetB(color) * 114) /
++ 1000;
++ return luma >= kHighLightnessThreshold;
++}
+
+ } // namespace
+
+@@ -179,12 +197,18 @@ DarkModeImageClassifier::Features DarkModeImageClassifier::ComputeFeatures(
+ const float background_ratio) const {
+ int samples_count = static_cast<int>(sampled_pixels.size());
+
+- // Is image grayscale.
+ int color_pixels = 0;
++ int high_luma_pixels = 0;
+ for (const SkColor& sample : sampled_pixels) {
+- if (!IsColorGray(sample))
++ if (!IsColorGray(sample)) {
+ color_pixels++;
++ }
++
++ if (IsColorLight(sample)) {
++ high_luma_pixels++;
++ }
+ }
++
+ ColorMode color_mode = (color_pixels > samples_count / 100)
+ ? ColorMode::kColor
+ : ColorMode::kGrayscale;
+@@ -195,6 +219,8 @@ DarkModeImageClassifier::Features DarkModeImageClassifier::ComputeFeatures(
+ ComputeColorBucketsRatio(sampled_pixels, color_mode);
+ features.transparency_ratio = transparency_ratio;
+ features.background_ratio = background_ratio;
++ features.high_luminance_ratio =
++ static_cast<float>(high_luma_pixels) / samples_count;
+
+ return features;
+ }
+@@ -258,18 +284,26 @@ DarkModeResult DarkModeImageClassifier::ClassifyWithFeatures(
+
+ DarkModeResult DarkModeImageClassifier::ClassifyUsingDecisionTree(
+ const DarkModeImageClassifier::Features& features) const {
+- float low_color_count_threshold =
+- kLowColorCountThreshold[features.is_colorful];
+- float high_color_count_threshold =
+- kHighColorCountThreshold[features.is_colorful];
++ // Skip filtering for images that have transparent background and whose
++ // foreground is predominantly light. Inverting such images would make
++ // visible pixels darker, causing them to merge with dark background, so do
++ // not apply filter.
++ if (features.transparency_ratio > kTransparencyRatioThreshold &&
++ features.high_luminance_ratio > kHighLuminanceThreshold) {
++ return DarkModeResult::kDoNotApplyFilter;
++ }
+
+ // Very few colors means it's not a photo, apply the filter.
+- if (features.color_buckets_ratio < low_color_count_threshold)
++ if (features.color_buckets_ratio <
++ kLowColorCountThreshold[features.is_colorful]) {
+ return DarkModeResult::kApplyFilter;
++ }
+
+ // Too many colors means it's probably photorealistic, do not apply it.
+- if (features.color_buckets_ratio > high_color_count_threshold)
++ if (features.color_buckets_ratio >
++ kHighColorCountThreshold[features.is_colorful]) {
+ return DarkModeResult::kDoNotApplyFilter;
++ }
+
+ // In-between, decision tree cannot give a precise result.
+ return DarkModeResult::kNotClassified;
+diff --git a/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.h b/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.h
+index a660e9c999c7..9bc536750e76 100644
+--- a/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.h
++++ b/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.h
+@@ -40,6 +40,9 @@ class PLATFORM_EXPORT DarkModeImageClassifier {
+ // background.
+ float transparency_ratio;
+ float background_ratio;
++
++ // Ratio of high luminance pixels to all sampled pixels in the image.
++ float high_luminance_ratio;
+ };
+
+ DarkModeResult Classify(const SkPixmap& pixmap, const SkIRect& src) const;
+diff --git a/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier_test.cc b/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier_test.cc
+index fa54e4e8fddc..e634550498a7 100644
+--- a/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier_test.cc
++++ b/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier_test.cc
+@@ -63,7 +63,7 @@ TEST_F(DarkModeImageClassifierTest, ValidImage) {
+ bitmap.peekPixels(&pixmap);
+ EXPECT_EQ(image_classifier()->Classify(
+ pixmap, SkIRect::MakeWH(image->width(), image->height())),
+- DarkModeResult::kApplyFilter);
++ DarkModeResult::kDoNotApplyFilter);
+ }
+
+ TEST_F(DarkModeImageClassifierTest, InvalidImage) {
+@@ -156,6 +156,58 @@ TEST_F(DarkModeImageClassifierTest, ImageSpriteAlternateFragmentsSame) {
+ DarkModeResult::kDoNotApplyFilter);
+ }
+
++TEST_F(DarkModeImageClassifierTest, ImageWithTransparentBackground) {
++ scoped_refptr<BitmapImage> image;
++ SkBitmap bitmap;
++ SkPixmap pixmap;
++ image = GetImage("/images/resources/sprite_transparent_background.png");
++ bitmap = image->AsSkBitmapForCurrentFrame(kDoNotRespectImageOrientation);
++ bitmap.peekPixels(&pixmap);
++
++ EXPECT_EQ(
++ image_classifier()->Classify(pixmap, SkIRect::MakeXYWH(0, 0, 128, 24)),
++ DarkModeResult::kApplyFilter);
++
++ EXPECT_EQ(
++ image_classifier()->Classify(pixmap, SkIRect::MakeXYWH(0, 24, 128, 24)),
++ DarkModeResult::kDoNotApplyFilter);
++}
++
++TEST_F(DarkModeImageClassifierTest, ImageWithLightBackground) {
++ scoped_refptr<BitmapImage> image;
++ SkBitmap bitmap;
++ SkPixmap pixmap;
++ image = GetImage("/images/resources/sprite_light_background.png");
++ bitmap = image->AsSkBitmapForCurrentFrame(kDoNotRespectImageOrientation);
++ bitmap.peekPixels(&pixmap);
++
++ // TODO(pnevase): Handle this case better.
++ EXPECT_EQ(
++ image_classifier()->Classify(pixmap, SkIRect::MakeXYWH(0, 0, 128, 24)),
++ DarkModeResult::kDoNotApplyFilter);
++
++ EXPECT_EQ(
++ image_classifier()->Classify(pixmap, SkIRect::MakeXYWH(0, 24, 128, 24)),
++ DarkModeResult::kApplyFilter);
++}
++
++TEST_F(DarkModeImageClassifierTest, ImageWithDarkBackground) {
++ scoped_refptr<BitmapImage> image;
++ SkBitmap bitmap;
++ SkPixmap pixmap;
++ image = GetImage("/images/resources/sprite_dark_background.png");
++ bitmap = image->AsSkBitmapForCurrentFrame(kDoNotRespectImageOrientation);
++ bitmap.peekPixels(&pixmap);
++
++ EXPECT_EQ(
++ image_classifier()->Classify(pixmap, SkIRect::MakeXYWH(0, 0, 128, 24)),
++ DarkModeResult::kApplyFilter);
++
++ EXPECT_EQ(
++ image_classifier()->Classify(pixmap, SkIRect::MakeXYWH(0, 24, 128, 24)),
++ DarkModeResult::kDoNotApplyFilter);
++}
++
+ TEST_F(DarkModeImageClassifierTest, BlockSamples) {
+ SkBitmap bitmap;
+ SkPixmap pixmap;
+@@ -282,12 +334,13 @@ TEST_F(DarkModeImageClassifierTest, FeaturesAndClassification) {
+ EXPECT_NEAR(0.1875f, features.color_buckets_ratio, kEpsilon);
+ EXPECT_NEAR(0.0f, features.transparency_ratio, kEpsilon);
+ EXPECT_NEAR(0.0f, features.background_ratio, kEpsilon);
++ EXPECT_NEAR(0.3044f, features.high_luminance_ratio, kEpsilon);
+
+ // Test Case 2:
+ // Grayscale
+ // Color Buckets Ratio: Medium
+- // Decision Tree: Can't Decide
+- // Neural Network: Apply
++ // Decision Tree: Do Not Apply
++ // Neural Network: NA
+ image = GetImage("/images/resources/apng08-ref.png");
+ bitmap = image->AsSkBitmapForCurrentFrame(kDoNotRespectImageOrientation);
+ bitmap.peekPixels(&pixmap);
+@@ -298,16 +351,17 @@ TEST_F(DarkModeImageClassifierTest, FeaturesAndClassification) {
+ EXPECT_EQ(image_classifier()->ClassifyWithFeatures(features),
+ DarkModeResult::kDoNotApplyFilter);
+ EXPECT_EQ(image_classifier()->ClassifyUsingDecisionTree(features),
+- DarkModeResult::kNotClassified);
++ DarkModeResult::kDoNotApplyFilter);
+ EXPECT_FALSE(features.is_colorful);
+ EXPECT_NEAR(0.8125f, features.color_buckets_ratio, kEpsilon);
+ EXPECT_NEAR(0.446667f, features.transparency_ratio, kEpsilon);
+ EXPECT_NEAR(0.03f, features.background_ratio, kEpsilon);
++ EXPECT_NEAR(0.6144578f, features.high_luminance_ratio, kEpsilon);
+
+ // Test Case 3:
+ // Color
+ // Color Buckets Ratio: Low
+- // Decision Tree: Apply
++ // Decision Tree: Do Not Apply
+ // Neural Network: NA.
+ image = GetImage("/images/resources/twitter_favicon.ico");
+ bitmap = image->AsSkBitmapForCurrentFrame(kDoNotRespectImageOrientation);
+@@ -317,13 +371,14 @@ TEST_F(DarkModeImageClassifierTest, FeaturesAndClassification) {
+ SkIRect::MakeWH(image->width(), image->height()))
+ .value();
+ EXPECT_EQ(image_classifier()->ClassifyWithFeatures(features),
+- DarkModeResult::kApplyFilter);
++ DarkModeResult::kDoNotApplyFilter);
+ EXPECT_EQ(image_classifier()->ClassifyUsingDecisionTree(features),
+- DarkModeResult::kApplyFilter);
++ DarkModeResult::kDoNotApplyFilter);
+ EXPECT_TRUE(features.is_colorful);
+ EXPECT_NEAR(0.0002441f, features.color_buckets_ratio, kEpsilon);
+ EXPECT_NEAR(0.542092f, features.transparency_ratio, kEpsilon);
+ EXPECT_NEAR(0.1500000f, features.background_ratio, kEpsilon);
++ EXPECT_NEAR(1.0f, features.high_luminance_ratio, kEpsilon);
+
+ // Test Case 4:
+ // Color
+@@ -345,6 +400,7 @@ TEST_F(DarkModeImageClassifierTest, FeaturesAndClassification) {
+ EXPECT_NEAR(0.032959f, features.color_buckets_ratio, kEpsilon);
+ EXPECT_NEAR(0.0f, features.transparency_ratio, kEpsilon);
+ EXPECT_NEAR(0.0f, features.background_ratio, kEpsilon);
++ EXPECT_NEAR(0.33f, features.high_luminance_ratio, kEpsilon);
+
+ // Test Case 5:
+ // Color
+@@ -366,6 +422,7 @@ TEST_F(DarkModeImageClassifierTest, FeaturesAndClassification) {
+ EXPECT_NEAR(0.0151367f, features.color_buckets_ratio, kEpsilon);
+ EXPECT_NEAR(0.0f, features.transparency_ratio, kEpsilon);
+ EXPECT_NEAR(0.0f, features.background_ratio, kEpsilon);
++ EXPECT_NEAR(0.9255555272102356f, features.high_luminance_ratio, kEpsilon);
+ }
+
+ } // namespace blink
+diff --git a/third_party/blink/web_tests/images/resources/sprite_dark_background.png b/third_party/blink/web_tests/images/resources/sprite_dark_background.png
+new file mode 100644
+index 000000000000..cc67ef3e897d
+Binary files /dev/null and b/third_party/blink/web_tests/images/resources/sprite_dark_background.png differ
+diff --git a/third_party/blink/web_tests/images/resources/sprite_light_background.png b/third_party/blink/web_tests/images/resources/sprite_light_background.png
+new file mode 100644
+index 000000000000..3977af4d55fb
+Binary files /dev/null and b/third_party/blink/web_tests/images/resources/sprite_light_background.png differ
+diff --git a/third_party/blink/web_tests/images/resources/sprite_transparent_background.png b/third_party/blink/web_tests/images/resources/sprite_transparent_background.png
+new file mode 100644
+index 000000000000..df08f2291eb9
+Binary files /dev/null and b/third_party/blink/web_tests/images/resources/sprite_transparent_background.png differ
diff --git a/chromium-148-Add-saturation-feature-for-dark-mode-image-classification.patch b/chromium-148-Add-saturation-feature-for-dark-mode-image-classification.patch
new file mode 100644
index 0000000..f7cc6cf
--- /dev/null
+++ b/chromium-148-Add-saturation-feature-for-dark-mode-image-classification.patch
@@ -0,0 +1,853 @@
+commit 90fda3febeb4e7391013da953fffe4a5ccbd579c
+Author: Prashant Nevase <pnevase@microsoft.com>
+Date: Thu May 14 06:54:05 2026 -0700
+
+ Reland "Add saturation feature for dark mode image classification."
+
+ This is a reland of commit 320dcd441b7661859b2e6ab08382766810ee9e68
+
+ Original change's description:
+ > Add saturation feature for dark mode image classification.
+ >
+ > Images with vivid/saturated colors (e.g. country flags. logos) were
+ > getting inverted, making them lose the meaning of colors used. This
+ > cl adds saturation ratio feature which helps classify these images
+ > correctly. This uses little stricter ratio (0.3), so comparatively
+ > less images are considered for further classification.
+ >
+ > - Images with a limited palette dominated by highly saturated colors
+ > are skipped.
+ >
+ > - Images with a mostly-light field and a smaller saturated region are
+ > skipped.
+ >
+ > This new feature corrects the classification of images having gradient
+ > vivid colors.
+ >
+ > Bug: 449909524
+ > Change-Id: I80fb34c028db23b667f0c66b3431522a3e31dd86
+ > Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7836698
+ > Commit-Queue: Stephen Chenney <schenney@chromium.org>
+ > Reviewed-by: Stephen Chenney <schenney@chromium.org>
+ > Auto-Submit: Prashant Nevase <pnevase@microsoft.com>
+ > Cr-Commit-Position: refs/heads/main@{#1629379}
+
+ Bug: 449909524
+ Change-Id: Ic13f611b6e3a6107b13d0db94938c98c5e3d83ce
+ Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7844414
+ Reviewed-by: Stephen Chenney <schenney@chromium.org>
+ Auto-Submit: Prashant Nevase <pnevase@microsoft.com>
+ Commit-Queue: Prashant Nevase <pnevase@microsoft.com>
+ Cr-Commit-Position: refs/heads/main@{#1630601}
+
+diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn
+index 374d5119f853..89c70520d6b0 100644
+--- a/third_party/blink/renderer/platform/BUILD.gn
++++ b/third_party/blink/renderer/platform/BUILD.gn
+@@ -2640,6 +2640,9 @@ group("blink_platform_unittests_data") {
+ "//third_party/blink/web_tests/images/bmp-suite/",
+ "//third_party/blink/web_tests/images/jpeg-suite/",
+
++ # Required by dark mode image classifier tests.
++ "//third_party/blink/web_tests/dark-mode/images/resources/",
++
+ # Required by some font tests.
+ "//third_party/blink/web_tests/external/wpt/fonts/",
+ "//third_party/blink/web_tests/external/wpt/css/css-fonts/resources",
+diff --git a/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.cc b/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.cc
+index 104a99c35aab..0111db051cca 100644
+--- a/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.cc
++++ b/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.cc
+@@ -4,6 +4,7 @@
+
+ #include "third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.h"
+
++#include <algorithm>
+ #include <array>
+ #include <optional>
+ #include <set>
+@@ -22,6 +23,12 @@ const float kMinOpaquePixelPercentageForForeground = 0.2;
+ // Color is considered light if its luma is above this threshold.
+ constexpr int kHighLightnessThreshold = 96;
+
++// Per-pixel chroma (max channel - min channel, in 0..255) at or above which
++// the pixel is considered vivid / highly saturated. Tuned to count both
++// fully saturated colors and their anti-aliased fringes, while excluding
++// typical photographic colors which usually have chroma below 60.
++constexpr int kHighSaturationThreshold = 80;
++
+ // Decision tree thresholds for classifying images
+
+ // Lower and upper color thresholds for grayscale and color images.
+@@ -36,6 +43,16 @@ constexpr float kFeatureTransparencyRatioThreshold = 0.4f;
+ // Luminance ratio threshold above which the image is classified as light.
+ constexpr float kFeatureHighLuminanceThreshold = 0.5f;
+
++// Saturated pixel ratio threshold above which a low-color-bucket image is
++// considered to have a vivid-color theme and is skipped from inversion.
++constexpr float kFeatureHighSaturationRatioThreshold = 0.3f;
++
++// Lower saturation threshold used together with a high luminance gate to
++// catch images with a mostly-light field and a smaller saturated region,
++// where the dominant light pixels pull the overall saturated_pixel_ratio
++// below kFeatureHighSaturationRatioThreshold.
++constexpr float kFeatureLowSaturationRatioThreshold = 0.1f;
++
+ bool IsColorGray(const SkColor& color) {
+ return abs(static_cast<int>(SkColorGetR(color)) -
+ static_cast<int>(SkColorGetG(color))) +
+@@ -56,6 +73,17 @@ bool IsColorLight(const SkColor& color) {
+ return luma >= kHighLightnessThreshold;
+ }
+
++bool IsColorSaturated(const SkColor& color) {
++ // Approximate HSV chroma: max(R,G,B) - min(R,G,B). A high value indicates
++ // a vivid/saturated color, while neutral grays and pastels have a low
++ // value.
++ int r = SkColorGetR(color);
++ int g = SkColorGetG(color);
++ int b = SkColorGetB(color);
++ int chroma = std::max({r, g, b}) - std::min({r, g, b});
++ return chroma >= kHighSaturationThreshold;
++}
++
+ } // namespace
+
+ DarkModeImageClassifier::DarkModeImageClassifier() = default;
+@@ -200,6 +228,7 @@ DarkModeImageClassifier::Features DarkModeImageClassifier::ComputeFeatures(
+
+ int color_pixels = 0;
+ int high_luma_pixels = 0;
++ int saturated_pixels = 0;
+ for (const SkColor& sample : sampled_pixels) {
+ if (!IsColorGray(sample)) {
+ color_pixels++;
+@@ -208,6 +237,10 @@ DarkModeImageClassifier::Features DarkModeImageClassifier::ComputeFeatures(
+ if (IsColorLight(sample)) {
+ high_luma_pixels++;
+ }
++
++ if (IsColorSaturated(sample)) {
++ saturated_pixels++;
++ }
+ }
+
+ ColorMode color_mode = (color_pixels > samples_count / 100)
+@@ -222,6 +255,8 @@ DarkModeImageClassifier::Features DarkModeImageClassifier::ComputeFeatures(
+ features.background_ratio = background_ratio;
+ features.high_luminance_ratio =
+ static_cast<float>(high_luma_pixels) / samples_count;
++ features.saturated_pixel_ratio =
++ static_cast<float>(saturated_pixels) / samples_count;
+
+ return features;
+ }
+@@ -294,6 +329,31 @@ DarkModeResult DarkModeImageClassifier::ClassifyUsingDecisionTree(
+ return DarkModeResult::kDoNotApplyFilter;
+ }
+
++ // Skip filtering for images with a limited palette dominated by highly
++ // saturated colors. Inverting such images would replace their semantic
++ // colors with the complements, which is usually wrong (a saturated red
++ // should not become teal). Use the upper bucket threshold to remain
++ // robust to compression artifacts that can inflate the bucket count.
++ if (features.is_colorful &&
++ features.color_buckets_ratio <
++ kFeatureHighColorCountThreshold[features.is_colorful] &&
++ features.saturated_pixel_ratio > kFeatureHighSaturationRatioThreshold) {
++ return DarkModeResult::kDoNotApplyFilter;
++ }
++
++ // Also skip images with a mostly-light field and a smaller saturated
++ // region. These have a low overall saturated_pixel_ratio because light
++ // pixels dominate, but the combination of few colors, high luminance, and
++ // some saturated content indicates an asset whose colors carry meaning
++ // and should be preserved rather than inverted.
++ if (features.is_colorful &&
++ features.color_buckets_ratio <
++ kFeatureHighColorCountThreshold[features.is_colorful] &&
++ features.high_luminance_ratio > kFeatureHighLuminanceThreshold &&
++ features.saturated_pixel_ratio > kFeatureLowSaturationRatioThreshold) {
++ return DarkModeResult::kDoNotApplyFilter;
++ }
++
+ // Very few colors means it's not a photo, apply the filter.
+ if (features.color_buckets_ratio <
+ kFeatureLowColorCountThreshold[features.is_colorful]) {
+diff --git a/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.h b/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.h
+index fcf37ba4b054..e04a437d223a 100644
+--- a/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.h
++++ b/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.h
+@@ -42,6 +42,11 @@ class PLATFORM_EXPORT DarkModeImageClassifier {
+
+ // Ratio of high luminance pixels to all sampled pixels in the image.
+ float high_luminance_ratio;
++
++ // Ratio of highly saturated (vivid) pixels to all sampled pixels in the
++ // image. Used to detect images dominated by vivid flat colors whose
++ // colors carry meaning and should be preserved rather than inverted.
++ float saturated_pixel_ratio;
+ };
+
+ DarkModeResult Classify(const SkPixmap& pixmap, const SkIRect& src) const;
+diff --git a/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier_test.cc b/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier_test.cc
+index e634550498a7..6ec427db1d72 100644
+--- a/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier_test.cc
++++ b/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier_test.cc
+@@ -13,13 +13,29 @@
+ #include "third_party/blink/renderer/platform/testing/testing_platform_support.h"
+ #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
+ #include "third_party/blink/renderer/platform/wtf/shared_buffer.h"
++#include "third_party/skia/include/core/SkBitmap.h"
+ #include "third_party/skia/include/core/SkCanvas.h"
++#include "third_party/skia/include/core/SkColor.h"
+
+ namespace blink {
+ namespace {
+
+ const float kEpsilon = 0.00001;
+
++SkBitmap MakeStripedBitmap(SkColor background,
++ SkColor foreground,
++ int foreground_x,
++ int foreground_width) {
++ SkBitmap bitmap;
++ bitmap.allocN32Pixels(100, 100);
++ bitmap.eraseColor(background);
++ if (foreground_width > 0) {
++ bitmap.erase(foreground,
++ SkIRect::MakeXYWH(foreground_x, 0, foreground_width, 100));
++ }
++ return bitmap;
++}
++
+ } // namespace
+
+ class DarkModeImageClassifierTest : public testing::Test {
+@@ -405,7 +421,7 @@ TEST_F(DarkModeImageClassifierTest, FeaturesAndClassification) {
+ // Test Case 5:
+ // Color
+ // Color Buckets Ratio: Medium
+- // Decision Tree: Apply
++ // Decision Tree: Do Not Apply
+ // Neural Network: NA.
+ image = GetImage("/images/resources/ycbcr-444-float.jpg");
+ bitmap = image->AsSkBitmapForCurrentFrame(kDoNotRespectImageOrientation);
+@@ -415,9 +431,9 @@ TEST_F(DarkModeImageClassifierTest, FeaturesAndClassification) {
+ SkIRect::MakeWH(image->width(), image->height()))
+ .value();
+ EXPECT_EQ(image_classifier()->ClassifyWithFeatures(features),
+- DarkModeResult::kApplyFilter);
++ DarkModeResult::kDoNotApplyFilter);
+ EXPECT_EQ(image_classifier()->ClassifyUsingDecisionTree(features),
+- DarkModeResult::kApplyFilter);
++ DarkModeResult::kDoNotApplyFilter);
+ EXPECT_TRUE(features.is_colorful);
+ EXPECT_NEAR(0.0151367f, features.color_buckets_ratio, kEpsilon);
+ EXPECT_NEAR(0.0f, features.transparency_ratio, kEpsilon);
+@@ -425,4 +441,55 @@ TEST_F(DarkModeImageClassifierTest, FeaturesAndClassification) {
+ EXPECT_NEAR(0.9255555272102356f, features.high_luminance_ratio, kEpsilon);
+ }
+
++TEST_F(DarkModeImageClassifierTest, ImageWithHighlySaturatedColors) {
++ scoped_refptr<BitmapImage> image =
++ GetImage("/dark-mode/images/resources/country-flags-sprite.png");
++ SkBitmap bitmap =
++ image->AsSkBitmapForCurrentFrame(kDoNotRespectImageOrientation);
++ SkPixmap pixmap;
++ bitmap.peekPixels(&pixmap);
++
++ EXPECT_EQ(
++ image_classifier()->Classify(pixmap, SkIRect::MakeXYWH(0, 192, 48, 32)),
++ DarkModeResult::kDoNotApplyFilter);
++
++ EXPECT_EQ(
++ image_classifier()->Classify(pixmap, SkIRect::MakeXYWH(0, 48, 48, 32)),
++ DarkModeResult::kDoNotApplyFilter);
++}
++
++TEST_F(DarkModeImageClassifierTest,
++ SyntheticImageWithTransparentBackgroundLightForeground) {
++ // Image with mostly-transparent background and predominantly light foreground
++ // pixels.
++ SkBitmap bitmap =
++ MakeStripedBitmap(SK_ColorTRANSPARENT, SK_ColorWHITE, 50, 50);
++ SkPixmap pixmap;
++ ASSERT_TRUE(bitmap.peekPixels(&pixmap));
++ EXPECT_EQ(image_classifier()->Classify(pixmap, bitmap.bounds()),
++ DarkModeResult::kDoNotApplyFilter);
++}
++
++TEST_F(DarkModeImageClassifierTest,
++ SyntheticImageWithFullySaturatedBackground) {
++ // Colorful, low-palette image with a saturated-dominant pixel distribution
++ // (e.g. dominated by vivid flat colors)
++ SkBitmap bitmap = MakeStripedBitmap(SK_ColorRED, SK_ColorRED, 0, 0);
++ SkPixmap pixmap;
++ ASSERT_TRUE(bitmap.peekPixels(&pixmap));
++ EXPECT_EQ(image_classifier()->Classify(pixmap, bitmap.bounds()),
++ DarkModeResult::kDoNotApplyFilter);
++}
++
++TEST_F(DarkModeImageClassifierTest,
++ SyntheticImageWithLightBackgroundAndSaturatedForeground) {
++ // Colorful, mostly-light image with a smaller saturated region (e.g.
++ // light-field image with a smaller area of vivid colors).
++ SkBitmap bitmap = MakeStripedBitmap(SK_ColorWHITE, SK_ColorRED, 0, 15);
++ SkPixmap pixmap;
++ ASSERT_TRUE(bitmap.peekPixels(&pixmap));
++ EXPECT_EQ(image_classifier()->Classify(pixmap, bitmap.bounds()),
++ DarkModeResult::kDoNotApplyFilter);
++}
++
+ } // namespace blink
+diff --git a/third_party/blink/web_tests/dark-mode/images/country-flags-expected.png b/third_party/blink/web_tests/dark-mode/images/country-flags-expected.png
+new file mode 100644
+index 000000000000..28cea1997bd1
+Binary files /dev/null and b/third_party/blink/web_tests/dark-mode/images/country-flags-expected.png differ
+diff --git a/third_party/blink/web_tests/dark-mode/images/country-flags.html b/third_party/blink/web_tests/dark-mode/images/country-flags.html
+new file mode 100644
+index 000000000000..86a8e139428a
+--- /dev/null
++++ b/third_party/blink/web_tests/dark-mode/images/country-flags.html
+@@ -0,0 +1,520 @@
++<!DOCTYPE html>
++<style>
++body { font: 12px system-ui, sans-serif; padding: 0px; }
++ul {
++ list-style: none;
++ padding: 0px;
++ display: grid;
++ grid-template-columns: repeat(16, max-content);
++ gap: 0px 0px;
++}
++li { display: flex; align-items: center; }
++.flag {
++ display: inline-block;
++ width: 32px;
++ height: 28px;
++ margin: 0px;
++ background-image: url('resources/country-flags-sprite.png');
++ background-repeat: no-repeat;
++}
++.flag-afghanistan { background-position: -0px -0px; }
++.flag-aland-islands { background-position: -48px -0px; }
++.flag-albania { background-position: -96px -0px; }
++.flag-algeria { background-position: -144px -0px; }
++.flag-american-samoa { background-position: -192px -0px; }
++.flag-andorra { background-position: -240px -0px; }
++.flag-angola { background-position: -288px -0px; }
++.flag-anguilla { background-position: -336px -0px; }
++.flag-antigua-and-barbuda { background-position: -384px -0px; }
++.flag-argentina { background-position: -432px -0px; }
++.flag-armenia { background-position: -480px -0px; }
++.flag-aruba { background-position: -528px -0px; }
++.flag-australia { background-position: -576px -0px; }
++.flag-austria { background-position: -624px -0px; }
++.flag-azerbaijan { background-position: -672px -0px; }
++.flag-bahrain { background-position: -720px -0px; }
++.flag-bangladesh { background-position: -0px -32px; }
++.flag-barbados { background-position: -48px -32px; }
++.flag-belarus { background-position: -96px -32px; }
++.flag-belgium { background-position: -144px -32px; }
++.flag-belize { background-position: -192px -32px; }
++.flag-benin { background-position: -240px -32px; }
++.flag-bermuda { background-position: -288px -32px; }
++.flag-bhutan { background-position: -336px -32px; }
++.flag-bolivia { background-position: -384px -32px; }
++.flag-bonaire { background-position: -432px -32px; }
++.flag-bosnia-and-herzegovina { background-position: -480px -32px; }
++.flag-botswana { background-position: -528px -32px; }
++.flag-bouvet-island { background-position: -576px -32px; }
++.flag-brazil { background-position: -624px -32px; }
++.flag-british-indian-ocean-territory {
++ background-position: -672px -32px;
++}
++.flag-british-virgin-islands { background-position: -720px -32px; }
++.flag-brunei { background-position: -0px -64px; }
++.flag-bulgaria { background-position: -48px -64px; }
++.flag-burkina-faso { background-position: -96px -64px; }
++.flag-burundi { background-position: -144px -64px; }
++.flag-cambodia { background-position: -192px -64px; }
++.flag-cameroon { background-position: -240px -64px; }
++.flag-canada { background-position: -288px -64px; }
++.flag-cape-verde { background-position: -336px -64px; }
++.flag-cayman-islands { background-position: -384px -64px; }
++.flag-central-african-republic { background-position: -432px -64px; }
++.flag-chad { background-position: -480px -64px; }
++.flag-chile { background-position: -528px -64px; }
++.flag-china { background-position: -576px -64px; }
++.flag-christmas-island { background-position: -624px -64px; }
++.flag-cocos-(keeling)-islands { background-position: -672px -64px; }
++.flag-colombia { background-position: -720px -64px; }
++.flag-comoros { background-position: -0px -96px; }
++.flag-cook-islands { background-position: -48px -96px; }
++.flag-costa-rica { background-position: -96px -96px; }
++.flag-croatia { background-position: -144px -96px; }
++.flag-cuba { background-position: -192px -96px; }
++.flag-curacao { background-position: -240px -96px; }
++.flag-cyprus { background-position: -288px -96px; }
++.flag-czech-republic { background-position: -336px -96px; }
++.flag-democratic-republic-of-the-congo {
++ background-position: -384px -96px;
++}
++.flag-denmark { background-position: -432px -96px; }
++.flag-djibouti { background-position: -480px -96px; }
++.flag-dominica { background-position: -528px -96px; }
++.flag-dominican-republic { background-position: -576px -96px; }
++.flag-ecuador { background-position: -624px -96px; }
++.flag-egypt { background-position: -672px -96px; }
++.flag-el-salvador { background-position: -720px -96px; }
++.flag-equatorial-guinea { background-position: -0px -128px; }
++.flag-eritrea { background-position: -48px -128px; }
++.flag-estonia { background-position: -96px -128px; }
++.flag-ethiopia { background-position: -144px -128px; }
++.flag-falkland-islands { background-position: -192px -128px; }
++.flag-faroe-islands { background-position: -240px -128px; }
++.flag-fiji { background-position: -288px -128px; }
++.flag-finland { background-position: -336px -128px; }
++.flag-france { background-position: -384px -128px; }
++.flag-french-guiana { background-position: -432px -128px; }
++.flag-french-polynesia { background-position: -480px -128px; }
++.flag-gabon { background-position: -528px -128px; }
++.flag-gambia { background-position: -576px -128px; }
++.flag-georgia { background-position: -624px -128px; }
++.flag-germany { background-position: -672px -128px; }
++.flag-ghana { background-position: -720px -128px; }
++.flag-gibraltar { background-position: -0px -160px; }
++.flag-greece { background-position: -48px -160px; }
++.flag-greenland { background-position: -96px -160px; }
++.flag-grenada { background-position: -144px -160px; }
++.flag-guadeloupe { background-position: -192px -160px; }
++.flag-guam { background-position: -240px -160px; }
++.flag-guatemala { background-position: -288px -160px; }
++.flag-guernsey { background-position: -336px -160px; }
++.flag-guinea-bissau { background-position: -384px -160px; }
++.flag-guinea { background-position: -432px -160px; }
++.flag-guyana { background-position: -480px -160px; }
++.flag-haiti { background-position: -528px -160px; }
++.flag-honduras { background-position: -576px -160px; }
++.flag-hong-kong { background-position: -624px -160px; }
++.flag-hungary { background-position: -672px -160px; }
++.flag-iceland { background-position: -720px -160px; }
++.flag-india { background-position: -0px -192px; }
++.flag-indonesia { background-position: -48px -192px; }
++.flag-iran { background-position: -96px -192px; }
++.flag-iraq { background-position: -144px -192px; }
++.flag-ireland { background-position: -192px -192px; }
++.flag-isle-of-man { background-position: -240px -192px; }
++.flag-israel { background-position: -288px -192px; }
++.flag-italy { background-position: -336px -192px; }
++.flag-ivory-coast { background-position: -384px -192px; }
++.flag-jamaica { background-position: -432px -192px; }
++.flag-japan { background-position: -480px -192px; }
++.flag-jersey { background-position: -528px -192px; }
++.flag-jordan { background-position: -576px -192px; }
++.flag-kazakhstan { background-position: -624px -192px; }
++.flag-kenya { background-position: -672px -192px; }
++.flag-kiribati { background-position: -720px -192px; }
++.flag-kosovo { background-position: -0px -224px; }
++.flag-kuwait { background-position: -48px -224px; }
++.flag-kyrgyzstan { background-position: -96px -224px; }
++.flag-laos { background-position: -144px -224px; }
++.flag-latvia { background-position: -192px -224px; }
++.flag-lebanon { background-position: -240px -224px; }
++.flag-lesotho { background-position: -288px -224px; }
++.flag-liberia { background-position: -336px -224px; }
++.flag-libya { background-position: -384px -224px; }
++.flag-liechtenstein { background-position: -432px -224px; }
++.flag-lithuania { background-position: -480px -224px; }
++.flag-luxembourg { background-position: -528px -224px; }
++.flag-macau { background-position: -576px -224px; }
++.flag-madagascar { background-position: -624px -224px; }
++.flag-malawi { background-position: -672px -224px; }
++.flag-malaysia { background-position: -720px -224px; }
++.flag-maldives { background-position: -0px -256px; }
++.flag-mali { background-position: -48px -256px; }
++.flag-malta { background-position: -96px -256px; }
++.flag-marshall-islands { background-position: -144px -256px; }
++.flag-martinique { background-position: -192px -256px; }
++.flag-mauritania { background-position: -240px -256px; }
++.flag-mauritius { background-position: -288px -256px; }
++.flag-mayotte { background-position: -336px -256px; }
++.flag-mexico { background-position: -384px -256px; }
++.flag-micronesia { background-position: -432px -256px; }
++.flag-moldova { background-position: -480px -256px; }
++.flag-monaco { background-position: -528px -256px; }
++.flag-mongolia { background-position: -576px -256px; }
++.flag-montenegro { background-position: -624px -256px; }
++.flag-montserrat { background-position: -672px -256px; }
++.flag-morocco { background-position: -720px -256px; }
++.flag-mozambique { background-position: -0px -288px; }
++.flag-myanmar-(burma) { background-position: -48px -288px; }
++.flag-namibia { background-position: -96px -288px; }
++.flag-nauru { background-position: -144px -288px; }
++.flag-nepal { background-position: -192px -288px; }
++.flag-netherlands { background-position: -240px -288px; }
++.flag-new-caledonia { background-position: -288px -288px; }
++.flag-new-zealand { background-position: -336px -288px; }
++.flag-nicaragua { background-position: -384px -288px; }
++.flag-niger { background-position: -432px -288px; }
++.flag-nigeria { background-position: -480px -288px; }
++.flag-niue { background-position: -528px -288px; }
++.flag-norfolk-island { background-position: -576px -288px; }
++.flag-north-korea { background-position: -624px -288px; }
++.flag-northern-mariana-islands { background-position: -672px -288px; }
++.flag-norway { background-position: -720px -288px; }
++.flag-oman { background-position: -0px -320px; }
++.flag-pakistan { background-position: -48px -320px; }
++.flag-palau { background-position: -96px -320px; }
++.flag-palestine { background-position: -144px -320px; }
++.flag-panama { background-position: -192px -320px; }
++.flag-papua-new-guinea { background-position: -240px -320px; }
++.flag-paraguay { background-position: -288px -320px; }
++.flag-peru { background-position: -336px -320px; }
++.flag-philippines { background-position: -384px -320px; }
++.flag-pitcairn-islands { background-position: -432px -320px; }
++.flag-poland { background-position: -480px -320px; }
++.flag-portugal { background-position: -528px -320px; }
++.flag-puerto-rico { background-position: -576px -320px; }
++.flag-qatar { background-position: -624px -320px; }
++.flag-republic-of-the-congo { background-position: -672px -320px; }
++.flag-reunion { background-position: -720px -320px; }
++.flag-romania { background-position: -0px -352px; }
++.flag-russia { background-position: -48px -352px; }
++.flag-rwanda { background-position: -96px -352px; }
++.flag-saint-barthelemy { background-position: -144px -352px; }
++.flag-saint-helena { background-position: -192px -352px; }
++.flag-saint-kitts-and-nevis { background-position: -240px -352px; }
++.flag-saint-lucia { background-position: -288px -352px; }
++.flag-saint-martin { background-position: -336px -352px; }
++.flag-saint-pierre-and-miquelon { background-position: -384px -352px; }
++.flag-saint-vincent-and-the-grenadines {
++ background-position: -432px -352px;
++}
++.flag-samoa { background-position: -480px -352px; }
++.flag-san-marino { background-position: -528px -352px; }
++.flag-sao-tome-and-principe { background-position: -576px -352px; }
++.flag-saudi-arabia { background-position: -624px -352px; }
++.flag-senegal { background-position: -672px -352px; }
++.flag-serbia { background-position: -720px -352px; }
++.flag-seychelles { background-position: -0px -384px; }
++.flag-sierra-leone { background-position: -48px -384px; }
++.flag-singapore { background-position: -96px -384px; }
++.flag-sint-maarten { background-position: -144px -384px; }
++.flag-slovakia { background-position: -192px -384px; }
++.flag-slovenia { background-position: -240px -384px; }
++.flag-solomon-islands { background-position: -288px -384px; }
++.flag-somalia { background-position: -336px -384px; }
++.flag-south-africa { background-position: -384px -384px; }
++.flag-south-georgia-and-the-south-sandwich-islands {
++ background-position: -432px -384px;
++}
++.flag-south-korea { background-position: -480px -384px; }
++.flag-south-sudan { background-position: -528px -384px; }
++.flag-spain { background-position: -576px -384px; }
++.flag-sri-lanka { background-position: -624px -384px; }
++.flag-sudan { background-position: -672px -384px; }
++.flag-suriname { background-position: -720px -384px; }
++.flag-svalbard-and-jan-mayen { background-position: -0px -416px; }
++.flag-sweden { background-position: -48px -416px; }
++.flag-switzerland { background-position: -96px -416px; }
++.flag-syria { background-position: -144px -416px; }
++.flag-taiwan { background-position: -192px -416px; }
++.flag-tajikistan { background-position: -240px -416px; }
++.flag-tanzania { background-position: -288px -416px; }
++.flag-thailand { background-position: -336px -416px; }
++.flag-the-bahamas { background-position: -384px -416px; }
++.flag-timor-leste { background-position: -432px -416px; }
++.flag-togo { background-position: -480px -416px; }
++.flag-tokelau { background-position: -528px -416px; }
++.flag-tonga { background-position: -576px -416px; }
++.flag-trinidad-and-tobago { background-position: -624px -416px; }
++.flag-tunisia { background-position: -672px -416px; }
++.flag-turkey { background-position: -720px -416px; }
++.flag-turkmenistan { background-position: -0px -448px; }
++.flag-turks-and-caicos-islands { background-position: -48px -448px; }
++.flag-tuvalu { background-position: -96px -448px; }
++.flag-uganda { background-position: -144px -448px; }
++.flag-ukraine { background-position: -192px -448px; }
++.flag-united-arab-emirates { background-position: -240px -448px; }
++.flag-united-kingdom { background-position: -288px -448px; }
++.flag-united-states-of-america { background-position: -336px -448px; }
++.flag-uruguay { background-position: -384px -448px; }
++.flag-us-virgin-islands { background-position: -432px -448px; }
++.flag-uzbekistan { background-position: -480px -448px; }
++.flag-vanuatu { background-position: -528px -448px; }
++.flag-vatican-city { background-position: -576px -448px; }
++.flag-venezuela { background-position: -624px -448px; }
++.flag-vietnam { background-position: -672px -448px; }
++.flag-wallis-and-futuna { background-position: -720px -448px; }
++.flag-western-sahara { background-position: -0px -480px; }
++.flag-yemen { background-position: -48px -480px; }
++.flag-zambia { background-position: -96px -480px; }
++.flag-zimbabwe { background-position: -144px -480px; }
++</style>
++
++
++<ul>
++ <li><span class="flag flag-afghanistan"></span></li>
++ <li><span class="flag flag-aland-islands"></span></li>
++ <li><span class="flag flag-albania"></span></li>
++ <li><span class="flag flag-algeria"></span></li>
++ <li><span class="flag flag-american-samoa"></span></li>
++ <li><span class="flag flag-andorra"></span></li>
++ <li><span class="flag flag-angola"></span></li>
++ <li><span class="flag flag-anguilla"></span></li>
++ <li><span class="flag flag-antigua-and-barbuda"></span></li>
++ <li><span class="flag flag-argentina"></span></li>
++ <li><span class="flag flag-armenia"></span></li>
++ <li><span class="flag flag-aruba"></span></li>
++ <li><span class="flag flag-australia"></span></li>
++ <li><span class="flag flag-austria"></span></li>
++ <li><span class="flag flag-azerbaijan"></span></li>
++ <li><span class="flag flag-bahrain"></span></li>
++ <li><span class="flag flag-bangladesh"></span></li>
++ <li><span class="flag flag-barbados"></span></li>
++ <li><span class="flag flag-belarus"></span></li>
++ <li><span class="flag flag-belgium"></span></li>
++ <li><span class="flag flag-belize"></span></li>
++ <li><span class="flag flag-benin"></span></li>
++ <li><span class="flag flag-bermuda"></span></li>
++ <li><span class="flag flag-bhutan"></span></li>
++ <li><span class="flag flag-bolivia"></span></li>
++ <li><span class="flag flag-bonaire"></span></li>
++ <li><span class="flag flag-bosnia-and-herzegovina"></span></li>
++ <li><span class="flag flag-botswana"></span></li>
++ <li><span class="flag flag-bouvet-island"></span></li>
++ <li><span class="flag flag-brazil"></span></li>
++ <li><span class="flag flag-british-indian-ocean-territory"></span></li>
++ <li><span class="flag flag-british-virgin-islands"></span></li>
++ <li><span class="flag flag-brunei"></span></li>
++ <li><span class="flag flag-bulgaria"></span></li>
++ <li><span class="flag flag-burkina-faso"></span></li>
++ <li><span class="flag flag-burundi"></span></li>
++ <li><span class="flag flag-cambodia"></span></li>
++ <li><span class="flag flag-cameroon"></span></li>
++ <li><span class="flag flag-canada"></span></li>
++ <li><span class="flag flag-cape-verde"></span></li>
++ <li><span class="flag flag-cayman-islands"></span></li>
++ <li><span class="flag flag-central-african-republic"></span></li>
++ <li><span class="flag flag-chad"></span></li>
++ <li><span class="flag flag-chile"></span></li>
++ <li><span class="flag flag-china"></span></li>
++ <li><span class="flag flag-christmas-island"></span></li>
++ <li><span class="flag flag-cocos-(keeling)-islands"></span></li>
++ <li><span class="flag flag-colombia"></span></li>
++ <li><span class="flag flag-comoros"></span></li>
++ <li><span class="flag flag-cook-islands"></span></li>
++ <li><span class="flag flag-costa-rica"></span></li>
++ <li><span class="flag flag-croatia"></span></li>
++ <li><span class="flag flag-cuba"></span></li>
++ <li><span class="flag flag-curacao"></span></li>
++ <li><span class="flag flag-cyprus"></span></li>
++ <li><span class="flag flag-czech-republic"></span></li>
++ <li><span class="flag flag-democratic-republic-of-the-congo"></span></li>
++ <li><span class="flag flag-denmark"></span></li>
++ <li><span class="flag flag-djibouti"></span></li>
++ <li><span class="flag flag-dominica"></span></li>
++ <li><span class="flag flag-dominican-republic"></span></li>
++ <li><span class="flag flag-ecuador"></span></li>
++ <li><span class="flag flag-egypt"></span></li>
++ <li><span class="flag flag-el-salvador"></span></li>
++ <li><span class="flag flag-equatorial-guinea"></span></li>
++ <li><span class="flag flag-eritrea"></span></li>
++ <li><span class="flag flag-estonia"></span></li>
++ <li><span class="flag flag-ethiopia"></span></li>
++ <li><span class="flag flag-falkland-islands"></span></li>
++ <li><span class="flag flag-faroe-islands"></span></li>
++ <li><span class="flag flag-fiji"></span></li>
++ <li><span class="flag flag-finland"></span></li>
++ <li><span class="flag flag-france"></span></li>
++ <li><span class="flag flag-french-guiana"></span></li>
++ <li><span class="flag flag-french-polynesia"></span></li>
++ <li><span class="flag flag-gabon"></span></li>
++ <li><span class="flag flag-gambia"></span></li>
++ <li><span class="flag flag-georgia"></span></li>
++ <li><span class="flag flag-germany"></span></li>
++ <li><span class="flag flag-ghana"></span></li>
++ <li><span class="flag flag-gibraltar"></span></li>
++ <li><span class="flag flag-greece"></span></li>
++ <li><span class="flag flag-greenland"></span></li>
++ <li><span class="flag flag-grenada"></span></li>
++ <li><span class="flag flag-guadeloupe"></span></li>
++ <li><span class="flag flag-guam"></span></li>
++ <li><span class="flag flag-guatemala"></span></li>
++ <li><span class="flag flag-guernsey"></span></li>
++ <li><span class="flag flag-guinea-bissau"></span></li>
++ <li><span class="flag flag-guinea"></span></li>
++ <li><span class="flag flag-guyana"></span></li>
++ <li><span class="flag flag-haiti"></span></li>
++ <li><span class="flag flag-honduras"></span></li>
++ <li><span class="flag flag-hong-kong"></span></li>
++ <li><span class="flag flag-hungary"></span></li>
++ <li><span class="flag flag-iceland"></span></li>
++ <li><span class="flag flag-india"></span></li>
++ <li><span class="flag flag-indonesia"></span></li>
++ <li><span class="flag flag-iran"></span></li>
++ <li><span class="flag flag-iraq"></span></li>
++ <li><span class="flag flag-ireland"></span></li>
++ <li><span class="flag flag-isle-of-man"></span></li>
++ <li><span class="flag flag-israel"></span></li>
++ <li><span class="flag flag-italy"></span></li>
++ <li><span class="flag flag-ivory-coast"></span></li>
++ <li><span class="flag flag-jamaica"></span></li>
++ <li><span class="flag flag-japan"></span></li>
++ <li><span class="flag flag-jersey"></span></li>
++ <li><span class="flag flag-jordan"></span></li>
++ <li><span class="flag flag-kazakhstan"></span></li>
++ <li><span class="flag flag-kenya"></span></li>
++ <li><span class="flag flag-kiribati"></span></li>
++ <li><span class="flag flag-kosovo"></span></li>
++ <li><span class="flag flag-kuwait"></span></li>
++ <li><span class="flag flag-kyrgyzstan"></span></li>
++ <li><span class="flag flag-laos"></span></li>
++ <li><span class="flag flag-latvia"></span></li>
++ <li><span class="flag flag-lebanon"></span></li>
++ <li><span class="flag flag-lesotho"></span></li>
++ <li><span class="flag flag-liberia"></span></li>
++ <li><span class="flag flag-libya"></span></li>
++ <li><span class="flag flag-liechtenstein"></span></li>
++ <li><span class="flag flag-lithuania"></span></li>
++ <li><span class="flag flag-luxembourg"></span></li>
++ <li><span class="flag flag-macau"></span></li>
++ <li><span class="flag flag-madagascar"></span></li>
++ <li><span class="flag flag-malawi"></span></li>
++ <li><span class="flag flag-malaysia"></span></li>
++ <li><span class="flag flag-maldives"></span></li>
++ <li><span class="flag flag-mali"></span></li>
++ <li><span class="flag flag-malta"></span></li>
++ <li><span class="flag flag-marshall-islands"></span></li>
++ <li><span class="flag flag-martinique"></span></li>
++ <li><span class="flag flag-mauritania"></span></li>
++ <li><span class="flag flag-mauritius"></span></li>
++ <li><span class="flag flag-mayotte"></span></li>
++ <li><span class="flag flag-mexico"></span></li>
++ <li><span class="flag flag-micronesia"></span></li>
++ <li><span class="flag flag-moldova"></span></li>
++ <li><span class="flag flag-monaco"></span></li>
++ <li><span class="flag flag-mongolia"></span></li>
++ <li><span class="flag flag-montenegro"></span></li>
++ <li><span class="flag flag-montserrat"></span></li>
++ <li><span class="flag flag-morocco"></span></li>
++ <li><span class="flag flag-mozambique"></span></li>
++ <li><span class="flag flag-myanmar-(burma)"></span></li>
++ <li><span class="flag flag-namibia"></span></li>
++ <li><span class="flag flag-nauru"></span></li>
++ <li><span class="flag flag-nepal"></span></li>
++ <li><span class="flag flag-netherlands"></span></li>
++ <li><span class="flag flag-new-caledonia"></span></li>
++ <li><span class="flag flag-new-zealand"></span></li>
++ <li><span class="flag flag-nicaragua"></span></li>
++ <li><span class="flag flag-niger"></span></li>
++ <li><span class="flag flag-nigeria"></span></li>
++ <li><span class="flag flag-niue"></span></li>
++ <li><span class="flag flag-norfolk-island"></span></li>
++ <li><span class="flag flag-north-korea"></span></li>
++ <li><span class="flag flag-northern-mariana-islands"></span></li>
++ <li><span class="flag flag-norway"></span></li>
++ <li><span class="flag flag-oman"></span></li>
++ <li><span class="flag flag-pakistan"></span></li>
++ <li><span class="flag flag-palau"></span></li>
++ <li><span class="flag flag-palestine"></span></li>
++ <li><span class="flag flag-panama"></span></li>
++ <li><span class="flag flag-papua-new-guinea"></span></li>
++ <li><span class="flag flag-paraguay"></span></li>
++ <li><span class="flag flag-peru"></span></li>
++ <li><span class="flag flag-philippines"></span></li>
++ <li><span class="flag flag-pitcairn-islands"></span></li>
++ <li><span class="flag flag-poland"></span></li>
++ <li><span class="flag flag-portugal"></span></li>
++ <li><span class="flag flag-puerto-rico"></span></li>
++ <li><span class="flag flag-qatar"></span></li>
++ <li><span class="flag flag-republic-of-the-congo"></span></li>
++ <li><span class="flag flag-reunion"></span></li>
++ <li><span class="flag flag-romania"></span></li>
++ <li><span class="flag flag-russia"></span></li>
++ <li><span class="flag flag-rwanda"></span></li>
++ <li><span class="flag flag-saint-barthelemy"></span></li>
++ <li><span class="flag flag-saint-helena"></span></li>
++ <li><span class="flag flag-saint-kitts-and-nevis"></span></li>
++ <li><span class="flag flag-saint-lucia"></span></li>
++ <li><span class="flag flag-saint-martin"></span></li>
++ <li><span class="flag flag-saint-pierre-and-miquelon"></span></li>
++ <li><span class="flag flag-saint-vincent-and-the-grenadines"></span></li>
++ <li><span class="flag flag-samoa"></span></li>
++ <li><span class="flag flag-san-marino"></span></li>
++ <li><span class="flag flag-sao-tome-and-principe"></span></li>
++ <li><span class="flag flag-saudi-arabia"></span></li>
++ <li><span class="flag flag-senegal"></span></li>
++ <li><span class="flag flag-serbia"></span></li>
++ <li><span class="flag flag-seychelles"></span></li>
++ <li><span class="flag flag-sierra-leone"></span></li>
++ <li><span class="flag flag-singapore"></span></li>
++ <li><span class="flag flag-sint-maarten"></span></li>
++ <li><span class="flag flag-slovakia"></span></li>
++ <li><span class="flag flag-slovenia"></span></li>
++ <li><span class="flag flag-solomon-islands"></span></li>
++ <li><span class="flag flag-somalia"></span></li>
++ <li><span class="flag flag-south-africa"></span></li>
++ <li><span class="flag flag-south-georgia-and-the-south-sandwich-islands"></span></li>
++ <li><span class="flag flag-south-korea"></span></li>
++ <li><span class="flag flag-south-sudan"></span></li>
++ <li><span class="flag flag-spain"></span></li>
++ <li><span class="flag flag-sri-lanka"></span></li>
++ <li><span class="flag flag-sudan"></span></li>
++ <li><span class="flag flag-suriname"></span></li>
++ <li><span class="flag flag-svalbard-and-jan-mayen"></span></li>
++ <li><span class="flag flag-sweden"></span></li>
++ <li><span class="flag flag-switzerland"></span></li>
++ <li><span class="flag flag-syria"></span></li>
++ <li><span class="flag flag-taiwan"></span></li>
++ <li><span class="flag flag-tajikistan"></span></li>
++ <li><span class="flag flag-tanzania"></span></li>
++ <li><span class="flag flag-thailand"></span></li>
++ <li><span class="flag flag-the-bahamas"></span></li>
++ <li><span class="flag flag-timor-leste"></span></li>
++ <li><span class="flag flag-togo"></span></li>
++ <li><span class="flag flag-tokelau"></span></li>
++ <li><span class="flag flag-tonga"></span></li>
++ <li><span class="flag flag-trinidad-and-tobago"></span></li>
++ <li><span class="flag flag-tunisia"></span></li>
++ <li><span class="flag flag-turkey"></span></li>
++ <li><span class="flag flag-turkmenistan"></span></li>
++ <li><span class="flag flag-turks-and-caicos-islands"></span></li>
++ <li><span class="flag flag-tuvalu"></span></li>
++ <li><span class="flag flag-uganda"></span></li>
++ <li><span class="flag flag-ukraine"></span></li>
++ <li><span class="flag flag-united-arab-emirates"></span></li>
++ <li><span class="flag flag-united-kingdom"></span></li>
++ <li><span class="flag flag-united-states-of-america"></span></li>
++ <li><span class="flag flag-uruguay"></span></li>
++ <li><span class="flag flag-us-virgin-islands"></span></li>
++ <li><span class="flag flag-uzbekistan"></span></li>
++ <li><span class="flag flag-vanuatu"></span></li>
++ <li><span class="flag flag-vatican-city"></span></li>
++ <li><span class="flag flag-venezuela"></span></li>
++ <li><span class="flag flag-vietnam"></span></li>
++ <li><span class="flag flag-wallis-and-futuna"></span></li>
++ <li><span class="flag flag-western-sahara"></span></li>
++ <li><span class="flag flag-yemen"></span></li>
++ <li><span class="flag flag-zambia"></span></li>
++ <li><span class="flag flag-zimbabwe"></span></li>
++</ul>
+diff --git a/third_party/blink/web_tests/dark-mode/images/resources/country-flags-sprite.png b/third_party/blink/web_tests/dark-mode/images/resources/country-flags-sprite.png
+new file mode 100644
+index 000000000000..b2dbb8877c38
+Binary files /dev/null and b/third_party/blink/web_tests/dark-mode/images/resources/country-flags-sprite.png differ
+diff --git a/third_party/blink/web_tests/platform/mac-mac13/virtual/dark-mode-default/dark-mode/images/country-flags-expected.png b/third_party/blink/web_tests/platform/mac-mac13/virtual/dark-mode-default/dark-mode/images/country-flags-expected.png
+new file mode 100644
+index 000000000000..1b0fabc3ff77
+Binary files /dev/null and b/third_party/blink/web_tests/platform/mac-mac13/virtual/dark-mode-default/dark-mode/images/country-flags-expected.png differ
+diff --git a/third_party/blink/web_tests/platform/mac/virtual/dark-mode-default/dark-mode/images/country-flags-expected.png b/third_party/blink/web_tests/platform/mac/virtual/dark-mode-default/dark-mode/images/country-flags-expected.png
+new file mode 100644
+index 000000000000..51c05fb642e7
+Binary files /dev/null and b/third_party/blink/web_tests/platform/mac/virtual/dark-mode-default/dark-mode/images/country-flags-expected.png differ
+diff --git a/third_party/blink/web_tests/platform/win/virtual/dark-mode-default/dark-mode/images/country-flags-expected.png b/third_party/blink/web_tests/platform/win/virtual/dark-mode-default/dark-mode/images/country-flags-expected.png
+new file mode 100644
+index 000000000000..1b0fabc3ff77
+Binary files /dev/null and b/third_party/blink/web_tests/platform/win/virtual/dark-mode-default/dark-mode/images/country-flags-expected.png differ
+diff --git a/third_party/blink/web_tests/platform/win11-arm64/virtual/dark-mode-default/dark-mode/images/country-flags-expected.png b/third_party/blink/web_tests/platform/win11-arm64/virtual/dark-mode-default/dark-mode/images/country-flags-expected.png
+new file mode 100644
+index 000000000000..51c05fb642e7
+Binary files /dev/null and b/third_party/blink/web_tests/platform/win11-arm64/virtual/dark-mode-default/dark-mode/images/country-flags-expected.png differ
diff --git a/chromium-148-Prefix-dark-mode-decision-tree-threshold-constants-with-kFeature.patch b/chromium-148-Prefix-dark-mode-decision-tree-threshold-constants-with-kFeature.patch
new file mode 100644
index 0000000..f853057
--- /dev/null
+++ b/chromium-148-Prefix-dark-mode-decision-tree-threshold-constants-with-kFeature.patch
@@ -0,0 +1,83 @@
+commit f60c4bb9d944849d3d9269a3f4c0782353c973ec
+Author: Prashant Nevase <pnevase@microsoft.com>
+Date: Fri May 8 05:37:26 2026 -0700
+
+ Prefix dark mode decision-tree threshold constants with kFeature.
+
+ This CL prefixes feature constants with kFeature to clearly
+ distinguish them from other constants, improving readability and
+ scalability as more features are getting added.
+
+ Bug: 449909524
+ Change-Id: I84492594bead3e3b26a926933edfa11cbdba4c4b
+ Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7831584
+ Commit-Queue: Stephen Chenney <schenney@chromium.org>
+ Reviewed-by: Stephen Chenney <schenney@chromium.org>
+ Auto-Submit: Prashant Nevase <pnevase@microsoft.com>
+ Cr-Commit-Position: refs/heads/main@{#1627580}
+
+diff --git a/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.cc b/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.cc
+index 8151543ee33f..1d1b7fdf2348 100644
+--- a/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.cc
++++ b/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.cc
+@@ -17,23 +17,25 @@
+ namespace blink {
+ namespace {
+
+-// Decision tree lower and upper thresholds for grayscale and color images.
+-constexpr std::array<float, 2> kLowColorCountThreshold = {0.8125, 0.015137};
+-constexpr std::array<float, 2> kHighColorCountThreshold = {1, 0.025635};
+-
++const int kMaxSampledPixels = 1000;
++const int kMaxBlocks = 10;
++const float kMinOpaquePixelPercentageForForeground = 0.2;
+ // Color is considered light if its luma is above this threshold.
+ constexpr int kHighLightnessThreshold = 96;
+
+-// Luminance ratio threshold above which the image is classified as light.
+-constexpr float kHighLuminanceThreshold = 0.5f;
++// Decision tree thresholds for classifying images
++
++// Lower and upper color thresholds for grayscale and color images.
++constexpr std::array<float, 2> kFeatureLowColorCountThreshold = {0.8125,
++ 0.015137};
++constexpr std::array<float, 2> kFeatureHighColorCountThreshold = {1, 0.025635};
+
+ // Transparency ratio threshold above which the image is classified as
+ // transparent, meaning most of the background pixels are transparent.
+-constexpr float kTransparencyRatioThreshold = 0.4f;
++constexpr float kFeatureTransparencyRatioThreshold = 0.4f;
+
+-const int kMaxSampledPixels = 1000;
+-const int kMaxBlocks = 10;
+-const float kMinOpaquePixelPercentageForForeground = 0.2;
++// Luminance ratio threshold above which the image is classified as light.
++constexpr float kFeatureHighLuminanceThreshold = 0.5f;
+
+ bool IsColorGray(const SkColor& color) {
+ return abs(static_cast<int>(SkColorGetR(color)) -
+@@ -288,20 +290,20 @@ DarkModeResult DarkModeImageClassifier::ClassifyUsingDecisionTree(
+ // foreground is predominantly light. Inverting such images would make
+ // visible pixels darker, causing them to merge with dark background, so do
+ // not apply filter.
+- if (features.transparency_ratio > kTransparencyRatioThreshold &&
+- features.high_luminance_ratio > kHighLuminanceThreshold) {
++ if (features.transparency_ratio > kFeatureTransparencyRatioThreshold &&
++ features.high_luminance_ratio > kFeatureHighLuminanceThreshold) {
+ return DarkModeResult::kDoNotApplyFilter;
+ }
+
+ // Very few colors means it's not a photo, apply the filter.
+ if (features.color_buckets_ratio <
+- kLowColorCountThreshold[features.is_colorful]) {
++ kFeatureLowColorCountThreshold[features.is_colorful]) {
+ return DarkModeResult::kApplyFilter;
+ }
+
+ // Too many colors means it's probably photorealistic, do not apply it.
+ if (features.color_buckets_ratio >
+- kHighColorCountThreshold[features.is_colorful]) {
++ kFeatureHighColorCountThreshold[features.is_colorful]) {
+ return DarkModeResult::kDoNotApplyFilter;
+ }
+
diff --git a/chromium-148-autodarkmode-workaround.patch b/chromium-148-autodarkmode-workaround.patch
deleted file mode 100644
index 58a2d13..0000000
--- a/chromium-148-autodarkmode-workaround.patch
+++ /dev/null
@@ -1,14 +0,0 @@
-Workaround auto darkmode issue, image are not inverted correctly in darkmode
-
-diff -up chromium-148.0.7778.96/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.cc.me chromium-148.0.7778.96/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.cc
---- chromium-148.0.7778.96/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.cc.me 2026-05-06 16:22:25.906024153 +0200
-+++ chromium-148.0.7778.96/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.cc 2026-05-06 16:22:52.465423557 +0200
-@@ -265,7 +265,7 @@ DarkModeResult DarkModeImageClassifier::
-
- // Very few colors means it's not a photo, apply the filter.
- if (features.color_buckets_ratio < low_color_count_threshold)
-- return DarkModeResult::kApplyFilter;
-+ return DarkModeResult::kDoNotApplyFilter;
-
- // Too many colors means it's probably photorealistic, do not apply it.
- if (features.color_buckets_ratio > high_color_count_threshold)
diff --git a/chromium.conf b/chromium.conf
index fc4167e..f77975e 100644
--- a/chromium.conf
+++ b/chromium.conf
@@ -20,7 +20,7 @@ fi
# Disable chromium's AI model
DISABLE_FEATURES="LensOverlay,OptimizationGuideOnDeviceModel,PromptAPIForGeminiNano,Compose,TabOrganization"
ENABLE_FEATURES="AllowQt"
-CHROMIUM_FLAGS=" --enable-chrome-browser-cloud-management"
+CHROMIUM_FLAGS=""
if [ "$NATIVE_WAYLAND" == "on" ] ; then
ENABLE_FEATURES+=",WaylandLinuxDrmSyncobj,WaylandPerSurfaceScale,WaylandUiScale"
else
@@ -60,7 +60,7 @@ fi
# Web Dark mode
if [ "$WEB_AUTO_DARKMODE_WEBCONTENT" == "on" ] ; then
- darktype="WebContentsForceDark"
+ darktype="WebContentsForceDark,AutoDarkModeSkipImages"
if [ -z "$ENABLE_FEATURES" ] ; then
ENABLE_FEATURES+="$darktype"
else
diff --git a/chromium.spec b/chromium.spec
index 7fb12f6..3f289ae 100644
--- a/chromium.spec
+++ b/chromium.spec
@@ -262,7 +262,7 @@
%endif
Name: chromium
-Version: 148.0.7778.167
+Version: 148.0.7778.178
Release: 1%{?dist}
Summary: A WebKit (Blink) powered web browser that Google doesn't want you to use
Url: http://www.chromium.org/Home
@@ -291,9 +291,6 @@ Patch22: chromium-131-fix-qt-ui.pach
# needs //third_party/libpng:libpng_for_testonly(//build/toolchain/linux/unbundle:default)
Patch23: chromium-143-revert-libpng_for_testonly.patch
-# Get around the problem of auto darkmode webcontent inverting and making them unreadable
-Patch30: chromium-148-autodarkmode-workaround.patch
-
# disable enterprise_companion_integration_tests due to Unresolved dependencies
Patch31: chromium-145-disable-enterprise_companion_integration_tests.patch
@@ -521,7 +518,12 @@ Patch511: 0001-fips-disable-options.patch
Patch520: build-with-wasm-rollup.patch
Patch521: disable-ai.patch
-# upstream patches
+# Upstream patches
+# Fix auto dark mode
+Patch600: chromium-148-Add-luminance-ratio-feature-for-dark-mode-image-classification.patch
+Patch601: chromium-148-Prefix-dark-mode-decision-tree-threshold-constants-with-kFeature.patch
+Patch602: chromium-148-Add-saturation-feature-for-dark-mode-image-classification.patch
+Patch603: chromium-148-Add-AutoDarkModeSkipImages-flag-to-bypass-image-dark-mode.patch
# Use chromium-latest.py to generate clean tarball from released build tarballs, found here:
# http://build.chromium.org/buildbot/official/
@@ -1068,7 +1070,6 @@ Qt6 UI for chromium.
%endif
%patch -P23 -p1 -R -b .revert-libpng_for_testonly
-%patch -P30 -p1 -b .autodarkmode-workaround
%patch -P31 -p1 -b .disable-enterprise_companion_integration_tests
%if ! %{bundlebrotli}
@@ -1234,6 +1235,11 @@ Qt6 UI for chromium.
%patch -P521 -p1 -b .disable-ai
# Upstream patches
+# improve auto dark image inversion logic
+%patch -P600 -p1 -b .Add-luminance-ratio-feature-for-dark-mode-image-classification
+%patch -P601 -p1 -b .Prefix-dark-mode-decision-tree-threshold-constants-with-kFeature
+%patch -P602 -p1 -b .Add-saturation-feature-for-dark-mode-image-classification
+%patch -P603 -p1 -b .Add-AutoDarkModeSkipImages-flag-to-bypass-image-dark-mode
# Change shebang in all relevant files in this directory and all subdirectories
# See `man find` for how the `-exec command {} +` syntax works
@@ -1885,6 +1891,11 @@ fi
%endif
%changelog
+* Wed May 20 2026 Than Ngo <than@redhat.com> - 148.0.7778.178-1
+- Update to 148.0.7778.178
+- Backport upstream patches to improve auto dark image inversion logic
+- Update default chromium browser config
+
* Fri May 15 2026 Than Ngo <than@redhat.com> - 148.0.7778.167-1
- Update to 148.0.7778.167
* CVE-2026-8509: Heap buffer overflow in WebML
diff --git a/sources b/sources
index 070db24..eabdf8b 100644
--- a/sources
+++ b/sources
@@ -1,2 +1,2 @@
SHA512 (node-v22.22.0-stripped.tar.gz) = f32a8a73063b3c78cbacf941e11dd529ebcf2618b3ba661966312e49ee9870c43a3acf256e8d331a4b0b621b16a501810c02a3ad763c75884cc250addca8e106
-SHA512 (chromium-148.0.7778.167-clean.tar.xz) = 39b0c4d98d4fcbfefa4ae8913a5ed0fa40491c6803e790e1e299ee5abedef9ea63c5d010a1d374750575887bc3a326037dcf5b2d7f0a12c86fa019fd556d4594
+SHA512 (chromium-148.0.7778.178-clean.tar.xz) = 66a7879842702800051529f9c6b0a3915d4fc4f8fa357defa2b88d7d5f59f02a807ab6922d0a3c8d59569fbf80f5ade5ed2a2e8cddafac74a250c8dcdfa25ee7
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2026-08-07 16:09 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-08-07 16:09 [rpms/chromium] epel9-next: - Update to 148.0.7778.178 Than Ngo
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox