Bug 1697672 [wpt PR 28012] - Disable SVG composited animation if effective zoom is...
[gecko.git] / widget / RemoteLookAndFeel.cpp
blob685547d18c22196ca2eb95f734c7b33b520f9b3a
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: sw=2 ts=8 et :
3 */
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #include "RemoteLookAndFeel.h"
10 #include "gfxFont.h"
11 #include "MainThreadUtils.h"
12 #include "mozilla/Assertions.h"
13 #include "mozilla/ClearOnShutdown.h"
14 #include "mozilla/Result.h"
15 #include "mozilla/ResultExtensions.h"
16 #include "mozilla/StaticPrefs_widget.h"
17 #include "nsLookAndFeel.h"
18 #include "nsXULAppAPI.h"
20 #include <limits>
21 #include <type_traits>
22 #include <utility>
24 namespace mozilla::widget {
26 RemoteLookAndFeel::RemoteLookAndFeel(FullLookAndFeel&& aData)
27 : mTables(std::move(aData.tables())) {
28 MOZ_ASSERT(XRE_IsContentProcess(),
29 "Only content processes should be using a RemoteLookAndFeel");
31 #ifdef MOZ_WIDGET_GTK
32 if (!StaticPrefs::widget_non_native_theme_enabled()) {
33 // Configure the theme in this content process with the Gtk theme that was
34 // chosen by WithThemeConfiguredForContent in the parent process.
35 nsLookAndFeel::ConfigureTheme(aData.theme());
37 #endif
40 RemoteLookAndFeel::~RemoteLookAndFeel() = default;
42 void RemoteLookAndFeel::SetDataImpl(FullLookAndFeel&& aData) {
43 MOZ_ASSERT(XRE_IsContentProcess(),
44 "Only content processes should be using a RemoteLookAndFeel");
45 MOZ_ASSERT(NS_IsMainThread());
46 mTables = std::move(aData.tables());
48 #ifdef MOZ_WIDGET_GTK
49 if (!StaticPrefs::widget_non_native_theme_enabled()) {
50 // Configure the theme in this content process with the Gtk theme that was
51 // chosen by WithThemeConfiguredForContent in the parent process.
52 nsLookAndFeel::ConfigureTheme(aData.theme());
54 #endif
57 namespace {
59 template <typename Item, typename UInt, typename ID>
60 Result<const Item*, nsresult> MapLookup(const nsTArray<Item>& aItems,
61 const nsTArray<UInt>& aMap, ID aID,
62 ID aMinimum = ID(0)) {
63 UInt mapped = aMap[static_cast<size_t>(aID) - static_cast<size_t>(aMinimum)];
65 if (mapped == std::numeric_limits<UInt>::max()) {
66 return Err(NS_ERROR_NOT_IMPLEMENTED);
69 return &aItems[static_cast<size_t>(mapped)];
72 template <typename Item, typename UInt>
73 void AddToMap(nsTArray<Item>* aItems, nsTArray<UInt>* aMap,
74 Maybe<Item>&& aNewItem) {
75 if (aNewItem.isNothing()) {
76 aMap->AppendElement(std::numeric_limits<UInt>::max());
77 return;
80 size_t newIndex = aItems->Length();
81 MOZ_ASSERT(newIndex < std::numeric_limits<UInt>::max());
83 // Check if there is an existing value in aItems that we can point to.
85 // The arrays should be small enough and contain few enough unique
86 // values that sequential search here is reasonable.
87 for (size_t i = 0; i < newIndex; ++i) {
88 if ((*aItems)[i] == aNewItem.ref()) {
89 aMap->AppendElement(static_cast<UInt>(i));
90 return;
94 aItems->AppendElement(aNewItem.extract());
95 aMap->AppendElement(static_cast<UInt>(newIndex));
98 } // namespace
100 nsresult RemoteLookAndFeel::NativeGetColor(ColorID aID, nscolor& aResult) {
101 const nscolor* result;
102 MOZ_TRY_VAR(result, MapLookup(mTables.colors(), mTables.colorMap(), aID));
103 aResult = *result;
104 return NS_OK;
107 nsresult RemoteLookAndFeel::NativeGetInt(IntID aID, int32_t& aResult) {
108 const int32_t* result;
109 MOZ_TRY_VAR(result, MapLookup(mTables.ints(), mTables.intMap(), aID));
110 aResult = *result;
111 return NS_OK;
114 nsresult RemoteLookAndFeel::NativeGetFloat(FloatID aID, float& aResult) {
115 const float* result;
116 MOZ_TRY_VAR(result, MapLookup(mTables.floats(), mTables.floatMap(), aID));
117 aResult = *result;
118 return NS_OK;
121 bool RemoteLookAndFeel::NativeGetFont(FontID aID, nsString& aFontName,
122 gfxFontStyle& aFontStyle) {
123 auto result =
124 MapLookup(mTables.fonts(), mTables.fontMap(), aID, FontID::MINIMUM);
125 if (result.isErr()) {
126 return false;
129 const LookAndFeelFont& font = *result.unwrap();
130 MOZ_ASSERT(font.haveFont());
131 aFontName = font.name();
132 aFontStyle = gfxFontStyle();
133 aFontStyle.size = font.size();
134 aFontStyle.weight = FontWeight(font.weight());
135 aFontStyle.style =
136 font.italic() ? FontSlantStyle::Italic() : FontSlantStyle::Normal();
138 return true;
141 char16_t RemoteLookAndFeel::GetPasswordCharacterImpl() {
142 return static_cast<char16_t>(mTables.passwordChar());
145 bool RemoteLookAndFeel::GetEchoPasswordImpl() { return mTables.passwordEcho(); }
147 // static
148 const FullLookAndFeel* RemoteLookAndFeel::ExtractData() {
149 MOZ_ASSERT(XRE_IsParentProcess(),
150 "Only parent processes should be extracting LookAndFeel data");
152 if (sCachedLookAndFeelData) {
153 return sCachedLookAndFeelData;
156 static bool sInitialized = false;
157 if (!sInitialized) {
158 sInitialized = true;
159 ClearOnShutdown(&sCachedLookAndFeelData);
162 FullLookAndFeel* lf = new FullLookAndFeel{};
163 nsXPLookAndFeel* impl = nsXPLookAndFeel::GetInstance();
165 int32_t darkTheme = 0;
166 int32_t accessibilityTheme = 0;
167 impl->NativeGetInt(IntID::SystemUsesDarkTheme, darkTheme);
168 impl->NativeGetInt(IntID::UseAccessibilityTheme, accessibilityTheme);
170 impl->WithThemeConfiguredForContent([&](const LookAndFeelTheme& aTheme) {
171 for (auto id : MakeEnumeratedRange(IntID::End)) {
172 int32_t theInt;
173 nsresult rv;
174 // We want to take SystemUsesDarkTheme and UseAccessibilityTheme from
175 // the parent process theme rather than the content configured theme.
176 // This ensures that media queries like (prefers-color-scheme: dark) will
177 // match correctly in content processes.
179 // (When the RemoteLookAndFeel is not in use, the LookAndFeelCache
180 // ensures we get these values from the parent process theme.)
181 switch (id) {
182 case IntID::SystemUsesDarkTheme:
183 theInt = darkTheme;
184 rv = NS_OK;
185 break;
186 case IntID::UseAccessibilityTheme:
187 theInt = accessibilityTheme;
188 rv = NS_OK;
189 break;
190 default:
191 rv = impl->NativeGetInt(id, theInt);
192 break;
194 AddToMap(&lf->tables().ints(), &lf->tables().intMap(),
195 NS_SUCCEEDED(rv) ? Some(theInt) : Nothing{});
198 for (auto id : MakeEnumeratedRange(FloatID::End)) {
199 float theFloat;
200 nsresult rv = impl->NativeGetFloat(id, theFloat);
201 AddToMap(&lf->tables().floats(), &lf->tables().floatMap(),
202 NS_SUCCEEDED(rv) ? Some(theFloat) : Nothing{});
205 for (auto id : MakeEnumeratedRange(ColorID::End)) {
206 nscolor theColor;
207 nsresult rv = impl->NativeGetColor(id, theColor);
208 AddToMap(&lf->tables().colors(), &lf->tables().colorMap(),
209 NS_SUCCEEDED(rv) ? Some(theColor) : Nothing{});
212 for (auto id :
213 MakeInclusiveEnumeratedRange(FontID::MINIMUM, FontID::MAXIMUM)) {
214 LookAndFeelFont font{};
215 gfxFontStyle fontStyle{};
217 bool rv = impl->NativeGetFont(id, font.name(), fontStyle);
218 Maybe<LookAndFeelFont> maybeFont;
219 if (rv) {
220 font.haveFont() = true;
221 font.size() = fontStyle.size;
222 font.weight() = fontStyle.weight.ToFloat();
223 font.italic() = fontStyle.style.IsItalic();
224 MOZ_ASSERT(fontStyle.style.IsNormal() || fontStyle.style.IsItalic(),
225 "Cannot handle oblique font style");
226 #ifdef DEBUG
228 // Assert that all the remaining font style properties have their
229 // default values.
230 gfxFontStyle candidate = fontStyle;
231 gfxFontStyle defaults{};
232 candidate.size = defaults.size;
233 candidate.weight = defaults.weight;
234 candidate.style = defaults.style;
235 MOZ_ASSERT(candidate.Equals(defaults),
236 "Some font style properties not supported");
238 #endif
239 maybeFont = Some(std::move(font));
241 AddToMap(&lf->tables().fonts(), &lf->tables().fontMap(),
242 std::move(maybeFont));
245 lf->tables().passwordChar() = impl->GetPasswordCharacterImpl();
246 lf->tables().passwordEcho() = impl->GetEchoPasswordImpl();
247 #ifdef MOZ_WIDGET_GTK
248 lf->theme() = aTheme;
249 #endif
252 // This assignment to sCachedLookAndFeelData must be done after the
253 // WithThemeConfiguredForContent call, since it can end up calling RefreshImpl
254 // on the LookAndFeel, which will clear out sCachedTables.
255 sCachedLookAndFeelData = lf;
256 return sCachedLookAndFeelData;
259 void RemoteLookAndFeel::ClearCachedData() {
260 MOZ_ASSERT(XRE_IsParentProcess());
261 sCachedLookAndFeelData = nullptr;
264 StaticAutoPtr<FullLookAndFeel> RemoteLookAndFeel::sCachedLookAndFeelData;
266 } // namespace mozilla::widget