From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Birunthan Mohanathas <birunthan@mohanathas.com>
Date: Fri, 30 Nov 2018 12:44:12 +0200
Subject: Add --disable-color-correct-rendering switch

In Electron 2.0, `--disable-features=ColorCorrectRendering` could be
used to make the app use the display color space (e.g. P3 on Macs)
instead of color correcting to sRGB. Because color correct rendering is
always enabled on Chromium 62 and later and because
`--force-color-profile` has no effect on macOS, apps that need e.g. P3
colors are currently stuck on Electron 2.0.

This restores the functionality removed in
https://chromium-review.googlesource.com/698347 in the form of the
`--disable-color-correct-rendering` switch.

This can be removed once web content (including WebGL) learn how
to deal with color spaces. That is being tracked at
https://crbug.com/634542 and https://crbug.com/711107.

diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 2782b23d66cdf79e7fdbbd3111b7434ef20a90d3..6543722350b89c94974ab0b97a937cd5fa29fde4 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -1569,6 +1569,10 @@ void LayerTreeHostImpl::SetIsLikelyToRequireADraw(
 }
 
 RasterColorSpace LayerTreeHostImpl::GetRasterColorSpace() const {
+  if (!settings_.enable_color_correct_rendering) {
+    return {};
+  }
+
   RasterColorSpace result;
   // The pending tree will have the most recently updated color space, so
   // prefer that.
diff --git a/cc/trees/layer_tree_settings.h b/cc/trees/layer_tree_settings.h
index 9de6c5f5f45d7cb3e9141ffb480f6052090cc696..30f491ec4a2663d18bf22c27eff8dbbd7440e195 100644
--- a/cc/trees/layer_tree_settings.h
+++ b/cc/trees/layer_tree_settings.h
@@ -98,6 +98,8 @@ class CC_EXPORT LayerTreeSettings {
 
   bool enable_mask_tiling = true;
 
+  bool enable_color_correct_rendering = true;
+
   // If set to true, the compositor may selectively defer image decodes to the
   // Image Decode Service and raster tiles without images until the decode is
   // ready.
diff --git a/components/viz/common/display/renderer_settings.h b/components/viz/common/display/renderer_settings.h
index 2b8cd275a5ee29b665f1a0fb27105cf75eab13ed..3493572110e2dda18c57fe079174f0934fb288b9 100644
--- a/components/viz/common/display/renderer_settings.h
+++ b/components/viz/common/display/renderer_settings.h
@@ -20,6 +20,7 @@ class VIZ_COMMON_EXPORT RendererSettings {
   RendererSettings(const RendererSettings& other);
   ~RendererSettings();
 
+  bool enable_color_correct_rendering = true;
   bool allow_antialiasing = true;
   bool force_antialiasing = false;
   bool force_blending_with_shaders = false;
diff --git a/components/viz/host/renderer_settings_creation.cc b/components/viz/host/renderer_settings_creation.cc
index e63d201943faf1b537df711299168d0378823bd0..fb5ca48f16b78a4d0a45cb57988d1d94cb4159bb 100644
--- a/components/viz/host/renderer_settings_creation.cc
+++ b/components/viz/host/renderer_settings_creation.cc
@@ -11,6 +11,7 @@
 #include "components/viz/common/display/renderer_settings.h"
 #include "components/viz/common/features.h"
 #include "ui/base/ui_base_switches.h"
+#include "ui/gfx/switches.h"
 
 #if defined(OS_MACOSX)
 #include "ui/base/cocoa/remote_layer_api.h"
@@ -43,6 +44,8 @@ bool GetSwitchValueAsInt(const base::CommandLine* command_line,
 RendererSettings CreateRendererSettings() {
   RendererSettings renderer_settings;
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+  renderer_settings.enable_color_correct_rendering =
+      !command_line->HasSwitch(switches::kDisableColorCorrectRendering);
   renderer_settings.partial_swap_enabled =
       !command_line->HasSwitch(switches::kUIDisablePartialSwap);
 #if defined(OS_WIN)
diff --git a/components/viz/service/display/gl_renderer.cc b/components/viz/service/display/gl_renderer.cc
index 6ee04d0919d9b4ae5e2d6719f1417f00a3d600fa..62c0b5da24e02102b268429b1d8e3654064300fc 100644
--- a/components/viz/service/display/gl_renderer.cc
+++ b/components/viz/service/display/gl_renderer.cc
@@ -78,6 +78,9 @@
 
 using gpu::gles2::GLES2Interface;
 
+#define PATCH_CS(color_space) \
+  (settings_->enable_color_correct_rendering ? color_space : gfx::ColorSpace())
+
 namespace viz {
 namespace {
 
@@ -523,8 +526,9 @@ void GLRenderer::DoDrawQuad(const DrawQuad* quad,
 void GLRenderer::DrawDebugBorderQuad(const DebugBorderDrawQuad* quad) {
   SetBlendEnabled(quad->ShouldDrawWithBlending());
 
-  SetUseProgram(ProgramKey::DebugBorder(), gfx::ColorSpace::CreateSRGB(),
-                current_frame()->current_render_pass->color_space);
+  SetUseProgram(ProgramKey::DebugBorder(),
+                PATCH_CS(gfx::ColorSpace::CreateSRGB()),
+                PATCH_CS(current_frame()->current_render_pass->color_space));
 
   // Use the full quad_rect for debug quads to not move the edges based on
   // partial swaps.
@@ -1326,7 +1330,8 @@ void GLRenderer::ChooseRPDQProgram(DrawRenderPassDrawQuadParams* params,
           tex_coord_precision, sampler_type, shader_blend_mode,
           params->use_aa ? USE_AA : NO_AA, mask_mode, mask_for_background,
           params->use_color_matrix, tint_gl_composited_content_),
-      params->contents_and_bypass_color_space, target_color_space);
+      PATCH_CS(params->contents_and_bypass_color_space),
+      PATCH_CS(target_color_space));
 }
 
 void GLRenderer::UpdateRPDQUniforms(DrawRenderPassDrawQuadParams* params) {
@@ -1789,8 +1794,8 @@ void GLRenderer::DrawSolidColorQuad(const SolidColorDrawQuad* quad,
   gfx::ColorSpace quad_color_space = gfx::ColorSpace::CreateSRGB();
   SetUseProgram(ProgramKey::SolidColor(use_aa ? USE_AA : NO_AA,
                                        tint_gl_composited_content_),
-                quad_color_space,
-                current_frame()->current_render_pass->color_space);
+                PATCH_CS(quad_color_space),
+                PATCH_CS(current_frame()->current_render_pass->color_space));
   SetShaderColor(color, opacity);
 
   if (current_program_->tint_color_matrix_location() != -1) {
@@ -1940,8 +1945,8 @@ void GLRenderer::DrawContentQuadAA(const ContentDrawQuadBase* quad,
                        quad->is_premultiplied ? PREMULTIPLIED_ALPHA
                                               : NON_PREMULTIPLIED_ALPHA,
                        false, false, tint_gl_composited_content_),
-      quad_resource_lock.color_space(),
-      current_frame()->current_render_pass->color_space);
+      PATCH_CS(quad_resource_lock.color_space()),
+      PATCH_CS(current_frame()->current_render_pass->color_space));
 
   if (current_program_->tint_color_matrix_location() != -1) {
     auto matrix = cc::DebugColors::TintCompositedContentColorTransformMatrix();
@@ -2029,8 +2034,8 @@ void GLRenderer::DrawContentQuadNoAA(const ContentDrawQuadBase* quad,
                                               : NON_PREMULTIPLIED_ALPHA,
                        !quad->ShouldDrawWithBlending(), has_tex_clamp_rect,
                        tint_gl_composited_content_),
-      quad_resource_lock.color_space(),
-      current_frame()->current_render_pass->color_space);
+      PATCH_CS(quad_resource_lock.color_space()),
+      PATCH_CS(current_frame()->current_render_pass->color_space));
 
   if (current_program_->tint_color_matrix_location() != -1) {
     auto matrix = cc::DebugColors::TintCompositedContentColorTransformMatrix();
@@ -2125,7 +2130,7 @@ void GLRenderer::DrawYUVVideoQuad(const YUVVideoDrawQuad* quad,
   DCHECK_NE(src_color_space, src_color_space.GetAsFullRangeRGB());
 
   gfx::ColorSpace dst_color_space =
-      current_frame()->current_render_pass->color_space;
+      PATCH_CS(current_frame()->current_render_pass->color_space);
   // Force sRGB output on Windows for overlay candidate video quads to match
   // DirectComposition behavior in case these switch between overlays and
   // compositing. See https://crbug.com/811118 for details.
@@ -2273,8 +2278,8 @@ void GLRenderer::DrawStreamVideoQuad(const StreamVideoDrawQuad* quad,
                                                  quad->resource_id());
 
   SetUseProgram(ProgramKey::VideoStream(tex_coord_precision),
-                lock.color_space(),
-                current_frame()->current_render_pass->color_space);
+                PATCH_CS(lock.color_space()),
+                PATCH_CS(current_frame()->current_render_pass->color_space));
 
   DCHECK_EQ(GL_TEXTURE0, GetActiveTextureUnit(gl_));
   gl_->BindTexture(GL_TEXTURE_EXTERNAL_OES, lock.texture_id());
@@ -2326,8 +2331,8 @@ void GLRenderer::FlushTextureQuadCache(BoundGeometry flush_binding) {
       draw_cache_.nearest_neighbor ? GL_NEAREST : GL_LINEAR);
 
   // Bind the program to the GL state.
-  SetUseProgram(draw_cache_.program_key, locked_quad.color_space(),
-                current_frame()->current_render_pass->color_space);
+  SetUseProgram(draw_cache_.program_key, PATCH_CS(locked_quad.color_space()),
+                PATCH_CS(current_frame()->current_render_pass->color_space));
 
   DCHECK_EQ(GL_TEXTURE0, GetActiveTextureUnit(gl_));
   gl_->BindTexture(locked_quad.target(), locked_quad.texture_id());
@@ -2982,7 +2987,9 @@ void GLRenderer::PrepareGeometry(BoundGeometry binding) {
 void GLRenderer::SetUseProgram(const ProgramKey& program_key_no_color,
                                const gfx::ColorSpace& src_color_space,
                                const gfx::ColorSpace& dst_color_space) {
-  DCHECK(dst_color_space.IsValid());
+  if (settings_->enable_color_correct_rendering) {
+    DCHECK(dst_color_space.IsValid());
+  }
 
   ProgramKey program_key = program_key_no_color;
   const gfx::ColorTransform* color_transform =
@@ -3336,7 +3343,7 @@ void GLRenderer::CopyRenderPassDrawQuadToOverlayResource(
 
   *overlay_texture = FindOrCreateOverlayTexture(
       params.quad->render_pass_id, iosurface_width, iosurface_height,
-      current_frame()->root_render_pass->color_space);
+      PATCH_CS(current_frame()->root_render_pass->color_space));
   *new_bounds = gfx::RectF(updated_dst_rect.origin(),
                            gfx::SizeF((*overlay_texture)->texture.size()));
 
@@ -3540,8 +3547,9 @@ void GLRenderer::FlushOverdrawFeedback(const gfx::Rect& output_rect) {
 
   PrepareGeometry(SHARED_BINDING);
 
-  SetUseProgram(ProgramKey::DebugBorder(), gfx::ColorSpace::CreateSRGB(),
-                current_frame()->root_render_pass->color_space);
+  SetUseProgram(ProgramKey::DebugBorder(),
+                PATCH_CS(gfx::ColorSpace::CreateSRGB()),
+                PATCH_CS(current_frame()->root_render_pass->color_space));
 
   gfx::Transform render_matrix;
   render_matrix.Translate(0.5 * output_rect.width() + output_rect.x(),
@@ -3701,3 +3709,5 @@ gfx::Size GLRenderer::GetRenderPassBackingPixelSize(
 }
 
 }  // namespace viz
+
+#undef PATCH_CS
diff --git a/components/viz/service/display/skia_renderer.cc b/components/viz/service/display/skia_renderer.cc
index 5a757c437d36f98d6d813ef2af81b46434cdc5de..86ed034d207fe5cdf6810de085cc34ea8981169c 100644
--- a/components/viz/service/display/skia_renderer.cc
+++ b/components/viz/service/display/skia_renderer.cc
@@ -708,9 +708,11 @@ void SkiaRenderer::DrawPictureQuad(const PictureDrawQuad* quad,
 
   std::unique_ptr<SkCanvas> color_transform_canvas;
   // TODO(enne): color transform needs to be replicated in gles2_cmd_decoder
-  color_transform_canvas = SkCreateColorSpaceXformCanvas(
-      current_canvas_, gfx::ColorSpace::CreateSRGB().ToSkColorSpace());
-  raster_canvas = color_transform_canvas.get();
+  if (settings_->enable_color_correct_rendering) {
+    color_transform_canvas = SkCreateColorSpaceXformCanvas(
+        current_canvas_, gfx::ColorSpace::CreateSRGB().ToSkColorSpace());
+    raster_canvas = color_transform_canvas.get();
+  }
 
   base::Optional<skia::OpacityFilterCanvas> opacity_canvas;
   if (needs_transparency || disable_image_filtering) {
diff --git a/components/viz/service/display/software_renderer.cc b/components/viz/service/display/software_renderer.cc
index 0aba701c131f11f5e8be6ce9c1bebe6ccb44edf8..aac9c128ed3d212758d8d4a3ec774b651491d92f 100644
--- a/components/viz/service/display/software_renderer.cc
+++ b/components/viz/service/display/software_renderer.cc
@@ -332,9 +332,11 @@ void SoftwareRenderer::DrawPictureQuad(const PictureDrawQuad* quad) {
 
   std::unique_ptr<SkCanvas> color_transform_canvas;
   // TODO(enne): color transform needs to be replicated in gles2_cmd_decoder
-  color_transform_canvas = SkCreateColorSpaceXformCanvas(
-      current_canvas_, gfx::ColorSpace::CreateSRGB().ToSkColorSpace());
-  raster_canvas = color_transform_canvas.get();
+  if (settings_->enable_color_correct_rendering) {
+    color_transform_canvas = SkCreateColorSpaceXformCanvas(
+        current_canvas_, gfx::ColorSpace::CreateSRGB().ToSkColorSpace());
+    raster_canvas = color_transform_canvas.get();
+  }
 
   base::Optional<skia::OpacityFilterCanvas> opacity_canvas;
   if (needs_transparency || disable_image_filtering) {
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc
index 1c93dfbc345d07769d7c91c8ecffc33bcd7505c1..ab87b6e5be09117e3dc1485a411ce72d3fa0d07f 100644
--- a/content/browser/gpu/gpu_process_host.cc
+++ b/content/browser/gpu/gpu_process_host.cc
@@ -193,6 +193,7 @@ GpuTerminationStatus ConvertToGpuTerminationStatus(
 
 // Command-line switches to propagate to the GPU process.
 static const char* const kSwitchNames[] = {
+    switches::kDisableColorCorrectRendering,
     service_manager::switches::kDisableSeccompFilterSandbox,
     service_manager::switches::kGpuSandboxAllowSysVShm,
     service_manager::switches::kGpuSandboxFailuresFatal,
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 553ba03f0e8b995d3a5b1c26242bf85565c0037b..47d2047662bec651c94bb0667bf51791abe2ca49 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -221,6 +221,7 @@
 #include "ui/base/ui_base_switches.h"
 #include "ui/base/ui_base_switches_util.h"
 #include "ui/display/display_switches.h"
+#include "ui/gfx/switches.h"
 #include "ui/gl/gl_switches.h"
 #include "ui/native_theme/native_theme_features.h"
 
@@ -3068,6 +3069,7 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
   // Propagate the following switches to the renderer command line (along
   // with any associated values) if present in the browser command line.
   static const char* const kSwitchNames[] = {
+    switches::kDisableColorCorrectRendering,
     network::switches::kNoReferrers,
     network::switches::kExplicitlyAllowedPorts,
     service_manager::switches::kDisableInProcessStackTraces,
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc
index 5223ac9b87817c99b84f6a6f98d3c96be54e466d..8d07310695af146b694b3342296439ccecb0d74e 100644
--- a/content/renderer/render_widget.cc
+++ b/content/renderer/render_widget.cc
@@ -2655,6 +2655,9 @@ cc::LayerTreeSettings RenderWidget::GenerateLayerTreeSettings(
   settings.main_frame_before_activation_enabled =
       cmd.HasSwitch(cc::switches::kEnableMainFrameBeforeActivation);
 
+  settings.enable_color_correct_rendering =
+    !cmd.HasSwitch(switches::kDisableColorCorrectRendering);
+
   // Checkerimaging is not supported for synchronous single-threaded mode, which
   // is what the renderer uses if its not threaded.
   settings.enable_checker_imaging =
diff --git a/ui/gfx/mac/io_surface.cc b/ui/gfx/mac/io_surface.cc
index d12f8a42cb6af501dad92483b957dcf33d76a6c9..fbc0ab37aef36b46a54c7afc54945161ce973834 100644
--- a/ui/gfx/mac/io_surface.cc
+++ b/ui/gfx/mac/io_surface.cc
@@ -16,6 +16,7 @@
 #include "base/trace_event/trace_event.h"
 #include "ui/gfx/buffer_format_util.h"
 #include "ui/gfx/icc_profile.h"
+#include "ui/gfx/switches.h"
 
 namespace gfx {
 
@@ -189,6 +190,11 @@ IOSurfaceRef CreateIOSurface(const gfx::Size& size,
 
   // Ensure that all IOSurfaces start as sRGB.
   CGColorSpaceRef color_space = base::mac::GetSRGBColorSpace();
+  auto* cmd_line = base::CommandLine::ForCurrentProcess();
+  if (cmd_line->HasSwitch(switches::kDisableColorCorrectRendering)) {
+    color_space = base::mac::GetSystemColorSpace();
+  }
+
   base::ScopedCFTypeRef<CFDataRef> color_space_icc(
       CGColorSpaceCopyICCProfile(color_space));
   IOSurfaceSetValue(surface, CFSTR("IOSurfaceColorSpace"), color_space_icc);
@@ -200,6 +206,14 @@ IOSurfaceRef CreateIOSurface(const gfx::Size& size,
 
 void IOSurfaceSetColorSpace(IOSurfaceRef io_surface,
                             const ColorSpace& color_space) {
+  auto* cmd_line = base::CommandLine::ForCurrentProcess();
+  if (cmd_line->HasSwitch(switches::kDisableColorCorrectRendering)) {
+    base::ScopedCFTypeRef<CFDataRef> system_icc(
+        CGColorSpaceCopyICCProfile(base::mac::GetSystemColorSpace()));
+    IOSurfaceSetValue(io_surface, CFSTR("IOSurfaceColorSpace"), system_icc);
+    return;
+  }
+
   // Special-case sRGB.
   if (color_space == ColorSpace::CreateSRGB()) {
     base::ScopedCFTypeRef<CFDataRef> srgb_icc(
diff --git a/ui/gfx/switches.cc b/ui/gfx/switches.cc
index 606cbb42070be3a826f73269cd2bf40454358b3d..bd31d565b002b653a6b104114c9616416ac86649 100644
--- a/ui/gfx/switches.cc
+++ b/ui/gfx/switches.cc
@@ -7,6 +7,8 @@
 
 namespace switches {
 
+const char kDisableColorCorrectRendering[] = "disable-color-correct-rendering";
+
 #if defined(OS_WIN)
 // Disables DirectWrite font rendering for general UI elements.
 const char kDisableDirectWriteForUI[] = "disable-directwrite-for-ui";
diff --git a/ui/gfx/switches.h b/ui/gfx/switches.h
index b206f18ad77c21774073c2fa07372d2234926414..992468ce95b2829702fcdb26c26362eccb5556c7 100644
--- a/ui/gfx/switches.h
+++ b/ui/gfx/switches.h
@@ -11,6 +11,8 @@
 
 namespace switches {
 
+GFX_SWITCHES_EXPORT extern const char kDisableColorCorrectRendering[];
+
 #if defined(OS_WIN)
 GFX_SWITCHES_EXPORT extern const char kDisableDirectWriteForUI[];
 #endif
