chromium/ui/color/win/native_color_mixers_win.cc

// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <windows.h>

#include "base/command_line.h"
#include "ui/color/color_id.h"
#include "ui/color/color_mixer.h"
#include "ui/color/color_provider.h"
#include "ui/color/color_provider_key.h"
#include "ui/color/color_provider_utils.h"
#include "ui/color/color_recipe.h"
#include "ui/color/color_transform.h"
#include "ui/color/win/accent_color_observer.h"
#include "ui/gfx/color_palette.h"
#include "ui/gfx/color_utils.h"

namespace ui {

// Maps the base set of sys color ids to appropriate platform defined high
// contrast colors.
void AddHighContrastSysColors(ColorMixer& mixer) {
  // Primary.
  mixer[kColorSysPrimary] = {kColorNativeWindow};
  mixer[kColorSysOnPrimary] = {kColorNativeWindowText};
  mixer[kColorSysPrimaryContainer] = {kColorNativeBtnFace};
  mixer[kColorSysOnPrimaryContainer] = {kColorNativeBtnText};
  // Secondary.
  mixer[kColorSysSecondary] = {kColorNativeWindow};
  mixer[kColorSysOnSecondary] = {kColorNativeWindowText};
  mixer[kColorSysSecondaryContainer] = {kColorNativeBtnFace};
  mixer[kColorSysOnSecondaryContainer] = {kColorNativeBtnText};
  // Tertiary.
  mixer[kColorSysTertiary] = {kColorNativeWindow};
  mixer[kColorSysOnTertiary] = {kColorNativeWindowText};
  mixer[kColorSysTertiaryContainer] = {kColorNativeBtnFace};
  mixer[kColorSysOnTertiaryContainer] = {kColorNativeBtnText};
  // Error.
  mixer[kColorSysError] = {kColorNativeWindow};
  mixer[kColorSysOnError] = {kColorNativeWindowText};
  mixer[kColorSysErrorContainer] = {kColorNativeBtnFace};
  mixer[kColorSysOnErrorContainer] = {kColorNativeBtnText};
  // Neutral.
  mixer[kColorSysOnSurface] = {kColorNativeBtnText};
  mixer[kColorSysOnSurfaceVariant] = {kColorNativeBtnText};
  mixer[kColorSysOutline] = {kColorNativeBtnText};
  mixer[kColorSysSurfaceVariant] = {kColorNativeBtnFace};
  // Inverse.
  mixer[kColorSysInversePrimary] = {kColorNativeWindow};
  mixer[kColorSysInverseSurface] = {kColorNativeWindow};
  mixer[kColorSysInverseOnSurface] = {kColorNativeWindowText};
  // Surfaces.
  mixer[kColorSysSurface] = {kColorNativeWindow};
  mixer[kColorSysSurface1] = {kColorNativeWindow};
  mixer[kColorSysSurface2] = {kColorNativeWindow};
  mixer[kColorSysSurface3] = {kColorNativeWindow};
  mixer[kColorSysSurface4] = {kColorNativeWindow};
  mixer[kColorSysSurface5] = {kColorNativeWindow};
  // General.
  mixer[kColorSysOnSurfaceSecondary] = {kColorNativeWindowText};
  mixer[kColorSysOnSurfaceSubtle] = {kColorNativeWindowText};
  mixer[kColorSysOnSurfacePrimary] = {kColorNativeWindowText};
  mixer[kColorSysOnSurfacePrimaryInactive] = {kColorNativeWindowText};
  mixer[kColorSysTonalContainer] = {kColorNativeBtnFace};
  mixer[kColorSysOnTonalContainer] = {kColorNativeBtnText};
  mixer[kColorSysTonalOutline] = {kColorNativeBtnText};
  mixer[kColorSysNeutralOutline] = {kColorNativeBtnText};
  mixer[kColorSysNeutralContainer] = {kColorNativeBtnFace};
  mixer[kColorSysDivider] = {kColorNativeBtnText};
  // Chrome surfaces.
  mixer[kColorSysBase] = {kColorNativeBtnFace};
  mixer[kColorSysBaseContainer] = {kColorNativeBtnFace};
  mixer[kColorSysBaseContainerElevated] = {kColorNativeBtnFace};
  mixer[kColorSysHeader] = {kColorNativeWindow};
  mixer[kColorSysHeaderInactive] = {kColorNativeWindow};
  mixer[kColorSysHeaderContainer] = {kColorNativeBtnFace};
  mixer[kColorSysHeaderContainerInactive] = {kColorNativeBtnFace};
  mixer[kColorSysOnHeaderDivider] = {kColorNativeWindowText};
  mixer[kColorSysOnHeaderDividerInactive] = {kColorNativeWindowText};
  mixer[kColorSysOnHeaderPrimary] = {kColorNativeWindowText};
  mixer[kColorSysOnHeaderPrimaryInactive] = {kColorNativeWindowText};
  // States.
  mixer[kColorSysStateDisabled] = {kColorNativeGrayText};
  mixer[kColorSysStateDisabledContainer] = {kColorNativeWindow};
  // Effects.
  mixer[kColorSysShadow] = {kColorNativeBtnShadow};
  // Experimentation.
  mixer[kColorSysOmniboxContainer] = {kColorNativeBtnFace};
}

void AddNativeCoreColorMixer(ColorProvider* provider,
                             const ColorProviderKey& key) {
  ColorMixer& mixer = provider->AddMixer();

  // TODO(pkasting): Not clear whether this is really the set of interest.
  // Maybe there's some way to query colors used by UxTheme.dll, or maybe we
  // should be hardcoding a list of colors for system light/dark modes based on
  // reverse-engineering current Windows behavior.  Or maybe the union of all
  // these.
  mixer[kColorNative3dDkShadow] = {
      color_utils::GetSysSkColor(COLOR_3DDKSHADOW)};
  mixer[kColorNative3dLight] = {color_utils::GetSysSkColor(COLOR_3DLIGHT)};
  mixer[kColorNativeActiveBorder] = {
      color_utils::GetSysSkColor(COLOR_ACTIVEBORDER)};
  mixer[kColorNativeActiveCaption] = {
      color_utils::GetSysSkColor(COLOR_ACTIVECAPTION)};
  mixer[kColorNativeAppWorkspace] = {
      color_utils::GetSysSkColor(COLOR_APPWORKSPACE)};
  mixer[kColorNativeBackground] = {
      color_utils::GetSysSkColor(COLOR_BACKGROUND)};
  mixer[kColorNativeBtnFace] = {color_utils::GetSysSkColor(COLOR_BTNFACE)};
  mixer[kColorNativeBtnHighlight] = {
      color_utils::GetSysSkColor(COLOR_BTNHIGHLIGHT)};
  mixer[kColorNativeBtnShadow] = {color_utils::GetSysSkColor(COLOR_BTNSHADOW)};
  mixer[kColorNativeBtnText] = {color_utils::GetSysSkColor(COLOR_BTNTEXT)};
  mixer[kColorNativeCaptionText] = {
      color_utils::GetSysSkColor(COLOR_CAPTIONTEXT)};
  mixer[kColorNativeGradientActiveCaption] = {
      color_utils::GetSysSkColor(COLOR_GRADIENTACTIVECAPTION)};
  mixer[kColorNativeGradientInactiveCaption] = {
      color_utils::GetSysSkColor(COLOR_GRADIENTINACTIVECAPTION)};
  mixer[kColorNativeGrayText] = {color_utils::GetSysSkColor(COLOR_GRAYTEXT)};
  mixer[kColorNativeHighlight] = {color_utils::GetSysSkColor(COLOR_HIGHLIGHT)};
  mixer[kColorNativeHighlightText] = {
      color_utils::GetSysSkColor(COLOR_HIGHLIGHTTEXT)};
  mixer[kColorNativeHotlight] = {color_utils::GetSysSkColor(COLOR_HOTLIGHT)};
  mixer[kColorNativeInactiveBorder] = {
      color_utils::GetSysSkColor(COLOR_INACTIVEBORDER)};
  mixer[kColorNativeInactiveCaption] = {
      color_utils::GetSysSkColor(COLOR_INACTIVECAPTION)};
  mixer[kColorNativeInactiveCaptionText] = {
      color_utils::GetSysSkColor(COLOR_INACTIVECAPTIONTEXT)};
  mixer[kColorNativeInfoBk] = {color_utils::GetSysSkColor(COLOR_INFOBK)};
  mixer[kColorNativeInfoText] = {color_utils::GetSysSkColor(COLOR_INFOTEXT)};
  mixer[kColorNativeMenu] = {color_utils::GetSysSkColor(COLOR_MENU)};
  mixer[kColorNativeMenuBar] = {color_utils::GetSysSkColor(COLOR_MENUBAR)};
  mixer[kColorNativeMenuHilight] = {
      color_utils::GetSysSkColor(COLOR_MENUHILIGHT)};
  mixer[kColorNativeMenuText] = {color_utils::GetSysSkColor(COLOR_MENUTEXT)};
  mixer[kColorNativeScrollbar] = {color_utils::GetSysSkColor(COLOR_SCROLLBAR)};
  mixer[kColorNativeWindow] = {color_utils::GetSysSkColor(COLOR_WINDOW)};
  mixer[kColorNativeWindowFrame] = {
      color_utils::GetSysSkColor(COLOR_WINDOWFRAME)};
  mixer[kColorNativeWindowText] = {
      color_utils::GetSysSkColor(COLOR_WINDOWTEXT)};

  // Use the system accent color as the Chrome accent color, if present and only
  // if dwm colors are enabled.
  const auto* accent_color_observer = AccentColorObserver::Get();
  const auto& accent_color = accent_color_observer->accent_color();
  if (accent_color.has_value() &&
      accent_color_observer->use_dwm_frame_color()) {
    mixer[kColorAccent] = PickGoogleColor(accent_color.value());
  }

  if (key.contrast_mode == ColorProviderKey::ContrastMode::kHigh) {
    AddHighContrastSysColors(mixer);
  }
}

void AddNativeUiColorMixer(ColorProvider* provider,
                           const ColorProviderKey& key) {
  if (key.contrast_mode == ColorProviderKey::ContrastMode::kNormal) {
    return;
  }

  ColorMixer& mixer = provider->AddMixer();

  mixer[kColorNotificationInputPlaceholderForeground] =
      SetAlpha(kColorNotificationInputForeground, gfx::kGoogleGreyAlpha700);
  mixer[kColorSliderTrack] = AlphaBlend(
      kColorNativeHighlight, kColorNativeWindow, gfx::kGoogleGreyAlpha400);

  // Window Background
  mixer[kColorBubbleFooterBackground] = {kColorNativeWindow};
  mixer[kColorButtonBackgroundProminentDisabled] = {kColorNativeWindow};
  mixer[kColorFrameActive] = {kColorNativeWindow};
  mixer[kColorFrameInactive] = {kColorNativeWindow};
  mixer[kColorPrimaryBackground] = {kColorNativeWindow};
  mixer[kColorTooltipBackground] = {kColorNativeWindow};

  // Window Text
  mixer[kColorAlertLowSeverity] = {kColorNativeWindowText};
  mixer[kColorAlertMediumSeverityIcon] = {kColorNativeWindowText};
  mixer[kColorAlertMediumSeverityText] = {kColorNativeWindowText};
  mixer[kColorAlertHighSeverity] = {kColorNativeWindowText};
  mixer[kColorIcon] = {kColorNativeWindowText};
  mixer[kColorMidground] = {kColorNativeWindowText};
  mixer[kColorPrimaryForeground] = {kColorNativeWindowText};
  mixer[kColorSecondaryForeground] = {kColorNativeWindowText};
  mixer[kColorTableGroupingIndicator] = {kColorNativeWindowText};
  mixer[kColorThrobber] = {kColorNativeWindowText};
  mixer[kColorTooltipForeground] = {kColorNativeWindowText};

  // Hyperlinks
  mixer[kColorLinkForegroundDefault] = {kColorNativeHotlight};
  mixer[kColorMenuItemForegroundHighlighted] = {kColorNativeHotlight};

  // Gray/Disabled Text
  mixer[kColorDisabledForeground] = {kColorNativeGrayText};
  mixer[kColorMenuItemForegroundDisabled] = {kColorNativeGrayText};
  mixer[kColorLinkForegroundDisabled] = {kColorNativeGrayText};
  mixer[kColorLabelForegroundDisabled] = {kColorNativeGrayText};
  mixer[kColorButtonForegroundDisabled] = {kColorNativeGrayText};
  mixer[kColorThrobberPreconnect] = {kColorNativeGrayText};

  // Button Background
  mixer[kColorButtonBackground] = {kColorNativeBtnFace};
  mixer[kColorComboboxBackground] = {kColorNativeBtnFace};
  mixer[kColorMenuBackground] = {kColorNativeBtnFace};
  mixer[kColorSliderTrack] = {kColorNativeBtnFace};
  mixer[kColorSliderTrackMinimal] = {kColorNativeBtnFace};
  mixer[kColorSubtleEmphasisBackground] = {kColorNativeBtnFace};
  mixer[kColorTextfieldBackground] = {kColorNativeBtnFace};
  mixer[kColorTextfieldBackgroundDisabled] = {kColorNativeBtnFace};

  // Button Text Foreground
  mixer[kColorButtonForeground] = {kColorNativeBtnText};
  mixer[kColorCheckboxForegroundChecked] = {kColorNativeBtnText};
  mixer[kColorFocusableBorderFocused] = {kColorNativeBtnText};
  mixer[kColorFocusableBorderUnfocused] = {kColorNativeBtnText};
  mixer[kColorMenuBorder] = {kColorNativeBtnText};
  mixer[kColorMenuItemForeground] = {kColorNativeBtnText};
  mixer[kColorMenuItemForegroundSecondary] = {kColorNativeBtnText};
  mixer[kColorMenuSeparator] = {kColorNativeBtnText};
  mixer[kColorRadioButtonForegroundChecked] = {kColorNativeBtnText};
  mixer[kColorSeparator] = {kColorNativeBtnText};
  mixer[kColorSliderThumb] = {kColorNativeBtnText};
  mixer[kColorSliderThumbMinimal] = {kColorNativeBtnText};
  mixer[kColorTabContentSeparator] = {kColorNativeBtnText};
  mixer[kColorTabForeground] = {kColorNativeBtnText};
  mixer[kColorTabForegroundSelected] = {kColorNativeBtnText};
  mixer[kColorTextfieldForeground] = {kColorNativeBtnText};
  mixer[kColorTextfieldForegroundPlaceholder] = {kColorNativeBtnText};
  mixer[kColorTextfieldForegroundDisabled] = {kColorNativeBtnText};

  // Highlight/Selected Background
  mixer[kColorAccent] = {kColorNativeHighlight};
  mixer[kColorButtonBackgroundProminent] = {kColorNativeHighlight};
  mixer[kColorButtonBorder] = {kColorNativeHighlight};
  mixer[kColorButtonBackgroundProminentFocused] = {kColorNativeHighlight};
  mixer[kColorHelpIconActive] = {kColorNativeHighlight};
  mixer[kColorItemSelectionBackground] = {kColorNativeHighlight};
  mixer[kColorMenuSelectionBackground] = {kColorNativeHighlight};
  mixer[kColorSubtleAccent] = {kColorNativeHighlight};
  mixer[kColorTextfieldSelectionBackground] = {kColorNativeHighlight};
  mixer[kColorTextSelectionBackground] = {kColorNativeHighlight};

  // Highlight/Selected Text Foreground
  mixer[kColorButtonForegroundProminent] = {kColorNativeHighlightText};
  mixer[kColorMenuItemForegroundSelected] = {kColorNativeHighlightText};
  mixer[kColorNotificationInputForeground] = {kColorNativeHighlightText};
  mixer[kColorTableForegroundSelectedFocused] = {kColorNativeHighlightText};
  mixer[kColorTableForegroundSelectedUnfocused] = {kColorNativeHighlightText};
  mixer[kColorTextSelectionForeground] = {kColorNativeHighlightText};
  mixer[kColorTreeNodeForegroundSelectedFocused] = {kColorNativeHighlightText};
  mixer[kColorTreeNodeForegroundSelectedUnfocused] = {
      kColorNativeHighlightText};
  mixer[kColorButtonForegroundProminent] = {kColorNativeHighlightText};
}

}  // namespace ui