Factor most Dark Mode code out of GraphicsContext.

This is a clean-up CL in preparation for adding an image-specific
filter.

Bug: 954318
Change-Id: I002e09c2ebd384c0f0d667dcb00eebc7550aee71
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1574629
Commit-Queue: Aran Gilman <gilmanmh@google.com>
Reviewed-by: Stephen Chenney <schenney@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#652679}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: b47924e0a0e2465111ee1e35806f643ff0553eb2
diff --git a/blink/renderer/platform/BUILD.gn b/blink/renderer/platform/BUILD.gn
index eee1b87..6af3f8f 100644
--- a/blink/renderer/platform/BUILD.gn
+++ b/blink/renderer/platform/BUILD.gn
@@ -892,6 +892,8 @@
     "graphics/dark_mode_bitmap_image_classifier.h",
     "graphics/dark_mode_color_classifier.cc",
     "graphics/dark_mode_color_classifier.h",
+    "graphics/dark_mode_filter.cc",
+    "graphics/dark_mode_filter.h",
     "graphics/dark_mode_settings.h",
     "graphics/darkmode/darkmode_classifier.cc",
     "graphics/darkmode/darkmode_classifier.h",
diff --git a/blink/renderer/platform/graphics/dark_mode_filter.cc b/blink/renderer/platform/graphics/dark_mode_filter.cc
new file mode 100644
index 0000000..7229c9e
--- /dev/null
+++ b/blink/renderer/platform/graphics/dark_mode_filter.cc
@@ -0,0 +1,72 @@
+#include "third_party/blink/renderer/platform/graphics/dark_mode_filter.h"
+
+#include "third_party/skia/include/core/SkColorFilter.h"
+#include "third_party/skia/include/effects/SkHighContrastFilter.h"
+#include "third_party/skia/include/effects/SkTableColorFilter.h"
+
+namespace blink {
+
+DarkModeFilter::DarkModeFilter() : default_filter_(nullptr) {
+  settings_.mode = DarkMode::kOff;
+  settings_.image_policy = DarkModeImagePolicy::kFilterNone;
+}
+
+void DarkModeFilter::UpdateSettings(const DarkModeSettings& new_settings) {
+  settings_ = new_settings;
+
+  SkHighContrastConfig config;
+  switch (settings_.mode) {
+    case DarkMode::kOff:
+      default_filter_.reset(nullptr);
+      return;
+    case DarkMode::kSimpleInvertForTesting: {
+      uint8_t identity[256], invert[256];
+      for (int i = 0; i < 256; ++i) {
+        identity[i] = i;
+        invert[i] = 255 - i;
+      }
+      default_filter_ =
+          SkTableColorFilter::MakeARGB(identity, invert, invert, invert);
+      return;
+    }
+    case DarkMode::kInvertBrightness:
+      config.fInvertStyle =
+          SkHighContrastConfig::InvertStyle::kInvertBrightness;
+      break;
+    case DarkMode::kInvertLightness:
+      config.fInvertStyle = SkHighContrastConfig::InvertStyle::kInvertLightness;
+      break;
+  }
+
+  config.fGrayscale = settings_.grayscale;
+  config.fContrast = settings_.contrast;
+  default_filter_ = SkHighContrastFilter::Make(config);
+}
+
+sk_sp<SkColorFilter> DarkModeFilter::GetColorFilter() {
+  return default_filter_;
+}
+
+bool DarkModeFilter::ShouldApplyToImage(Image& image,
+                                        const FloatRect& src_rect) {
+  if (!GetColorFilter())
+    return false;
+
+  switch (settings_.image_policy) {
+    case DarkModeImagePolicy::kFilterSmart:
+      return image.ShouldApplyDarkModeFilter(src_rect);
+    case DarkModeImagePolicy::kFilterAll:
+      return true;
+    default:
+      return false;
+  }
+}
+
+Color DarkModeFilter::Apply(const Color& color) {
+  sk_sp<SkColorFilter> filter = GetColorFilter();
+  if (!filter)
+    return color;
+  return Color(filter->filterColor(color.Rgb()));
+}
+
+}  // namespace blink
diff --git a/blink/renderer/platform/graphics/dark_mode_filter.h b/blink/renderer/platform/graphics/dark_mode_filter.h
new file mode 100644
index 0000000..6052af1
--- /dev/null
+++ b/blink/renderer/platform/graphics/dark_mode_filter.h
@@ -0,0 +1,34 @@
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_DARK_MODE_FILTER_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_DARK_MODE_FILTER_H_
+
+#include "third_party/blink/renderer/platform/geometry/float_rect.h"
+#include "third_party/blink/renderer/platform/graphics/color.h"
+#include "third_party/blink/renderer/platform/graphics/dark_mode_settings.h"
+#include "third_party/blink/renderer/platform/graphics/image.h"
+#include "third_party/skia/include/core/SkRefCnt.h"
+
+class SkColorFilter;
+
+namespace blink {
+
+class DarkModeFilter {
+ public:
+  DarkModeFilter();
+
+  const DarkModeSettings& settings() const { return settings_; }
+  void UpdateSettings(const DarkModeSettings& new_settings);
+
+  sk_sp<SkColorFilter> GetColorFilter();
+
+  bool ShouldApplyToImage(Image& image, const FloatRect& src_rect);
+
+  Color Apply(const Color& color);
+
+ private:
+  DarkModeSettings settings_;
+  sk_sp<SkColorFilter> default_filter_;
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_DARK_MODE_FILTER_H_
diff --git a/blink/renderer/platform/graphics/graphics_context.cc b/blink/renderer/platform/graphics/graphics_context.cc
index cc5a1df..340fbf3 100644
--- a/blink/renderer/platform/graphics/graphics_context.cc
+++ b/blink/renderer/platform/graphics/graphics_context.cc
@@ -64,16 +64,16 @@
 
  public:
   // This helper's lifetime should never exceed |flags|'.
-  DarkModeFlags(const GraphicsContext* gc, const PaintFlags& flags) {
-    if (!gc->dark_mode_filter_) {
+  DarkModeFlags(GraphicsContext* gc, const PaintFlags& flags) {
+    sk_sp<SkColorFilter> filter = gc->dark_mode_filter_.GetColorFilter();
+    if (!filter) {
       flags_ = &flags;
     } else {
       dark_mode_flags_ = flags;
       if (flags.HasShader()) {
-        dark_mode_flags_->setColorFilter(gc->dark_mode_filter_);
+        dark_mode_flags_->setColorFilter(filter);
       } else {
-        dark_mode_flags_->setColor(
-            gc->dark_mode_filter_->filterColor(flags.getColor()));
+        dark_mode_flags_->setColor(filter->filterColor(flags.getColor()));
       }
 
       flags_ = &dark_mode_flags_.value();
@@ -171,35 +171,7 @@
 #endif
 
 void GraphicsContext::SetDarkMode(const DarkModeSettings& settings) {
-  dark_mode_settings_ = settings;
-
-  SkHighContrastConfig config;
-  switch (dark_mode_settings_.mode) {
-    case DarkMode::kOff:
-      dark_mode_filter_.reset(nullptr);
-      return;
-    case DarkMode::kSimpleInvertForTesting: {
-      uint8_t identity[256], invert[256];
-      for (int i = 0; i < 256; ++i) {
-        identity[i] = i;
-        invert[i] = 255 - i;
-      }
-      dark_mode_filter_ =
-          SkTableColorFilter::MakeARGB(identity, invert, invert, invert);
-      return;
-    }
-    case DarkMode::kInvertBrightness:
-      config.fInvertStyle =
-          SkHighContrastConfig::InvertStyle::kInvertBrightness;
-      break;
-    case DarkMode::kInvertLightness:
-      config.fInvertStyle = SkHighContrastConfig::InvertStyle::kInvertLightness;
-      break;
-  }
-
-  config.fGrayscale = dark_mode_settings_.grayscale;
-  config.fContrast = dark_mode_settings_.contrast;
-  dark_mode_filter_ = SkHighContrastFilter::Make(config);
+  dark_mode_filter_.UpdateSettings(settings);
 }
 
 void GraphicsContext::SaveLayer(const SkRect* bounds, const PaintFlags* flags) {
@@ -415,13 +387,15 @@
 void GraphicsContext::DrawFocusRingPath(const SkPath& path,
                                         const Color& color,
                                         float width) {
-  DrawPlatformFocusRing(path, canvas_, ApplyDarkModeFilter(color).Rgb(), width);
+  DrawPlatformFocusRing(path, canvas_, dark_mode_filter_.Apply(color).Rgb(),
+                        width);
 }
 
 void GraphicsContext::DrawFocusRingRect(const SkRect& rect,
                                         const Color& color,
                                         float width) {
-  DrawPlatformFocusRing(rect, canvas_, ApplyDarkModeFilter(color).Rgb(), width);
+  DrawPlatformFocusRing(rect, canvas_, dark_mode_filter_.Apply(color).Rgb(),
+                        width);
 }
 
 void GraphicsContext::DrawFocusRing(const Path& focus_ring_path,
@@ -496,7 +470,7 @@
   if (ContextDisabled())
     return;
 
-  Color shadow_color = ApplyDarkModeFilter(orig_shadow_color);
+  Color shadow_color = dark_mode_filter_.Apply(orig_shadow_color);
 
   FloatRect hole_rect(rect.Rect());
   hole_rect.Inflate(-shadow_spread);
@@ -899,8 +873,10 @@
   image_flags.setBlendMode(op);
   image_flags.setColor(SK_ColorBLACK);
   image_flags.setFilterQuality(ComputeFilterQuality(image, dest, src));
-  if (ShouldApplyDarkModeFilterToImage(*image, src))
-    image_flags.setColorFilter(dark_mode_filter_);
+  if (dark_mode_filter_.ShouldApplyToImage(*image, src)) {
+    image_flags.setColorFilter(dark_mode_filter_.GetColorFilter());
+  }
+
   image->Draw(canvas_, image_flags, dest, src, should_respect_image_orientation,
               Image::kClampImageToSourceRect, decode_mode);
   paint_controller_.SetImagePainted();
@@ -934,8 +910,9 @@
   image_flags.setColor(SK_ColorBLACK);
   image_flags.setFilterQuality(
       ComputeFilterQuality(image, dest.Rect(), src_rect));
-  if (ShouldApplyDarkModeFilterToImage(*image, src_rect))
-    image_flags.setColorFilter(dark_mode_filter_);
+  if (dark_mode_filter_.ShouldApplyToImage(*image, src_rect)) {
+    image_flags.setColorFilter(dark_mode_filter_.GetColorFilter());
+  }
 
   bool use_shader = (visible_src == src_rect) &&
                     (respect_orientation == kDoNotRespectImageOrientation);
@@ -1145,7 +1122,7 @@
       canvas_->drawDRRect(outer, inner, ImmutableState()->FillFlags());
     } else {
       PaintFlags flags(ImmutableState()->FillFlags());
-      flags.setColor(ApplyDarkModeFilter(color).Rgb());
+      flags.setColor(dark_mode_filter_.Apply(color).Rgb());
       canvas_->drawDRRect(outer, inner, flags);
     }
 
@@ -1158,7 +1135,7 @@
   stroke_r_rect.inset(stroke_width / 2, stroke_width / 2);
 
   PaintFlags stroke_flags(ImmutableState()->FillFlags());
-  stroke_flags.setColor(ApplyDarkModeFilter(color).Rgb());
+  stroke_flags.setColor(dark_mode_filter_.Apply(color).Rgb());
   stroke_flags.setStyle(PaintFlags::kStroke_Style);
   stroke_flags.setStrokeWidth(stroke_width);
 
@@ -1353,7 +1330,7 @@
     return;
 
   PaintFlags flags(ImmutableState()->FillFlags());
-  flags.setColor(ApplyDarkModeFilter(color).Rgb());
+  flags.setColor(dark_mode_filter_.Apply(color).Rgb());
   canvas_->drawDRRect(SkRRect::MakeRect(rect), rounded_hole_rect, flags);
 }
 
@@ -1399,26 +1376,4 @@
   return nullptr;
 }
 
-bool GraphicsContext::ShouldApplyDarkModeFilterToImage(
-    Image& image,
-    const FloatRect& src_rect) {
-  if (!dark_mode_filter_)
-    return false;
-
-  switch (dark_mode_settings_.image_policy) {
-    case DarkModeImagePolicy::kFilterSmart:
-      return image.ShouldApplyDarkModeFilter(src_rect);
-    case DarkModeImagePolicy::kFilterAll:
-      return true;
-    default:
-      return false;
-  }
-}
-
-Color GraphicsContext::ApplyDarkModeFilter(const Color& input) const {
-  if (!dark_mode_filter_)
-    return input;
-  return Color(dark_mode_filter_->filterColor(input.Rgb()));
-}
-
 }  // namespace blink
diff --git a/blink/renderer/platform/graphics/graphics_context.h b/blink/renderer/platform/graphics/graphics_context.h
index d1ad6e5..dd46da0 100644
--- a/blink/renderer/platform/graphics/graphics_context.h
+++ b/blink/renderer/platform/graphics/graphics_context.h
@@ -33,6 +33,7 @@
 #include "base/macros.h"
 #include "cc/paint/node_holder.h"
 #include "third_party/blink/renderer/platform/fonts/font.h"
+#include "third_party/blink/renderer/platform/graphics/dark_mode_filter.h"
 #include "third_party/blink/renderer/platform/graphics/dark_mode_settings.h"
 #include "third_party/blink/renderer/platform/graphics/dash_array.h"
 #include "third_party/blink/renderer/platform/graphics/draw_looper_builder.h"
@@ -88,7 +89,7 @@
   bool ContextDisabled() const { return disabled_state_; }
 
   const DarkModeSettings& dark_mode_settings() const {
-    return dark_mode_settings_;
+    return dark_mode_filter_.settings();
   }
 
   // ---------- State management methods -----------------
@@ -458,9 +459,6 @@
                                const Color&);
 
   class DarkModeFlags;
-  bool ShouldApplyDarkModeFilterToImage(Image& image,
-                                        const FloatRect& src_rect);
-  Color ApplyDarkModeFilter(const Color& input) const;
 
   // null indicates painting is contextDisabled. Never delete this object.
   cc::PaintCanvas* canvas_;
@@ -491,8 +489,8 @@
 
   float device_scale_factor_;
 
-  DarkModeSettings dark_mode_settings_;
-  sk_sp<SkColorFilter> dark_mode_filter_;
+  // TODO(gilmanmh): Investigate making this base::Optional<DarkModeFilter>
+  DarkModeFilter dark_mode_filter_;
 
   unsigned printing_ : 1;
   unsigned in_drawing_recorder_ : 1;