mirror of
				https://github.com/mozilla/gecko-dev.git
				synced 2025-11-03 17:58:55 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			1553 lines
		
	
	
	
		
			50 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1553 lines
		
	
	
	
		
			50 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/* -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | 
						|
/* This Source Code Form is subject to the terms of the Mozilla Public
 | 
						|
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 | 
						|
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | 
						|
 | 
						|
#include "mozilla/ArrayUtils.h"
 | 
						|
 | 
						|
#include "mozilla/LookAndFeel.h"
 | 
						|
#include "nscore.h"
 | 
						|
 | 
						|
#include "nsXPLookAndFeel.h"
 | 
						|
#include "nsLookAndFeel.h"
 | 
						|
#include "HeadlessLookAndFeel.h"
 | 
						|
#include "RemoteLookAndFeel.h"
 | 
						|
#include "nsContentUtils.h"
 | 
						|
#include "nsCRT.h"
 | 
						|
#include "nsFont.h"
 | 
						|
#include "nsIFrame.h"
 | 
						|
#include "nsIXULRuntime.h"
 | 
						|
#include "nsLayoutUtils.h"
 | 
						|
#include "Theme.h"
 | 
						|
#include "SurfaceCacheUtils.h"
 | 
						|
#include "mozilla/dom/ContentParent.h"
 | 
						|
#include "mozilla/dom/ContentChild.h"
 | 
						|
#include "mozilla/Preferences.h"
 | 
						|
#include "mozilla/Services.h"
 | 
						|
#include "mozilla/ServoStyleSet.h"
 | 
						|
#include "mozilla/ServoCSSParser.h"
 | 
						|
#include "mozilla/StaticPrefs_browser.h"
 | 
						|
#include "mozilla/StaticPrefs_editor.h"
 | 
						|
#include "mozilla/StaticPrefs_layout.h"
 | 
						|
#include "mozilla/StaticPrefs_ui.h"
 | 
						|
#include "mozilla/StaticPrefs_widget.h"
 | 
						|
#include "mozilla/dom/Document.h"
 | 
						|
#include "mozilla/PreferenceSheet.h"
 | 
						|
#include "mozilla/gfx/2D.h"
 | 
						|
#include "mozilla/widget/WidgetMessageUtils.h"
 | 
						|
#include "mozilla/dom/KeyboardEventBinding.h"
 | 
						|
#include "mozilla/RelativeLuminanceUtils.h"
 | 
						|
#include "mozilla/Telemetry.h"
 | 
						|
#include "mozilla/TelemetryScalarEnums.h"
 | 
						|
#include "mozilla/Try.h"
 | 
						|
 | 
						|
#include "gfxPlatform.h"
 | 
						|
#include "gfxFont.h"
 | 
						|
 | 
						|
#include "qcms.h"
 | 
						|
 | 
						|
#include <bitset>
 | 
						|
 | 
						|
using namespace mozilla;
 | 
						|
 | 
						|
using IntID = mozilla::LookAndFeel::IntID;
 | 
						|
using FloatID = mozilla::LookAndFeel::FloatID;
 | 
						|
using ColorID = mozilla::LookAndFeel::ColorID;
 | 
						|
using FontID = mozilla::LookAndFeel::FontID;
 | 
						|
 | 
						|
template <typename Index, typename Value, Index kEnd>
 | 
						|
class EnumeratedCache {
 | 
						|
  mozilla::EnumeratedArray<Index, Value, size_t(kEnd)> mEntries;
 | 
						|
  std::bitset<size_t(kEnd)> mValidity;
 | 
						|
 | 
						|
 public:
 | 
						|
  constexpr EnumeratedCache() = default;
 | 
						|
 | 
						|
  bool IsValid(Index aIndex) const { return mValidity[size_t(aIndex)]; }
 | 
						|
 | 
						|
  const Value* Get(Index aIndex) const {
 | 
						|
    return IsValid(aIndex) ? &mEntries[aIndex] : nullptr;
 | 
						|
  }
 | 
						|
 | 
						|
  void Insert(Index aIndex, Value aValue) {
 | 
						|
    mValidity[size_t(aIndex)] = true;
 | 
						|
    mEntries[aIndex] = aValue;
 | 
						|
  }
 | 
						|
 | 
						|
  void Remove(Index aIndex) {
 | 
						|
    mValidity[size_t(aIndex)] = false;
 | 
						|
    mEntries[aIndex] = Value();
 | 
						|
  }
 | 
						|
 | 
						|
  void Clear() {
 | 
						|
    mValidity.reset();
 | 
						|
    for (auto& entry : mEntries) {
 | 
						|
      entry = Value();
 | 
						|
    }
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
using ColorCache = EnumeratedCache<ColorID, Maybe<nscolor>, ColorID::End>;
 | 
						|
 | 
						|
struct ColorCaches {
 | 
						|
  using UseStandins = LookAndFeel::UseStandins;
 | 
						|
 | 
						|
  ColorCache mCaches[2][2];
 | 
						|
 | 
						|
  constexpr ColorCaches() = default;
 | 
						|
 | 
						|
  ColorCache& Get(ColorScheme aScheme, UseStandins aUseStandins) {
 | 
						|
    return mCaches[aScheme == ColorScheme::Dark]
 | 
						|
                  [aUseStandins == UseStandins::Yes];
 | 
						|
  }
 | 
						|
 | 
						|
  void Clear() {
 | 
						|
    for (auto& c : mCaches) {
 | 
						|
      for (auto& cache : c) {
 | 
						|
        cache.Clear();
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
static ColorCaches sColorCaches;
 | 
						|
 | 
						|
static EnumeratedCache<FloatID, Maybe<float>, FloatID::End> sFloatCache;
 | 
						|
static EnumeratedCache<IntID, Maybe<int32_t>, IntID::End> sIntCache;
 | 
						|
static EnumeratedCache<FontID, widget::LookAndFeelFont, FontID::End> sFontCache;
 | 
						|
 | 
						|
// To make one of these prefs toggleable from a reftest add a user
 | 
						|
// pref in testing/profiles/reftest/user.js. For example, to make
 | 
						|
// ui.useAccessibilityTheme toggleable, add:
 | 
						|
//
 | 
						|
// user_pref("ui.useAccessibilityTheme", 0);
 | 
						|
//
 | 
						|
// This needs to be of the same length and in the same order as
 | 
						|
// LookAndFeel::IntID values.
 | 
						|
static const char sIntPrefs[][45] = {
 | 
						|
    "ui.caretBlinkTime",
 | 
						|
    "ui.caretBlinkCount",
 | 
						|
    "ui.caretWidth",
 | 
						|
    "ui.selectTextfieldsOnKeyFocus",
 | 
						|
    "ui.submenuDelay",
 | 
						|
    "ui.menusCanOverlapOSBar",
 | 
						|
    "ui.useOverlayScrollbars",
 | 
						|
    "ui.allowOverlayScrollbarsOverlap",
 | 
						|
    "ui.skipNavigatingDisabledMenuItem",
 | 
						|
    "ui.dragThresholdX",
 | 
						|
    "ui.dragThresholdY",
 | 
						|
    "ui.useAccessibilityTheme",
 | 
						|
    "ui.scrollArrowStyle",
 | 
						|
    "ui.scrollButtonLeftMouseButtonAction",
 | 
						|
    "ui.scrollButtonMiddleMouseButtonAction",
 | 
						|
    "ui.scrollButtonRightMouseButtonAction",
 | 
						|
    "ui.treeOpenDelay",
 | 
						|
    "ui.treeCloseDelay",
 | 
						|
    "ui.treeLazyScrollDelay",
 | 
						|
    "ui.treeScrollDelay",
 | 
						|
    "ui.treeScrollLinesMax",
 | 
						|
    "ui.chosenMenuItemsShouldBlink",
 | 
						|
    "ui.windowsAccentColorInTitlebar",
 | 
						|
    "ui.macBigSurTheme",
 | 
						|
    "ui.macRTL",
 | 
						|
    "ui.macTitlebarHeight",
 | 
						|
    "ui.alertNotificationOrigin",
 | 
						|
    "ui.scrollToClick",
 | 
						|
    "ui.IMERawInputUnderlineStyle",
 | 
						|
    "ui.IMESelectedRawTextUnderlineStyle",
 | 
						|
    "ui.IMEConvertedTextUnderlineStyle",
 | 
						|
    "ui.IMESelectedConvertedTextUnderlineStyle",
 | 
						|
    "ui.SpellCheckerUnderlineStyle",
 | 
						|
    "ui.menuBarDrag",
 | 
						|
    "ui.scrollbarButtonAutoRepeatBehavior",
 | 
						|
    "ui.swipeAnimationEnabled",
 | 
						|
    "ui.scrollbarDisplayOnMouseMove",
 | 
						|
    "ui.scrollbarFadeBeginDelay",
 | 
						|
    "ui.scrollbarFadeDuration",
 | 
						|
    "ui.contextMenuOffsetVertical",
 | 
						|
    "ui.contextMenuOffsetHorizontal",
 | 
						|
    "ui.tooltipOffsetVertical",
 | 
						|
    "ui.GtkCSDAvailable",
 | 
						|
    "ui.GtkCSDMinimizeButton",
 | 
						|
    "ui.GtkCSDMaximizeButton",
 | 
						|
    "ui.GtkCSDCloseButton",
 | 
						|
    "ui.GtkCSDMinimizeButtonPosition",
 | 
						|
    "ui.GtkCSDMaximizeButtonPosition",
 | 
						|
    "ui.GtkCSDCloseButtonPosition",
 | 
						|
    "ui.GtkCSDReversedPlacement",
 | 
						|
    "ui.systemUsesDarkTheme",
 | 
						|
    "ui.prefersReducedMotion",
 | 
						|
    "ui.prefersReducedTransparency",
 | 
						|
    "ui.invertedColors",
 | 
						|
    "ui.primaryPointerCapabilities",
 | 
						|
    "ui.allPointerCapabilities",
 | 
						|
    "ui.systemScrollbarSize",
 | 
						|
    "ui.touchDeviceSupportPresent",
 | 
						|
    "ui.titlebarRadius",
 | 
						|
    "ui.titlebarButtonSpacing",
 | 
						|
    "ui.dynamicRange",
 | 
						|
    "ui.panelAnimations",
 | 
						|
    "ui.hideCursorWhileTyping",
 | 
						|
    "ui.gtkThemeFamily",
 | 
						|
    "ui.fullKeyboardAccess",
 | 
						|
};
 | 
						|
 | 
						|
static_assert(ArrayLength(sIntPrefs) == size_t(LookAndFeel::IntID::End),
 | 
						|
              "Should have a pref for each int value");
 | 
						|
 | 
						|
// This array MUST be kept in the same order as the float id list in
 | 
						|
// LookAndFeel.h
 | 
						|
// clang-format off
 | 
						|
static const char sFloatPrefs[][37] = {
 | 
						|
    "ui.IMEUnderlineRelativeSize",
 | 
						|
    "ui.SpellCheckerUnderlineRelativeSize",
 | 
						|
    "ui.caretAspectRatio",
 | 
						|
    "ui.textScaleFactor",
 | 
						|
    "ui.cursorScale",
 | 
						|
};
 | 
						|
// clang-format on
 | 
						|
 | 
						|
static_assert(ArrayLength(sFloatPrefs) == size_t(LookAndFeel::FloatID::End),
 | 
						|
              "Should have a pref for each float value");
 | 
						|
 | 
						|
// This array MUST be kept in the same order as the color list in
 | 
						|
// specified/color.rs
 | 
						|
static const char sColorPrefs[][41] = {
 | 
						|
    "ui.activeborder",
 | 
						|
    "ui.activecaption",
 | 
						|
    "ui.appworkspace",
 | 
						|
    "ui.background",
 | 
						|
    "ui.buttonface",
 | 
						|
    "ui.buttonhighlight",
 | 
						|
    "ui.buttonshadow",
 | 
						|
    "ui.buttontext",
 | 
						|
    "ui.buttonborder",
 | 
						|
    "ui.captiontext",
 | 
						|
    "ui.-moz-field",
 | 
						|
    "ui.-moz-disabledfield",
 | 
						|
    "ui.-moz-fieldtext",
 | 
						|
    "ui.mark",
 | 
						|
    "ui.marktext",
 | 
						|
    "ui.-moz-comboboxtext",
 | 
						|
    "ui.-moz-combobox",
 | 
						|
    "ui.graytext",
 | 
						|
    "ui.highlight",
 | 
						|
    "ui.highlighttext",
 | 
						|
    "ui.inactiveborder",
 | 
						|
    "ui.inactivecaption",
 | 
						|
    "ui.inactivecaptiontext",
 | 
						|
    "ui.infobackground",
 | 
						|
    "ui.infotext",
 | 
						|
    "ui.menu",
 | 
						|
    "ui.menutext",
 | 
						|
    "ui.scrollbar",
 | 
						|
    "ui.threeddarkshadow",
 | 
						|
    "ui.threedface",
 | 
						|
    "ui.threedhighlight",
 | 
						|
    "ui.threedlightshadow",
 | 
						|
    "ui.threedshadow",
 | 
						|
    "ui.window",
 | 
						|
    "ui.windowframe",
 | 
						|
    "ui.windowtext",
 | 
						|
    "ui.-moz-default-color",
 | 
						|
    "ui.-moz-default-background-color",
 | 
						|
    "ui.-moz-dialog",
 | 
						|
    "ui.-moz-dialogtext",
 | 
						|
    "ui.-moz-cellhighlight",
 | 
						|
    "ui.-moz_cellhighlighttext",
 | 
						|
    "ui.selecteditem",
 | 
						|
    "ui.selecteditemtext",
 | 
						|
    "ui.-moz-buttonhoverface",
 | 
						|
    "ui.-moz_buttonhovertext",
 | 
						|
    "ui.-moz_menuhover",
 | 
						|
    "ui.-moz_menuhoverdisabled",
 | 
						|
    "ui.-moz_menuhovertext",
 | 
						|
    "ui.-moz_menubarhovertext",
 | 
						|
    "ui.-moz_eventreerow",
 | 
						|
    "ui.-moz_oddtreerow",
 | 
						|
    "ui.-moz-buttonactivetext",
 | 
						|
    "ui.-moz-buttonactiveface",
 | 
						|
    "ui.-moz-buttondisabledface",
 | 
						|
    "ui.-moz-headerbar",
 | 
						|
    "ui.-moz-headerbartext",
 | 
						|
    "ui.-moz-headerbarinactive",
 | 
						|
    "ui.-moz-headerbarinactivetext",
 | 
						|
    "ui.-moz-mac-defaultbuttontext",
 | 
						|
    "ui.-moz-mac-focusring",
 | 
						|
    "ui.-moz_mac_disabledtoolbartext",
 | 
						|
    "ui.-moz-sidebar",
 | 
						|
    "ui.-moz-sidebartext",
 | 
						|
    "ui.-moz-sidebarborder",
 | 
						|
    "ui.accentcolor",
 | 
						|
    "ui.accentcolortext",
 | 
						|
    "ui.-moz-autofill-background",
 | 
						|
    "ui.-moz-nativehyperlinktext",
 | 
						|
    "ui.-moz-nativevisitedhyperlinktext",
 | 
						|
    "ui.-moz-hyperlinktext",
 | 
						|
    "ui.-moz-activehyperlinktext",
 | 
						|
    "ui.-moz-visitedhyperlinktext",
 | 
						|
    "ui.-moz-colheader",
 | 
						|
    "ui.-moz-colheadertext",
 | 
						|
    "ui.-moz-colheaderhover",
 | 
						|
    "ui.-moz-colheaderhovertext",
 | 
						|
    "ui.-moz-colheaderactive",
 | 
						|
    "ui.-moz-colheaderactivetext",
 | 
						|
    "ui.textSelectDisabledBackground",
 | 
						|
    "ui.textSelectAttentionBackground",
 | 
						|
    "ui.textSelectAttentionForeground",
 | 
						|
    "ui.textHighlightBackground",
 | 
						|
    "ui.textHighlightForeground",
 | 
						|
    "ui.targetTextBackground",
 | 
						|
    "ui.targetTextForeground",
 | 
						|
    "ui.IMERawInputBackground",
 | 
						|
    "ui.IMERawInputForeground",
 | 
						|
    "ui.IMERawInputUnderline",
 | 
						|
    "ui.IMESelectedRawTextBackground",
 | 
						|
    "ui.IMESelectedRawTextForeground",
 | 
						|
    "ui.IMESelectedRawTextUnderline",
 | 
						|
    "ui.IMEConvertedTextBackground",
 | 
						|
    "ui.IMEConvertedTextForeground",
 | 
						|
    "ui.IMEConvertedTextUnderline",
 | 
						|
    "ui.IMESelectedConvertedTextBackground",
 | 
						|
    "ui.IMESelectedConvertedTextForeground",
 | 
						|
    "ui.IMESelectedConvertedTextUnderline",
 | 
						|
    "ui.SpellCheckerUnderline",
 | 
						|
    "ui.themedScrollbar",
 | 
						|
    "ui.themedScrollbarInactive",
 | 
						|
    "ui.themedScrollbarThumb",
 | 
						|
    "ui.themedScrollbarThumbHover",
 | 
						|
    "ui.themedScrollbarThumbActive",
 | 
						|
    "ui.themedScrollbarThumbInactive",
 | 
						|
};
 | 
						|
 | 
						|
static_assert(ArrayLength(sColorPrefs) == size_t(LookAndFeel::ColorID::End),
 | 
						|
              "Should have a pref for each color value");
 | 
						|
 | 
						|
// This array MUST be kept in the same order as the SystemFont enum.
 | 
						|
static const char sFontPrefs[][41] = {
 | 
						|
    "ui.font.caption",
 | 
						|
    "ui.font.icon",
 | 
						|
    "ui.font.menu",
 | 
						|
    "ui.font.message-box",
 | 
						|
    "ui.font.small-caption",
 | 
						|
    "ui.font.status-bar",
 | 
						|
    "ui.font.-moz-pull-down-menu",
 | 
						|
    "ui.font.-moz-button",
 | 
						|
    "ui.font.-moz-list",
 | 
						|
    "ui.font.-moz-field",
 | 
						|
};
 | 
						|
 | 
						|
static_assert(ArrayLength(sFontPrefs) == size_t(LookAndFeel::FontID::End),
 | 
						|
              "Should have a pref for each font value");
 | 
						|
 | 
						|
const char* nsXPLookAndFeel::GetColorPrefName(ColorID aId) {
 | 
						|
  return sColorPrefs[size_t(aId)];
 | 
						|
}
 | 
						|
 | 
						|
bool nsXPLookAndFeel::sInitialized = false;
 | 
						|
 | 
						|
nsXPLookAndFeel* nsXPLookAndFeel::sInstance = nullptr;
 | 
						|
bool nsXPLookAndFeel::sShutdown = false;
 | 
						|
 | 
						|
auto LookAndFeel::SystemZoomSettings() -> ZoomSettings {
 | 
						|
  ZoomSettings settings;
 | 
						|
  switch (StaticPrefs::browser_display_os_zoom_behavior()) {
 | 
						|
    case 0:
 | 
						|
    default:
 | 
						|
      break;
 | 
						|
    case 1:
 | 
						|
      settings.mFullZoom = GetTextScaleFactor();
 | 
						|
      break;
 | 
						|
    case 2:
 | 
						|
      settings.mTextZoom = GetTextScaleFactor();
 | 
						|
      break;
 | 
						|
  }
 | 
						|
  return settings;
 | 
						|
}
 | 
						|
 | 
						|
// static
 | 
						|
nsXPLookAndFeel* nsXPLookAndFeel::GetInstance() {
 | 
						|
  if (sInstance) {
 | 
						|
    return sInstance;
 | 
						|
  }
 | 
						|
 | 
						|
  NS_ENSURE_TRUE(!sShutdown, nullptr);
 | 
						|
 | 
						|
  // If we're in a content process, then the parent process will have supplied
 | 
						|
  // us with an initial FullLookAndFeel object.
 | 
						|
  // We grab this data from the ContentChild,
 | 
						|
  // where it's been temporarily stashed, and initialize our new LookAndFeel
 | 
						|
  // object with it.
 | 
						|
 | 
						|
  FullLookAndFeel* lnf = nullptr;
 | 
						|
 | 
						|
  if (auto* cc = mozilla::dom::ContentChild::GetSingleton()) {
 | 
						|
    lnf = &cc->BorrowLookAndFeelData();
 | 
						|
  }
 | 
						|
 | 
						|
  if (lnf) {
 | 
						|
    sInstance = new widget::RemoteLookAndFeel(std::move(*lnf));
 | 
						|
  } else if (gfxPlatform::IsHeadless()) {
 | 
						|
    sInstance = new widget::HeadlessLookAndFeel();
 | 
						|
  } else {
 | 
						|
    sInstance = new nsLookAndFeel();
 | 
						|
  }
 | 
						|
 | 
						|
  // This is only ever used once during initialization, and can be cleared now.
 | 
						|
  if (lnf) {
 | 
						|
    *lnf = {};
 | 
						|
  }
 | 
						|
 | 
						|
  widget::Theme::Init();
 | 
						|
  return sInstance;
 | 
						|
}
 | 
						|
 | 
						|
// static
 | 
						|
void nsXPLookAndFeel::Shutdown() {
 | 
						|
  if (sShutdown) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  sShutdown = true;
 | 
						|
  delete sInstance;
 | 
						|
  sInstance = nullptr;
 | 
						|
 | 
						|
  // This keeps strings alive, so need to clear to make leak checking happy.
 | 
						|
  sFontCache.Clear();
 | 
						|
 | 
						|
  widget::Theme::Shutdown();
 | 
						|
}
 | 
						|
 | 
						|
static void IntPrefChanged(const nsACString& aPref) {
 | 
						|
  // Most Int prefs can't change our system colors or fonts, but
 | 
						|
  // ui.systemUsesDarkTheme can, since it affects the effective color-scheme
 | 
						|
  // (affecting system colors).
 | 
						|
  auto changeKind = aPref.EqualsLiteral("ui.systemUsesDarkTheme")
 | 
						|
                        ? widget::ThemeChangeKind::Style
 | 
						|
                        : widget::ThemeChangeKind::MediaQueriesOnly;
 | 
						|
  LookAndFeel::NotifyChangedAllWindows(changeKind);
 | 
						|
}
 | 
						|
 | 
						|
static void FloatPrefChanged(const nsACString& aPref) {
 | 
						|
  // Most float prefs can't change our system colors or fonts, but
 | 
						|
  // textScaleFactor affects layout.
 | 
						|
  auto changeKind = aPref.EqualsLiteral("ui.textScaleFactor")
 | 
						|
                        ? widget::ThemeChangeKind::StyleAndLayout
 | 
						|
                        : widget::ThemeChangeKind::MediaQueriesOnly;
 | 
						|
  LookAndFeel::NotifyChangedAllWindows(changeKind);
 | 
						|
}
 | 
						|
 | 
						|
static void ColorPrefChanged() {
 | 
						|
  // Color prefs affect style, because they by definition change system colors.
 | 
						|
  LookAndFeel::NotifyChangedAllWindows(widget::ThemeChangeKind::Style);
 | 
						|
}
 | 
						|
 | 
						|
static void FontPrefChanged() {
 | 
						|
  // Color prefs affect style, because they by definition change system fonts.
 | 
						|
  LookAndFeel::NotifyChangedAllWindows(widget::ThemeChangeKind::Style);
 | 
						|
}
 | 
						|
 | 
						|
// static
 | 
						|
void nsXPLookAndFeel::OnPrefChanged(const char* aPref, void* aClosure) {
 | 
						|
  nsDependentCString prefName(aPref);
 | 
						|
  for (const char* pref : sIntPrefs) {
 | 
						|
    if (prefName.Equals(pref)) {
 | 
						|
      IntPrefChanged(prefName);
 | 
						|
      return;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  for (const char* pref : sFloatPrefs) {
 | 
						|
    if (prefName.Equals(pref)) {
 | 
						|
      FloatPrefChanged(prefName);
 | 
						|
      return;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  for (const char* pref : sColorPrefs) {
 | 
						|
    // We use StringBeginsWith to handle .dark prefs too.
 | 
						|
    if (StringBeginsWith(prefName, nsDependentCString(pref))) {
 | 
						|
      ColorPrefChanged();
 | 
						|
      return;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  for (const char* pref : sFontPrefs) {
 | 
						|
    if (StringBeginsWith(prefName, nsDependentCString(pref))) {
 | 
						|
      FontPrefChanged();
 | 
						|
      return;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
static constexpr struct {
 | 
						|
  nsLiteralCString mName;
 | 
						|
  widget::ThemeChangeKind mChangeKind =
 | 
						|
      widget::ThemeChangeKind::MediaQueriesOnly;
 | 
						|
} kMediaQueryPrefs[] = {
 | 
						|
    // Affects whether standins are used for the accent color.
 | 
						|
    {"widget.non-native-theme.use-theme-accent"_ns,
 | 
						|
     widget::ThemeChangeKind::Style},
 | 
						|
    // These three affect system colors on Windows.
 | 
						|
    {"widget.windows.uwp-system-colors.enabled"_ns,
 | 
						|
     widget::ThemeChangeKind::Style},
 | 
						|
    {"widget.windows.uwp-system-colors.highlight-accent"_ns,
 | 
						|
     widget::ThemeChangeKind::Style},
 | 
						|
    // Affects env().
 | 
						|
    {"layout.css.prefers-color-scheme.content-override"_ns,
 | 
						|
     widget::ThemeChangeKind::Style},
 | 
						|
    // Affects media queries and scrollbar sizes, so gotta relayout.
 | 
						|
    {"widget.gtk.overlay-scrollbars.enabled"_ns,
 | 
						|
     widget::ThemeChangeKind::StyleAndLayout},
 | 
						|
    // Affects zoom settings which includes text and full zoom.
 | 
						|
    {"browser.display.os-zoom-behavior"_ns,
 | 
						|
     widget::ThemeChangeKind::StyleAndLayout},
 | 
						|
    // This affects system colors on Linux.
 | 
						|
    {"widget.gtk.libadwaita-colors.enabled"_ns, widget::ThemeChangeKind::Style},
 | 
						|
    // This affects not only the media query, but also the native theme, so we
 | 
						|
    // need to re-layout.
 | 
						|
    {"browser.theme.toolbar-theme"_ns, widget::ThemeChangeKind::AllBits},
 | 
						|
    {"browser.theme.content-theme"_ns},
 | 
						|
};
 | 
						|
 | 
						|
// Read values from the user's preferences.
 | 
						|
// This is done once at startup, but since the user's preferences
 | 
						|
// haven't actually been read yet at that time, we also have to
 | 
						|
// set a callback to inform us of changes to each pref.
 | 
						|
void nsXPLookAndFeel::Init() {
 | 
						|
  MOZ_RELEASE_ASSERT(NS_IsMainThread());
 | 
						|
 | 
						|
  // Say we're already initialized, and take the chance that it might fail;
 | 
						|
  // protects against some other process writing to our static variables.
 | 
						|
  sInitialized = true;
 | 
						|
 | 
						|
  if (XRE_IsParentProcess()) {
 | 
						|
    nsLayoutUtils::RecomputeSmoothScrollDefault();
 | 
						|
  }
 | 
						|
 | 
						|
  // XXX If we could reorganize the pref names, we should separate the branch
 | 
						|
  //     for each types.  Then, we could reduce the unnecessary loop from
 | 
						|
  //     nsXPLookAndFeel::OnPrefChanged().
 | 
						|
  Preferences::RegisterPrefixCallback(OnPrefChanged, "ui.");
 | 
						|
 | 
						|
  for (const auto& pref : kMediaQueryPrefs) {
 | 
						|
    Preferences::RegisterCallback(
 | 
						|
        [](const char*, void* aChangeKind) {
 | 
						|
          auto changeKind =
 | 
						|
              widget::ThemeChangeKind(reinterpret_cast<uintptr_t>(aChangeKind));
 | 
						|
          LookAndFeel::NotifyChangedAllWindows(changeKind);
 | 
						|
        },
 | 
						|
        pref.mName, reinterpret_cast<void*>(uintptr_t(pref.mChangeKind)));
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
nsXPLookAndFeel::~nsXPLookAndFeel() {
 | 
						|
  NS_ASSERTION(sInstance == this,
 | 
						|
               "This destroying instance isn't the singleton instance");
 | 
						|
  sInstance = nullptr;
 | 
						|
}
 | 
						|
 | 
						|
static bool IsSpecialColor(LookAndFeel::ColorID aID, nscolor aColor) {
 | 
						|
  using ColorID = LookAndFeel::ColorID;
 | 
						|
 | 
						|
  if (aColor == NS_SAME_AS_FOREGROUND_COLOR) {
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  switch (aID) {
 | 
						|
    case ColorID::IMESelectedRawTextBackground:
 | 
						|
    case ColorID::IMESelectedConvertedTextBackground:
 | 
						|
    case ColorID::IMERawInputBackground:
 | 
						|
    case ColorID::IMEConvertedTextBackground:
 | 
						|
    case ColorID::IMESelectedRawTextForeground:
 | 
						|
    case ColorID::IMESelectedConvertedTextForeground:
 | 
						|
    case ColorID::IMERawInputForeground:
 | 
						|
    case ColorID::IMEConvertedTextForeground:
 | 
						|
    case ColorID::IMERawInputUnderline:
 | 
						|
    case ColorID::IMEConvertedTextUnderline:
 | 
						|
    case ColorID::IMESelectedRawTextUnderline:
 | 
						|
    case ColorID::IMESelectedConvertedTextUnderline:
 | 
						|
    case ColorID::SpellCheckerUnderline:
 | 
						|
      return NS_IS_SELECTION_SPECIAL_COLOR(aColor);
 | 
						|
    default:
 | 
						|
      break;
 | 
						|
  }
 | 
						|
  /*
 | 
						|
   * In GetColor(), every color that is not a special color is color
 | 
						|
   * corrected. Use false to make other colors color corrected.
 | 
						|
   */
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
nscolor nsXPLookAndFeel::GetStandinForNativeColor(ColorID aID,
 | 
						|
                                                  ColorScheme aScheme) {
 | 
						|
  if (aScheme == ColorScheme::Dark) {
 | 
						|
    if (auto color = GenericDarkColor(aID)) {
 | 
						|
      return *color;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  // The stand-in colors are taken from what the non-native theme needs (for
 | 
						|
  // field/button colors), the Windows 7 Aero theme except Mac-specific colors
 | 
						|
  // which are taken from Mac OS 10.7.
 | 
						|
 | 
						|
#define COLOR(name_, r, g, b) \
 | 
						|
  case ColorID::name_:        \
 | 
						|
    return NS_RGB(r, g, b);
 | 
						|
 | 
						|
#define COLORA(name_, r, g, b, a) \
 | 
						|
  case ColorID::name_:            \
 | 
						|
    return NS_RGBA(r, g, b, a);
 | 
						|
 | 
						|
  switch (aID) {
 | 
						|
    // These are here for the purposes of headless mode.
 | 
						|
    case ColorID::IMESelectedRawTextBackground:
 | 
						|
    case ColorID::IMESelectedConvertedTextBackground:
 | 
						|
    case ColorID::IMERawInputBackground:
 | 
						|
    case ColorID::IMEConvertedTextBackground:
 | 
						|
      return NS_TRANSPARENT;
 | 
						|
    case ColorID::IMESelectedRawTextForeground:
 | 
						|
    case ColorID::IMESelectedConvertedTextForeground:
 | 
						|
    case ColorID::IMERawInputForeground:
 | 
						|
    case ColorID::IMEConvertedTextForeground:
 | 
						|
      return NS_SAME_AS_FOREGROUND_COLOR;
 | 
						|
    case ColorID::IMERawInputUnderline:
 | 
						|
    case ColorID::IMEConvertedTextUnderline:
 | 
						|
      return NS_40PERCENT_FOREGROUND_COLOR;
 | 
						|
    case ColorID::Accentcolor:
 | 
						|
      return widget::sDefaultAccent.ToABGR();
 | 
						|
    case ColorID::Accentcolortext:
 | 
						|
      return widget::sDefaultAccentText.ToABGR();
 | 
						|
      COLOR(SpellCheckerUnderline, 0xff, 0x00, 0x00)
 | 
						|
      COLOR(TextSelectDisabledBackground, 0xAA, 0xAA, 0xAA)
 | 
						|
 | 
						|
      // Titlebar colors
 | 
						|
      // deprecated in CSS Color Level 4, same as Buttonborder:
 | 
						|
      COLOR(Activeborder, 0xE3, 0xE3, 0xE3)
 | 
						|
      // deprecated in CSS Color Level 4, same as Buttonborder:
 | 
						|
      COLOR(Inactiveborder, 0xE3, 0xE3, 0xE3)
 | 
						|
      // deprecated in CSS Color Level 4, same as Canvas/Window:
 | 
						|
      COLOR(Activecaption, 0xFF, 0xFF, 0xFF)
 | 
						|
      // deprecated in CSS Color Level 4, same as Canvas/Window:
 | 
						|
      COLOR(Inactivecaption, 0xFF, 0xFF, 0xFF)
 | 
						|
      // deprecated in CSS Color Level 4, same as Canvastext/Windowtext:
 | 
						|
      COLOR(Captiontext, 0x00, 0x00, 0x00)
 | 
						|
      // deprecated in CSS Color Level 4, same as Graytext:
 | 
						|
      COLOR(Inactivecaptiontext, 0x6D, 0x6D, 0x6D)
 | 
						|
 | 
						|
      // CSS 2 colors:
 | 
						|
      // deprecated in CSS Color Level 4, same as Canvas/Window:
 | 
						|
      COLOR(Appworkspace, 0xFF, 0xFF, 0xFF)
 | 
						|
      // deprecated in CSS Color Level 4, same as Canvas/Window:
 | 
						|
      COLOR(Background, 0xFF, 0xFF, 0xFF)
 | 
						|
      // deprecated in CSS Color Level 4, same as Buttonface:
 | 
						|
      COLOR(Buttonhighlight, 0xE9, 0xE9, 0xED)
 | 
						|
      // deprecated in CSS Color Level 4, same as Buttonface:
 | 
						|
      COLOR(Buttonshadow, 0xE9, 0xE9, 0xED)
 | 
						|
 | 
						|
      // Buttons and comboboxes should be kept in sync since they are drawn with
 | 
						|
      // the same colors by the non-native theme.
 | 
						|
      COLOR(Buttonface, 0xE9, 0xE9, 0xED)
 | 
						|
      COLORA(MozButtondisabledface, 0xE9, 0xE9, 0xED, 128)
 | 
						|
 | 
						|
      COLOR(MozCombobox, 0xE9, 0xE9, 0xED)
 | 
						|
 | 
						|
      COLOR(Buttontext, 0x00, 0x00, 0x00)
 | 
						|
      COLOR(MozComboboxtext, 0x00, 0x00, 0x00)
 | 
						|
 | 
						|
      COLOR(Graytext, 0x6D, 0x6D, 0x6D)
 | 
						|
      COLOR(Highlight, 0x33, 0x99, 0xFF)
 | 
						|
      COLOR(Highlighttext, 0xFF, 0xFF, 0xFF)
 | 
						|
      // deprecated in CSS Color Level 4, same as Canvas/Window:
 | 
						|
      COLOR(Infobackground, 0xFF, 0xFF, 0xFF)
 | 
						|
      // deprecated in CSS Color Level 4, same as Canvastext/Windowtext:
 | 
						|
      COLOR(Infotext, 0x00, 0x00, 0x00)
 | 
						|
      // deprecated in CSS Color Level 4, same as Canvas/Window:
 | 
						|
      COLOR(Menu, 0xFF, 0xFF, 0xFF)
 | 
						|
      // deprecated in CSS Color Level 4, same as Canvastext/Windowtext:
 | 
						|
      COLOR(Menutext, 0x00, 0x00, 0x00)
 | 
						|
      // deprecated in CSS Color Level 4, same as Canvas/Window:
 | 
						|
      COLOR(Scrollbar, 0xFF, 0xFF, 0xFF)
 | 
						|
      // deprecated in CSS Color Level 4, same as Buttonborder:
 | 
						|
      COLOR(Threeddarkshadow, 0xE3, 0xE3, 0xE3)
 | 
						|
      // deprecated in CSS Color Level 4, same as Buttonface:
 | 
						|
      COLOR(Threedface, 0xE9, 0xE9, 0xED)
 | 
						|
      // deprecated in CSS Color Level 4, same as Buttonborder:
 | 
						|
      COLOR(Threedhighlight, 0xE3, 0xE3, 0xE3)
 | 
						|
      COLOR(Threedlightshadow, 0xE3, 0xE3, 0xE3)
 | 
						|
      // deprecated in CSS Color Level 4, same as Buttonborder:
 | 
						|
      COLOR(Threedshadow, 0xE3, 0xE3, 0xE3)
 | 
						|
      COLOR(Buttonborder, 0xE3, 0xE3, 0xE3)
 | 
						|
      COLOR(Mark, 0xFF, 0xFF, 0x00)
 | 
						|
      COLOR(Marktext, 0x00, 0x00, 0x00)
 | 
						|
      COLOR(Window, 0xFF, 0xFF, 0xFF)
 | 
						|
      // deprecated in CSS Color Level 4, same as Buttonborder:
 | 
						|
      COLOR(Windowframe, 0xE3, 0xE3, 0xE3)
 | 
						|
      COLOR(Windowtext, 0x00, 0x00, 0x00)
 | 
						|
      COLOR(Field, 0xFF, 0xFF, 0xFF)
 | 
						|
      COLORA(MozDisabledfield, 0xFF, 0xFF, 0xFF, 128)
 | 
						|
      COLOR(Fieldtext, 0x00, 0x00, 0x00)
 | 
						|
      COLOR(MozDialog, 0xF0, 0xF0, 0xF0)
 | 
						|
      COLOR(MozDialogtext, 0x00, 0x00, 0x00)
 | 
						|
      COLOR(MozColheadertext, 0x00, 0x00, 0x00)
 | 
						|
      COLOR(MozColheaderhovertext, 0x00, 0x00, 0x00)
 | 
						|
      COLOR(MozCellhighlight, 0xF0, 0xF0, 0xF0)
 | 
						|
      COLOR(MozCellhighlighttext, 0x00, 0x00, 0x00)
 | 
						|
      COLOR(Selecteditem, 0x33, 0x99, 0xFF)
 | 
						|
      COLOR(Selecteditemtext, 0xFF, 0xFF, 0xFF)
 | 
						|
      COLOR(MozButtonhoverface, 0xd0, 0xd0, 0xd7)
 | 
						|
      COLOR(MozButtonhovertext, 0x00, 0x00, 0x00)
 | 
						|
      COLOR(MozButtonactiveface, 0xb1, 0xb1, 0xb9)
 | 
						|
      COLOR(MozButtonactivetext, 0x00, 0x00, 0x00)
 | 
						|
      COLOR(MozMenuhover, 0x33, 0x99, 0xFF)
 | 
						|
      COLOR(MozMenuhovertext, 0x00, 0x00, 0x00)
 | 
						|
      COLOR(MozMenubarhovertext, 0x00, 0x00, 0x00)
 | 
						|
      COLOR(MozMenuhoverdisabled, 0xF0, 0xF0, 0xF0)
 | 
						|
      COLOR(MozEventreerow, 0xFF, 0xFF, 0xFF)
 | 
						|
      COLOR(MozOddtreerow, 0xFF, 0xFF, 0xFF)
 | 
						|
      COLOR(MozMacFocusring, 0x60, 0x9D, 0xD7)
 | 
						|
      COLOR(MozMacDisabledtoolbartext, 0x3F, 0x3F, 0x3F)
 | 
						|
      // Seems to be the default color (hardcoded because of bug 1065998)
 | 
						|
      COLOR(MozNativehyperlinktext, 0x00, 0x66, 0xCC)
 | 
						|
      COLOR(MozNativevisitedhyperlinktext, 0x55, 0x1A, 0x8B)
 | 
						|
      COLOR(MozAutofillBackground, 0xff, 0xfc, 0xc8)
 | 
						|
      COLOR(TargetTextBackground, 0xff, 0xeb, 0xcd)
 | 
						|
      COLOR(TargetTextForeground, 0x00, 0x00, 0x00)
 | 
						|
    default:
 | 
						|
      break;
 | 
						|
  }
 | 
						|
  return NS_RGB(0xFF, 0xFF, 0xFF);
 | 
						|
}
 | 
						|
 | 
						|
#undef COLOR
 | 
						|
#undef COLORA
 | 
						|
 | 
						|
// Taken from in-content/common.inc.css's dark theme.
 | 
						|
Maybe<nscolor> nsXPLookAndFeel::GenericDarkColor(ColorID aID) {
 | 
						|
  nscolor color = NS_RGB(0, 0, 0);
 | 
						|
  static constexpr nscolor kWindowBackground = NS_RGB(28, 27, 34);
 | 
						|
  static constexpr nscolor kWindowText = NS_RGB(251, 251, 254);
 | 
						|
  switch (aID) {
 | 
						|
    case ColorID::Window:  // --in-content-page-background
 | 
						|
    case ColorID::Background:
 | 
						|
    case ColorID::Appworkspace:
 | 
						|
    case ColorID::Scrollbar:
 | 
						|
    case ColorID::Infobackground:
 | 
						|
      color = kWindowBackground;
 | 
						|
      break;
 | 
						|
 | 
						|
    case ColorID::Menu:
 | 
						|
      color = NS_RGB(0x2b, 0x2a, 0x33);
 | 
						|
      break;
 | 
						|
 | 
						|
    case ColorID::MozMenuhovertext:
 | 
						|
    case ColorID::MozMenubarhovertext:
 | 
						|
    case ColorID::Menutext:
 | 
						|
      color = NS_RGB(0xfb, 0xfb, 0xfe);
 | 
						|
      break;
 | 
						|
 | 
						|
    case ColorID::MozMenuhover:
 | 
						|
      color = NS_RGB(0x52, 0x52, 0x5e);
 | 
						|
      break;
 | 
						|
 | 
						|
    case ColorID::MozMenuhoverdisabled:
 | 
						|
      color = NS_RGB(0x3a, 0x39, 0x44);
 | 
						|
      break;
 | 
						|
 | 
						|
    case ColorID::MozEventreerow:
 | 
						|
    case ColorID::MozOddtreerow:
 | 
						|
    case ColorID::MozDialog:  // --in-content-box-background
 | 
						|
      color = NS_RGB(35, 34, 43);
 | 
						|
      break;
 | 
						|
    case ColorID::Windowtext:  // --in-content-page-color
 | 
						|
    case ColorID::MozDialogtext:
 | 
						|
    case ColorID::MozSidebartext:
 | 
						|
    case ColorID::Fieldtext:
 | 
						|
    case ColorID::Infotext:
 | 
						|
    case ColorID::Buttontext:  // --in-content-button-text-color (via
 | 
						|
                               // --in-content-page-color)
 | 
						|
    case ColorID::MozComboboxtext:
 | 
						|
    case ColorID::MozButtonhovertext:
 | 
						|
    case ColorID::MozButtonactivetext:
 | 
						|
    case ColorID::MozHeaderbartext:
 | 
						|
    case ColorID::MozHeaderbarinactivetext:
 | 
						|
    case ColorID::Captiontext:
 | 
						|
    case ColorID::Inactivecaptiontext:  // TODO(emilio): Maybe make
 | 
						|
                                        // Inactivecaptiontext Graytext?
 | 
						|
    case ColorID::MozColheadertext:
 | 
						|
    case ColorID::MozColheaderhovertext:
 | 
						|
    case ColorID::MozColheaderactivetext:
 | 
						|
      color = kWindowText;
 | 
						|
      break;
 | 
						|
    case ColorID::Buttonshadow:
 | 
						|
    case ColorID::Threedshadow:
 | 
						|
    case ColorID::MozSidebarborder:
 | 
						|
    case ColorID::Threedlightshadow:
 | 
						|
    case ColorID::Threedhighlight:
 | 
						|
    case ColorID::Windowframe:
 | 
						|
    case ColorID::Buttonborder:  // --in-content-box-border-color computed
 | 
						|
                                 // with kWindowText above
 | 
						|
                                 // kWindowBackground.
 | 
						|
    case ColorID::Graytext:      // opacity: 0.4 of kWindowText blended over the
 | 
						|
                             // "Window" background color, which happens to be
 | 
						|
                             // the same :-)
 | 
						|
      color = NS_ComposeColors(kWindowBackground, NS_RGBA(251, 251, 254, 102));
 | 
						|
      break;
 | 
						|
    case ColorID::MozCellhighlight:
 | 
						|
    case ColorID::Selecteditem:  // --in-content-primary-button-background /
 | 
						|
                                 // --in-content-item-selected
 | 
						|
      color = NS_RGB(0, 221, 255);
 | 
						|
      break;
 | 
						|
    case ColorID::MozSidebar:
 | 
						|
    case ColorID::Field:
 | 
						|
    case ColorID::Buttonface:  // --in-content-button-background
 | 
						|
    case ColorID::Buttonhighlight:
 | 
						|
    case ColorID::MozColheader:
 | 
						|
    case ColorID::Threedface:
 | 
						|
    case ColorID::MozCombobox:
 | 
						|
    case ColorID::MozCellhighlighttext:
 | 
						|
    case ColorID::Selecteditemtext:  // --in-content-primary-button-text-color /
 | 
						|
                                     // --in-content-item-selected-text
 | 
						|
      color = NS_RGB(43, 42, 51);
 | 
						|
      break;
 | 
						|
    case ColorID::Threeddarkshadow:  // Same as Threedlightshadow but with the
 | 
						|
                                     // background.
 | 
						|
    case ColorID::MozDisabledfield:  // opacity: 0.4 of the face above blended
 | 
						|
                                     // over the "Window" background color.
 | 
						|
    case ColorID::MozButtondisabledface:
 | 
						|
      color = NS_ComposeColors(kWindowBackground, NS_RGBA(43, 42, 51, 102));
 | 
						|
      break;
 | 
						|
    case ColorID::MozButtonhoverface:  // --in-content-button-background-hover
 | 
						|
    case ColorID::MozColheaderhover:
 | 
						|
      color = NS_RGB(82, 82, 94);
 | 
						|
      break;
 | 
						|
    case ColorID::MozButtonactiveface:  // --in-content-button-background-active
 | 
						|
    case ColorID::MozColheaderactive:
 | 
						|
      color = NS_RGB(91, 91, 102);
 | 
						|
      break;
 | 
						|
    case ColorID::Highlight:
 | 
						|
      color = NS_RGBA(0, 221, 255, 78);
 | 
						|
      break;
 | 
						|
    case ColorID::Highlighttext:
 | 
						|
      color = NS_SAME_AS_FOREGROUND_COLOR;
 | 
						|
      break;
 | 
						|
    case ColorID::MozNativehyperlinktext:
 | 
						|
      // If you change this color, you probably also want to change the default
 | 
						|
      // value of browser.anchor_color.dark.
 | 
						|
      color = NS_RGB(0x8c, 0x8c, 0xff);
 | 
						|
      break;
 | 
						|
    case ColorID::MozNativevisitedhyperlinktext:
 | 
						|
      // If you change this color, you probably also want to change the default
 | 
						|
      // value of browser.visited_color.dark.
 | 
						|
      color = NS_RGB(0xff, 0xad, 0xff);
 | 
						|
      break;
 | 
						|
    case ColorID::SpellCheckerUnderline:
 | 
						|
      // This is the default for active links in dark mode as well
 | 
						|
      // (browser.active_color.dark). See bug 1755564 for some analysis and
 | 
						|
      // other options too.
 | 
						|
      color = NS_RGB(0xff, 0x66, 0x66);
 | 
						|
      break;
 | 
						|
    case ColorID::Activeborder:
 | 
						|
    case ColorID::Inactiveborder:
 | 
						|
      color = NS_RGB(57, 57, 57);
 | 
						|
      break;
 | 
						|
    case ColorID::MozHeaderbar:
 | 
						|
    case ColorID::MozHeaderbarinactive:
 | 
						|
    case ColorID::Activecaption:
 | 
						|
    case ColorID::Inactivecaption:
 | 
						|
      color = NS_RGB(28, 27, 34);
 | 
						|
      break;
 | 
						|
    case ColorID::MozAutofillBackground:
 | 
						|
      // This is the light version of this color, but darkened to have good
 | 
						|
      // contrast with our white-ish FieldText.
 | 
						|
      color = NS_RGB(0x72, 0x6c, 0x00);
 | 
						|
      break;
 | 
						|
    default:
 | 
						|
      return Nothing();
 | 
						|
  }
 | 
						|
  return Some(color);
 | 
						|
}
 | 
						|
 | 
						|
// Uncomment the #define below if you want to debug system color use in a skin
 | 
						|
// that uses them.  When set, it will make all system color pairs that are
 | 
						|
// appropriate for foreground/background pairing the same.  This means if the
 | 
						|
// skin is using system colors correctly you will not be able to see *any* text.
 | 
						|
//
 | 
						|
// #define DEBUG_SYSTEM_COLOR_USE
 | 
						|
 | 
						|
#ifdef DEBUG_SYSTEM_COLOR_USE
 | 
						|
static nsresult SystemColorUseDebuggingColor(LookAndFeel::ColorID aID,
 | 
						|
                                             nscolor& aResult) {
 | 
						|
  using ColorID = LookAndFeel::ColorID;
 | 
						|
 | 
						|
  switch (aID) {
 | 
						|
      // css2  http://www.w3.org/TR/REC-CSS2/ui.html#system-colors
 | 
						|
    case ColorID::Activecaption:
 | 
						|
      // active window caption background
 | 
						|
    case ColorID::Captiontext:
 | 
						|
      // text in active window caption
 | 
						|
      aResult = NS_RGB(0xff, 0x00, 0x00);
 | 
						|
      break;
 | 
						|
 | 
						|
    case ColorID::Highlight:
 | 
						|
      // background of selected item
 | 
						|
    case ColorID::Highlighttext:
 | 
						|
      // text of selected item
 | 
						|
      aResult = NS_RGB(0xff, 0xff, 0x00);
 | 
						|
      break;
 | 
						|
 | 
						|
    case ColorID::Inactivecaption:
 | 
						|
      // inactive window caption
 | 
						|
    case ColorID::Inactivecaptiontext:
 | 
						|
      // text in inactive window caption
 | 
						|
      aResult = NS_RGB(0x66, 0x66, 0x00);
 | 
						|
      break;
 | 
						|
 | 
						|
    case ColorID::Infobackground:
 | 
						|
      // tooltip background color
 | 
						|
    case ColorID::Infotext:
 | 
						|
      // tooltip text color
 | 
						|
      aResult = NS_RGB(0x00, 0xff, 0x00);
 | 
						|
      break;
 | 
						|
 | 
						|
    case ColorID::Menu:
 | 
						|
      // menu background
 | 
						|
    case ColorID::Menutext:
 | 
						|
      // menu text
 | 
						|
      aResult = NS_RGB(0x00, 0xff, 0xff);
 | 
						|
      break;
 | 
						|
 | 
						|
    case ColorID::Threedface:
 | 
						|
    case ColorID::Buttonface:
 | 
						|
      // 3-D face color
 | 
						|
    case ColorID::Buttontext:
 | 
						|
      // text on push buttons
 | 
						|
      aResult = NS_RGB(0x00, 0x66, 0x66);
 | 
						|
      break;
 | 
						|
 | 
						|
    case ColorID::Window:
 | 
						|
    case ColorID::Windowtext:
 | 
						|
      aResult = NS_RGB(0x00, 0x00, 0xff);
 | 
						|
      break;
 | 
						|
 | 
						|
      // from the CSS3 working draft (not yet finalized)
 | 
						|
      // http://www.w3.org/tr/2000/wd-css3-userint-20000216.html#color
 | 
						|
 | 
						|
    case ColorID::Field:
 | 
						|
    case ColorID::Fieldtext:
 | 
						|
      aResult = NS_RGB(0xff, 0x00, 0xff);
 | 
						|
      break;
 | 
						|
 | 
						|
    case ColorID::MozDialog:
 | 
						|
    case ColorID::MozDialogtext:
 | 
						|
      aResult = NS_RGB(0x66, 0x00, 0x66);
 | 
						|
      break;
 | 
						|
 | 
						|
    default:
 | 
						|
      return NS_ERROR_NOT_AVAILABLE;
 | 
						|
  }
 | 
						|
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
static nsresult GetPrefColor(const char* aPref, nscolor& aResult) {
 | 
						|
  nsAutoCString colorStr;
 | 
						|
  MOZ_TRY(Preferences::GetCString(aPref, colorStr));
 | 
						|
  if (!ServoCSSParser::ComputeColor(nullptr, NS_RGB(0, 0, 0), colorStr,
 | 
						|
                                    &aResult)) {
 | 
						|
    return NS_ERROR_FAILURE;
 | 
						|
  }
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
static nsresult GetColorFromPref(LookAndFeel::ColorID aID, ColorScheme aScheme,
 | 
						|
                                 nscolor& aResult) {
 | 
						|
  const char* prefName = sColorPrefs[size_t(aID)];
 | 
						|
  if (aScheme == ColorScheme::Dark) {
 | 
						|
    nsAutoCString darkPrefName(prefName);
 | 
						|
    darkPrefName.Append(".dark");
 | 
						|
    if (NS_SUCCEEDED(GetPrefColor(darkPrefName.get(), aResult))) {
 | 
						|
      return NS_OK;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return GetPrefColor(prefName, aResult);
 | 
						|
}
 | 
						|
 | 
						|
// All these routines will return NS_OK if they have a value,
 | 
						|
// in which case the nsLookAndFeel should use that value;
 | 
						|
// otherwise we'll return NS_ERROR_NOT_AVAILABLE, in which case, the
 | 
						|
// platform-specific nsLookAndFeel should use its own values instead.
 | 
						|
nsresult nsXPLookAndFeel::GetColorValue(ColorID aID, ColorScheme aScheme,
 | 
						|
                                        UseStandins aUseStandins,
 | 
						|
                                        nscolor& aResult) {
 | 
						|
  if (!sInitialized) {
 | 
						|
    Init();
 | 
						|
  }
 | 
						|
 | 
						|
#ifdef DEBUG_SYSTEM_COLOR_USE
 | 
						|
  if (NS_SUCCEEDED(SystemColorUseDebuggingColor(aID, aResult))) {
 | 
						|
    return NS_OK;
 | 
						|
  }
 | 
						|
#endif
 | 
						|
 | 
						|
  auto& cache = sColorCaches.Get(aScheme, aUseStandins);
 | 
						|
  if (const auto* cached = cache.Get(aID)) {
 | 
						|
    if (cached->isNothing()) {
 | 
						|
      return NS_ERROR_FAILURE;
 | 
						|
    }
 | 
						|
    aResult = cached->value();
 | 
						|
    return NS_OK;
 | 
						|
  }
 | 
						|
 | 
						|
  // NOTE: Servo holds a lock and the main thread is paused, so writing to the
 | 
						|
  // global cache here is fine.
 | 
						|
  auto result = GetUncachedColor(aID, aScheme, aUseStandins);
 | 
						|
  cache.Insert(aID, result);
 | 
						|
  if (!result) {
 | 
						|
    return NS_ERROR_FAILURE;
 | 
						|
  }
 | 
						|
  aResult = *result;
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
Maybe<nscolor> nsXPLookAndFeel::GetUncachedColor(ColorID aID,
 | 
						|
                                                 ColorScheme aScheme,
 | 
						|
                                                 UseStandins aUseStandins) {
 | 
						|
  if (aUseStandins == UseStandins::Yes) {
 | 
						|
    return Some(GetStandinForNativeColor(aID, aScheme));
 | 
						|
  }
 | 
						|
  nscolor r;
 | 
						|
  if (NS_SUCCEEDED(GetColorFromPref(aID, aScheme, r))) {
 | 
						|
    return Some(r);
 | 
						|
  }
 | 
						|
  if (NS_SUCCEEDED(NativeGetColor(aID, aScheme, r))) {
 | 
						|
    if (gfxPlatform::GetCMSMode() == CMSMode::All && !IsSpecialColor(aID, r)) {
 | 
						|
      qcms_transform* transform = gfxPlatform::GetCMSInverseRGBTransform();
 | 
						|
      if (transform) {
 | 
						|
        uint8_t color[4];
 | 
						|
        color[0] = NS_GET_R(r);
 | 
						|
        color[1] = NS_GET_G(r);
 | 
						|
        color[2] = NS_GET_B(r);
 | 
						|
        color[3] = NS_GET_A(r);
 | 
						|
        qcms_transform_data(transform, color, color, 1);
 | 
						|
        r = NS_RGBA(color[0], color[1], color[2], color[3]);
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    return Some(r);
 | 
						|
  }
 | 
						|
  return Nothing();
 | 
						|
}
 | 
						|
 | 
						|
nsresult nsXPLookAndFeel::GetIntValue(IntID aID, int32_t& aResult) {
 | 
						|
  if (!sInitialized) {
 | 
						|
    Init();
 | 
						|
  }
 | 
						|
 | 
						|
  if (const auto* cached = sIntCache.Get(aID)) {
 | 
						|
    if (cached->isNothing()) {
 | 
						|
      return NS_ERROR_FAILURE;
 | 
						|
    }
 | 
						|
    aResult = cached->value();
 | 
						|
    return NS_OK;
 | 
						|
  }
 | 
						|
 | 
						|
  if (NS_SUCCEEDED(Preferences::GetInt(sIntPrefs[size_t(aID)], &aResult))) {
 | 
						|
    sIntCache.Insert(aID, Some(aResult));
 | 
						|
    return NS_OK;
 | 
						|
  }
 | 
						|
 | 
						|
  if (NS_FAILED(NativeGetInt(aID, aResult))) {
 | 
						|
    sIntCache.Insert(aID, Nothing());
 | 
						|
    return NS_ERROR_FAILURE;
 | 
						|
  }
 | 
						|
 | 
						|
  sIntCache.Insert(aID, Some(aResult));
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
nsresult nsXPLookAndFeel::GetFloatValue(FloatID aID, float& aResult) {
 | 
						|
  if (!sInitialized) {
 | 
						|
    Init();
 | 
						|
  }
 | 
						|
 | 
						|
  if (const auto* cached = sFloatCache.Get(aID)) {
 | 
						|
    if (cached->isNothing()) {
 | 
						|
      return NS_ERROR_FAILURE;
 | 
						|
    }
 | 
						|
    aResult = cached->value();
 | 
						|
    return NS_OK;
 | 
						|
  }
 | 
						|
 | 
						|
  int32_t pref = 0;
 | 
						|
  if (NS_SUCCEEDED(Preferences::GetInt(sFloatPrefs[size_t(aID)], &pref))) {
 | 
						|
    aResult = float(pref) / 100.0f;
 | 
						|
    sFloatCache.Insert(aID, Some(aResult));
 | 
						|
    return NS_OK;
 | 
						|
  }
 | 
						|
 | 
						|
  if (NS_FAILED(NativeGetFloat(aID, aResult))) {
 | 
						|
    sFloatCache.Insert(aID, Nothing());
 | 
						|
    return NS_ERROR_FAILURE;
 | 
						|
  }
 | 
						|
 | 
						|
  sFloatCache.Insert(aID, Some(aResult));
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
bool nsXPLookAndFeel::LookAndFeelFontToStyle(const LookAndFeelFont& aFont,
 | 
						|
                                             nsString& aName,
 | 
						|
                                             gfxFontStyle& aStyle) {
 | 
						|
  if (!aFont.haveFont()) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  aName = aFont.name();
 | 
						|
  aStyle = gfxFontStyle();
 | 
						|
  aStyle.size = aFont.size();
 | 
						|
  aStyle.weight = FontWeight::FromInt(aFont.weight());
 | 
						|
  aStyle.style =
 | 
						|
      aFont.italic() ? FontSlantStyle::ITALIC : FontSlantStyle::NORMAL;
 | 
						|
  aStyle.systemFont = true;
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
widget::LookAndFeelFont nsXPLookAndFeel::StyleToLookAndFeelFont(
 | 
						|
    const nsAString& aName, const gfxFontStyle& aStyle) {
 | 
						|
  LookAndFeelFont font;
 | 
						|
  font.haveFont() = true;
 | 
						|
  font.name() = aName;
 | 
						|
  font.size() = aStyle.size;
 | 
						|
  font.weight() = aStyle.weight.ToFloat();
 | 
						|
  font.italic() = aStyle.style.IsItalic();
 | 
						|
  MOZ_ASSERT(aStyle.style.IsNormal() || aStyle.style.IsItalic(),
 | 
						|
             "Cannot handle oblique font style");
 | 
						|
#ifdef DEBUG
 | 
						|
  {
 | 
						|
    // Assert that all the remaining font style properties have their
 | 
						|
    // default values.
 | 
						|
    gfxFontStyle candidate = aStyle;
 | 
						|
    gfxFontStyle defaults{};
 | 
						|
    candidate.size = defaults.size;
 | 
						|
    candidate.weight = defaults.weight;
 | 
						|
    candidate.style = defaults.style;
 | 
						|
    MOZ_ASSERT(candidate.Equals(defaults),
 | 
						|
               "Some font style properties not supported");
 | 
						|
  }
 | 
						|
#endif
 | 
						|
  return font;
 | 
						|
}
 | 
						|
 | 
						|
bool nsXPLookAndFeel::GetFontValue(FontID aID, nsString& aName,
 | 
						|
                                   gfxFontStyle& aStyle) {
 | 
						|
  if (const LookAndFeelFont* cached = sFontCache.Get(aID)) {
 | 
						|
    return LookAndFeelFontToStyle(*cached, aName, aStyle);
 | 
						|
  }
 | 
						|
 | 
						|
  LookAndFeelFont font;
 | 
						|
  auto GetFontsFromPrefs = [&]() -> bool {
 | 
						|
    nsDependentCString pref(sFontPrefs[size_t(aID)]);
 | 
						|
    if (NS_FAILED(Preferences::GetString(pref.get(), aName))) {
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
    font.haveFont() = true;
 | 
						|
    font.name() = aName;
 | 
						|
    font.size() = Preferences::GetFloat(nsAutoCString(pref + ".size"_ns).get());
 | 
						|
    // This is written this way rather than using the fallback so that an empty
 | 
						|
    // pref (such like the one about:config creates) doesn't cause system fonts
 | 
						|
    // to have zero-size.
 | 
						|
    if (font.size() < 1.0f) {
 | 
						|
      font.size() = StyleFONT_MEDIUM_PX;
 | 
						|
    }
 | 
						|
    font.weight() = Preferences::GetFloat(
 | 
						|
        nsAutoCString(pref + ".weight"_ns).get(), FontWeight::NORMAL.ToFloat());
 | 
						|
    font.italic() =
 | 
						|
        Preferences::GetBool(nsAutoCString(pref + ".italic"_ns).get());
 | 
						|
    return true;
 | 
						|
  };
 | 
						|
 | 
						|
  if (GetFontsFromPrefs()) {
 | 
						|
    LookAndFeelFontToStyle(font, aName, aStyle);
 | 
						|
  } else if (NativeGetFont(aID, aName, aStyle)) {
 | 
						|
    font = StyleToLookAndFeelFont(aName, aStyle);
 | 
						|
  } else {
 | 
						|
    MOZ_ASSERT(!font.haveFont());
 | 
						|
  }
 | 
						|
  bool success = font.haveFont();
 | 
						|
  sFontCache.Insert(aID, std::move(font));
 | 
						|
  return success;
 | 
						|
}
 | 
						|
 | 
						|
void nsXPLookAndFeel::RefreshImpl() {
 | 
						|
  // Wipe out our caches.
 | 
						|
  sColorCaches.Clear();
 | 
						|
  sFontCache.Clear();
 | 
						|
  sFloatCache.Clear();
 | 
						|
  sIntCache.Clear();
 | 
						|
 | 
						|
  if (XRE_IsParentProcess()) {
 | 
						|
    nsLayoutUtils::RecomputeSmoothScrollDefault();
 | 
						|
    // Clear any cached FullLookAndFeel data, which is now invalid.
 | 
						|
    widget::RemoteLookAndFeel::ClearCachedData();
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
static bool sRecordedLookAndFeelTelemetry = false;
 | 
						|
 | 
						|
void nsXPLookAndFeel::RecordTelemetry() {
 | 
						|
  if (!XRE_IsParentProcess()) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (sRecordedLookAndFeelTelemetry) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  sRecordedLookAndFeelTelemetry = true;
 | 
						|
 | 
						|
  int32_t i;
 | 
						|
  Telemetry::ScalarSet(
 | 
						|
      Telemetry::ScalarID::WIDGET_DARK_MODE,
 | 
						|
      NS_SUCCEEDED(GetIntValue(IntID::SystemUsesDarkTheme, i)) && i != 0);
 | 
						|
 | 
						|
  RecordLookAndFeelSpecificTelemetry();
 | 
						|
}
 | 
						|
 | 
						|
namespace mozilla {
 | 
						|
 | 
						|
bool LookAndFeel::sGlobalThemeChanged;
 | 
						|
static widget::ThemeChangeKind sGlobalThemeChangeKind{0};
 | 
						|
 | 
						|
void LookAndFeel::NotifyChangedAllWindows(widget::ThemeChangeKind aKind) {
 | 
						|
  sGlobalThemeChanged = true;
 | 
						|
  sGlobalThemeChangeKind |= aKind;
 | 
						|
 | 
						|
  if (nsCOMPtr<nsIObserverService> obs = services::GetObserverService()) {
 | 
						|
    const char16_t kind[] = {char16_t(aKind), 0};
 | 
						|
    obs->NotifyObservers(nullptr, "internal-look-and-feel-changed", kind);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void LookAndFeel::DoHandleGlobalThemeChange() {
 | 
						|
  MOZ_ASSERT(sGlobalThemeChanged);
 | 
						|
  sGlobalThemeChanged = false;
 | 
						|
  auto kind = std::exchange(sGlobalThemeChangeKind, widget::ThemeChangeKind(0));
 | 
						|
 | 
						|
  // Tell the theme that it changed, so it can flush any handles to stale theme
 | 
						|
  // data.
 | 
						|
  //
 | 
						|
  // We can use the *DoNotUseDirectly functions directly here, because we want
 | 
						|
  // to notify all possible themes in a given process (but just once).
 | 
						|
  if (XRE_IsParentProcess()) {
 | 
						|
    if (nsCOMPtr<nsITheme> theme = do_GetNativeThemeDoNotUseDirectly()) {
 | 
						|
      theme->ThemeChanged();
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if (nsCOMPtr<nsITheme> theme = do_GetBasicNativeThemeDoNotUseDirectly()) {
 | 
						|
    theme->ThemeChanged();
 | 
						|
  }
 | 
						|
 | 
						|
  // Clear all cached LookAndFeel colors.
 | 
						|
  LookAndFeel::Refresh();
 | 
						|
 | 
						|
  // Reset default background and foreground colors for the document since they
 | 
						|
  // may be using system colors, color scheme, etc.
 | 
						|
  PreferenceSheet::Refresh();
 | 
						|
 | 
						|
  // Vector images (SVG) may be using theme colors so we discard all cached
 | 
						|
  // surfaces. (We could add a vector image only version of DiscardAll, but
 | 
						|
  // in bug 940625 we decided theme changes are rare enough not to bother.)
 | 
						|
  image::SurfaceCacheUtils::DiscardAll();
 | 
						|
 | 
						|
  if (XRE_IsParentProcess()) {
 | 
						|
    dom::ContentParent::BroadcastThemeUpdate(kind);
 | 
						|
  }
 | 
						|
 | 
						|
  nsContentUtils::AddScriptRunner(
 | 
						|
      NS_NewRunnableFunction("HandleGlobalThemeChange", [] {
 | 
						|
        if (nsCOMPtr<nsIObserverService> obs = services::GetObserverService()) {
 | 
						|
          obs->NotifyObservers(nullptr, "look-and-feel-changed", nullptr);
 | 
						|
        }
 | 
						|
      }));
 | 
						|
}
 | 
						|
 | 
						|
#define BIT_FOR(_c) (1ull << size_t(ColorID::_c))
 | 
						|
 | 
						|
// We want to use a non-native color scheme for the non-native theme (except in
 | 
						|
// high-contrast mode), so spoof some of the colors with stand-ins to prevent
 | 
						|
// lack of contrast.
 | 
						|
static constexpr std::bitset<size_t(ColorID::End)> sNonNativeThemeStandinColors{
 | 
						|
    // Used by default button styles.
 | 
						|
    BIT_FOR(Buttonface) | BIT_FOR(Buttontext) | BIT_FOR(MozButtonhoverface) |
 | 
						|
    BIT_FOR(MozButtonhovertext) | BIT_FOR(MozButtonactiveface) |
 | 
						|
    BIT_FOR(MozButtonactivetext) | BIT_FOR(MozButtondisabledface) |
 | 
						|
    BIT_FOR(Buttonborder) |
 | 
						|
    // Used by select elements.
 | 
						|
    BIT_FOR(MozCombobox) | BIT_FOR(MozComboboxtext) |
 | 
						|
    BIT_FOR(Threedlightshadow) |
 | 
						|
    // For symmetry with the above.
 | 
						|
    BIT_FOR(Threeddarkshadow) |
 | 
						|
    // Used by fieldset borders.
 | 
						|
    BIT_FOR(Threedface) |
 | 
						|
    // Used by input / textarea.
 | 
						|
    BIT_FOR(Field) | BIT_FOR(Fieldtext) |
 | 
						|
    // Used by disabled form controls.
 | 
						|
    BIT_FOR(MozDisabledfield) | BIT_FOR(Graytext) |
 | 
						|
    // Per spec, the following colors are deprecated, see
 | 
						|
    // https://drafts.csswg.org/css-color-4/#deprecated-system-colors
 | 
						|
    // should match ButtonFace:
 | 
						|
    BIT_FOR(Buttonhighlight) | BIT_FOR(Buttonshadow) | BIT_FOR(Threedface) |
 | 
						|
    // should match ButtonBorder:
 | 
						|
    BIT_FOR(Activeborder) | BIT_FOR(Inactiveborder) |
 | 
						|
    BIT_FOR(Threeddarkshadow) | BIT_FOR(Threedhighlight) |
 | 
						|
    BIT_FOR(Threedshadow) | BIT_FOR(Windowframe) |
 | 
						|
    // should match GrayText:
 | 
						|
    BIT_FOR(Inactivecaptiontext) |
 | 
						|
    // should match Canvas/Window:
 | 
						|
    BIT_FOR(Appworkspace) | BIT_FOR(Background) | BIT_FOR(Inactivecaption) |
 | 
						|
    BIT_FOR(Infobackground) | BIT_FOR(Menu) | BIT_FOR(Scrollbar) |
 | 
						|
    // should match CanvasText/WindowText:
 | 
						|
    BIT_FOR(Activecaption) | BIT_FOR(Captiontext) | BIT_FOR(Infotext) |
 | 
						|
    BIT_FOR(Menutext) |
 | 
						|
    // Some pages expect these to return windows-like colors, see bug 1773795.
 | 
						|
    // Also, per spec, these should match Canvas/CanvasText, see
 | 
						|
    // https://drafts.csswg.org/css-color-4/#valdef-color-window and
 | 
						|
    // https://drafts.csswg.org/css-color-4/#valdef-color-windowtext
 | 
						|
    BIT_FOR(Window) | BIT_FOR(Windowtext)};
 | 
						|
#undef BIT_FOR
 | 
						|
 | 
						|
static bool ShouldUseStandinsForNativeColorForNonNativeTheme(
 | 
						|
    const dom::Document& aDoc, LookAndFeel::ColorID aColor,
 | 
						|
    const PreferenceSheet::Prefs& aPrefs) {
 | 
						|
  const bool shouldUseStandinsForColor = [&] {
 | 
						|
    if (sNonNativeThemeStandinColors[size_t(aColor)]) {
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
    // There are platforms where we want the content-exposed accent color to be
 | 
						|
    // the windows blue rather than the system accent color, for now.
 | 
						|
    return !StaticPrefs::widget_non_native_theme_use_theme_accent() &&
 | 
						|
           (aColor == LookAndFeel::ColorID::Accentcolor ||
 | 
						|
            aColor == LookAndFeel::ColorID::Accentcolortext);
 | 
						|
  }();
 | 
						|
 | 
						|
  return shouldUseStandinsForColor && aDoc.ShouldAvoidNativeTheme() &&
 | 
						|
         !aPrefs.NonNativeThemeShouldBeHighContrast();
 | 
						|
}
 | 
						|
 | 
						|
bool LookAndFeel::IsDarkColor(nscolor aColor) {
 | 
						|
  // Given https://www.w3.org/TR/WCAG20/#contrast-ratiodef, this is the
 | 
						|
  // threshold that tells us whether contrast is better against white or black.
 | 
						|
  //
 | 
						|
  // Contrast ratio against black is: (L + 0.05) / 0.05
 | 
						|
  // Contrast ratio against white is: 1.05 / (L + 0.05)
 | 
						|
  //
 | 
						|
  // So the intersection is:
 | 
						|
  //
 | 
						|
  //   (L + 0.05) / 0.05 = 1.05 / (L + 0.05)
 | 
						|
  //
 | 
						|
  // And the solution to that equation is:
 | 
						|
  //
 | 
						|
  //   sqrt(1.05 * 0.05) - 0.05
 | 
						|
  //
 | 
						|
  // So we consider a color dark if the contrast is below this threshold, and
 | 
						|
  // it's at least half-opaque.
 | 
						|
  constexpr float kThreshold = 0.179129;
 | 
						|
  return NS_GET_A(aColor) > 127 &&
 | 
						|
         RelativeLuminanceUtils::Compute(aColor) < kThreshold;
 | 
						|
}
 | 
						|
 | 
						|
ColorScheme LookAndFeel::ColorSchemeForStyle(
 | 
						|
    const dom::Document& aDoc, const StyleColorSchemeFlags& aFlags,
 | 
						|
    ColorSchemeMode aMode) {
 | 
						|
  const auto& prefs = PreferenceSheet::PrefsFor(aDoc);
 | 
						|
  StyleColorSchemeFlags style(aFlags);
 | 
						|
  if (!style) {
 | 
						|
    style._0 = aDoc.GetColorSchemeBits();
 | 
						|
  }
 | 
						|
  const bool supportsDark = bool(style & StyleColorSchemeFlags::DARK);
 | 
						|
  const bool supportsLight = bool(style & StyleColorSchemeFlags::LIGHT);
 | 
						|
  if (supportsLight && supportsDark) {
 | 
						|
    // Both color-schemes are explicitly supported, use the preferred one.
 | 
						|
    return aDoc.PreferredColorScheme();
 | 
						|
  }
 | 
						|
  if (supportsDark || supportsLight) {
 | 
						|
    // One color-scheme is explicitly supported and one isn't, so use the one
 | 
						|
    // the content supports.
 | 
						|
    return supportsDark ? ColorScheme::Dark : ColorScheme::Light;
 | 
						|
  }
 | 
						|
  // No value specified. Chrome docs, and forced-colors mode always supports
 | 
						|
  // both, so use the preferred color-scheme.
 | 
						|
  if (aMode == ColorSchemeMode::Preferred || aDoc.ChromeRulesEnabled() ||
 | 
						|
      !prefs.mUseDocumentColors) {
 | 
						|
    return aDoc.PreferredColorScheme();
 | 
						|
  }
 | 
						|
  // Otherwise default content to light.
 | 
						|
  return ColorScheme::Light;
 | 
						|
}
 | 
						|
 | 
						|
LookAndFeel::ColorScheme LookAndFeel::ColorSchemeForFrame(
 | 
						|
    const nsIFrame* aFrame, ColorSchemeMode aMode) {
 | 
						|
  return ColorSchemeForStyle(*aFrame->PresContext()->Document(),
 | 
						|
                             aFrame->StyleUI()->mColorScheme.bits, aMode);
 | 
						|
}
 | 
						|
 | 
						|
// static
 | 
						|
Maybe<nscolor> LookAndFeel::GetColor(ColorID aId, ColorScheme aScheme,
 | 
						|
                                     UseStandins aUseStandins) {
 | 
						|
  nscolor result;
 | 
						|
  nsresult rv = nsLookAndFeel::GetInstance()->GetColorValue(
 | 
						|
      aId, aScheme, aUseStandins, result);
 | 
						|
  if (NS_FAILED(rv)) {
 | 
						|
    return Nothing();
 | 
						|
  }
 | 
						|
  return Some(result);
 | 
						|
}
 | 
						|
 | 
						|
// Returns whether there is a CSS color name for this color.
 | 
						|
static bool ColorIsCSSAccessible(LookAndFeel::ColorID aId) {
 | 
						|
  using ColorID = LookAndFeel::ColorID;
 | 
						|
 | 
						|
  switch (aId) {
 | 
						|
    case ColorID::TextSelectDisabledBackground:
 | 
						|
    case ColorID::TextSelectAttentionBackground:
 | 
						|
    case ColorID::TextSelectAttentionForeground:
 | 
						|
    case ColorID::TextHighlightBackground:
 | 
						|
    case ColorID::TextHighlightForeground:
 | 
						|
    case ColorID::ThemedScrollbar:
 | 
						|
    case ColorID::ThemedScrollbarInactive:
 | 
						|
    case ColorID::ThemedScrollbarThumb:
 | 
						|
    case ColorID::ThemedScrollbarThumbActive:
 | 
						|
    case ColorID::ThemedScrollbarThumbInactive:
 | 
						|
    case ColorID::ThemedScrollbarThumbHover:
 | 
						|
    case ColorID::IMERawInputBackground:
 | 
						|
    case ColorID::IMERawInputForeground:
 | 
						|
    case ColorID::IMERawInputUnderline:
 | 
						|
    case ColorID::IMESelectedRawTextBackground:
 | 
						|
    case ColorID::IMESelectedRawTextForeground:
 | 
						|
    case ColorID::IMESelectedRawTextUnderline:
 | 
						|
    case ColorID::IMEConvertedTextBackground:
 | 
						|
    case ColorID::IMEConvertedTextForeground:
 | 
						|
    case ColorID::IMEConvertedTextUnderline:
 | 
						|
    case ColorID::IMESelectedConvertedTextBackground:
 | 
						|
    case ColorID::IMESelectedConvertedTextForeground:
 | 
						|
    case ColorID::IMESelectedConvertedTextUnderline:
 | 
						|
    case ColorID::SpellCheckerUnderline:
 | 
						|
      return false;
 | 
						|
    default:
 | 
						|
      break;
 | 
						|
  }
 | 
						|
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
LookAndFeel::UseStandins LookAndFeel::ShouldUseStandins(
 | 
						|
    const dom::Document& aDoc, ColorID aId) {
 | 
						|
  const auto& prefs = PreferenceSheet::PrefsFor(aDoc);
 | 
						|
  if (ShouldUseStandinsForNativeColorForNonNativeTheme(aDoc, aId, prefs)) {
 | 
						|
    return UseStandins::Yes;
 | 
						|
  }
 | 
						|
  if (prefs.mUseStandins && ColorIsCSSAccessible(aId)) {
 | 
						|
    return UseStandins::Yes;
 | 
						|
  }
 | 
						|
  return UseStandins::No;
 | 
						|
}
 | 
						|
 | 
						|
Maybe<nscolor> LookAndFeel::GetColor(ColorID aId, const nsIFrame* aFrame) {
 | 
						|
  const auto* doc = aFrame->PresContext()->Document();
 | 
						|
  return GetColor(aId, ColorSchemeForFrame(aFrame),
 | 
						|
                  ShouldUseStandins(*doc, aId));
 | 
						|
}
 | 
						|
 | 
						|
// static
 | 
						|
nsresult LookAndFeel::GetInt(IntID aID, int32_t* aResult) {
 | 
						|
  return nsLookAndFeel::GetInstance()->GetIntValue(aID, *aResult);
 | 
						|
}
 | 
						|
 | 
						|
// static
 | 
						|
nsresult LookAndFeel::GetFloat(FloatID aID, float* aResult) {
 | 
						|
  return nsLookAndFeel::GetInstance()->GetFloatValue(aID, *aResult);
 | 
						|
}
 | 
						|
 | 
						|
// static
 | 
						|
bool LookAndFeel::GetFont(FontID aID, nsString& aName, gfxFontStyle& aStyle) {
 | 
						|
  return nsLookAndFeel::GetInstance()->GetFontValue(aID, aName, aStyle);
 | 
						|
}
 | 
						|
 | 
						|
// static
 | 
						|
char16_t LookAndFeel::GetPasswordCharacter() {
 | 
						|
  return nsLookAndFeel::GetInstance()->GetPasswordCharacterImpl();
 | 
						|
}
 | 
						|
 | 
						|
// static
 | 
						|
bool LookAndFeel::GetEchoPassword() {
 | 
						|
  if (StaticPrefs::editor_password_mask_delay() >= 0) {
 | 
						|
    return StaticPrefs::editor_password_mask_delay() > 0;
 | 
						|
  }
 | 
						|
  return nsLookAndFeel::GetInstance()->GetEchoPasswordImpl();
 | 
						|
}
 | 
						|
 | 
						|
// static
 | 
						|
uint32_t LookAndFeel::GetPasswordMaskDelay() {
 | 
						|
  int32_t delay = StaticPrefs::editor_password_mask_delay();
 | 
						|
  if (delay < 0) {
 | 
						|
    return nsLookAndFeel::GetInstance()->GetPasswordMaskDelayImpl();
 | 
						|
  }
 | 
						|
  return delay;
 | 
						|
}
 | 
						|
 | 
						|
bool LookAndFeel::DrawInTitlebar() {
 | 
						|
  switch (StaticPrefs::browser_tabs_inTitlebar()) {
 | 
						|
    case 0:
 | 
						|
      return false;
 | 
						|
    case 1:
 | 
						|
      return true;
 | 
						|
    default:
 | 
						|
      break;
 | 
						|
  }
 | 
						|
  return nsLookAndFeel::GetInstance()->GetDefaultDrawInTitlebar();
 | 
						|
}
 | 
						|
 | 
						|
LookAndFeel::TitlebarAction LookAndFeel::GetTitlebarAction(
 | 
						|
    TitlebarEvent aEvent) {
 | 
						|
  return nsLookAndFeel::GetInstance()->GetTitlebarAction(aEvent);
 | 
						|
}
 | 
						|
 | 
						|
void LookAndFeel::GetThemeInfo(nsACString& aOut) {
 | 
						|
  nsLookAndFeel::GetInstance()->GetThemeInfo(aOut);
 | 
						|
}
 | 
						|
 | 
						|
uint32_t LookAndFeel::GetMenuAccessKey() {
 | 
						|
  return StaticPrefs::ui_key_menuAccessKey();
 | 
						|
}
 | 
						|
 | 
						|
Modifiers LookAndFeel::GetMenuAccessKeyModifiers() {
 | 
						|
  switch (GetMenuAccessKey()) {
 | 
						|
    case dom::KeyboardEvent_Binding::DOM_VK_SHIFT:
 | 
						|
      return MODIFIER_SHIFT;
 | 
						|
    case dom::KeyboardEvent_Binding::DOM_VK_CONTROL:
 | 
						|
      return MODIFIER_CONTROL;
 | 
						|
    case dom::KeyboardEvent_Binding::DOM_VK_ALT:
 | 
						|
      return MODIFIER_ALT;
 | 
						|
    case dom::KeyboardEvent_Binding::DOM_VK_META:
 | 
						|
    case dom::KeyboardEvent_Binding::DOM_VK_WIN:
 | 
						|
      return MODIFIER_META;
 | 
						|
    default:
 | 
						|
      return 0;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
// static
 | 
						|
void LookAndFeel::Refresh() {
 | 
						|
  nsLookAndFeel::GetInstance()->RefreshImpl();
 | 
						|
  widget::Theme::LookAndFeelChanged();
 | 
						|
}
 | 
						|
 | 
						|
// static
 | 
						|
void LookAndFeel::NativeInit() { nsLookAndFeel::GetInstance()->NativeInit(); }
 | 
						|
 | 
						|
// static
 | 
						|
void LookAndFeel::SetData(widget::FullLookAndFeel&& aTables) {
 | 
						|
  nsLookAndFeel::GetInstance()->SetDataImpl(std::move(aTables));
 | 
						|
}
 | 
						|
 | 
						|
}  // namespace mozilla
 |