Bug 1470983 - Remote all LookAndFeel values for the Gtk backend. r=spohl,jld

This adds a new LookAndFeel implementation, RemoteLookAndFeel, which can
be used in content processes and is supplied with all of its values by the
parent process.

Co-authored-by: Cameron McCormack <cam@mcc.id.au>

Differential Revision: https://phabricator.services.mozilla.com/D97977
This commit is contained in:
Jed Davis 2020-12-16 04:17:36 +00:00
parent cb3356b35e
commit 907aa1cd3c
27 changed files with 483 additions and 52 deletions

View File

@ -111,6 +111,7 @@
#include "mozilla/net/NeckoChild.h"
#include "mozilla/plugins/PluginInstanceParent.h"
#include "mozilla/plugins/PluginModuleParent.h"
#include "mozilla/widget/RemoteLookAndFeel.h"
#include "mozilla/widget/ScreenManager.h"
#include "mozilla/widget/WidgetMessageUtils.h"
#include "nsBaseDragService.h"
@ -602,7 +603,7 @@ NS_INTERFACE_MAP_END
mozilla::ipc::IPCResult ContentChild::RecvSetXPCOMProcessAttributes(
XPCOMInitData&& aXPCOMInit, const StructuredCloneData& aInitialData,
LookAndFeelCache&& aLookAndFeelCache,
LookAndFeelData&& aLookAndFeelData,
nsTArray<SystemFontListEntry>&& aFontList,
const Maybe<SharedMemoryHandle>& aSharedUASheetHandle,
const uintptr_t& aSharedUASheetAddress,
@ -611,7 +612,7 @@ mozilla::ipc::IPCResult ContentChild::RecvSetXPCOMProcessAttributes(
return IPC_OK();
}
mLookAndFeelCache = std::move(aLookAndFeelCache);
mLookAndFeelData = std::move(aLookAndFeelData);
mFontList = std::move(aFontList);
mSharedFontListBlocks = std::move(aSharedFontListBlocks);
#ifdef XP_WIN
@ -2287,8 +2288,17 @@ mozilla::ipc::IPCResult ContentChild::RecvNotifyVisited(
}
mozilla::ipc::IPCResult ContentChild::RecvThemeChanged(
LookAndFeelCache&& aLookAndFeelCache, widget::ThemeChangeKind aKind) {
LookAndFeel::SetCache(aLookAndFeelCache);
LookAndFeelData&& aLookAndFeelData, widget::ThemeChangeKind aKind) {
switch (aLookAndFeelData.type()) {
case LookAndFeelData::TLookAndFeelCache:
LookAndFeel::SetCache(aLookAndFeelData.get_LookAndFeelCache());
break;
case LookAndFeelData::TFullLookAndFeel:
LookAndFeel::SetData(std::move(aLookAndFeelData.get_FullLookAndFeel()));
break;
default:
MOZ_ASSERT(false, "unreachable");
}
LookAndFeel::NotifyChangedAllWindows(aKind);
return IPC_OK();
}

View File

@ -308,7 +308,8 @@ class ContentChild final : public PContentChild,
const bool& haveBidiKeyboards);
mozilla::ipc::IPCResult RecvNotifyVisited(nsTArray<VisitedQueryResult>&&);
mozilla::ipc::IPCResult RecvThemeChanged(LookAndFeelCache&& aLookAndFeelCache,
mozilla::ipc::IPCResult RecvThemeChanged(LookAndFeelData&& aLookAndFeelData,
widget::ThemeChangeKind);
mozilla::ipc::IPCResult RecvUpdateSystemParameters(
@ -546,7 +547,7 @@ class ContentChild final : public PContentChild,
mozilla::ipc::IPCResult RecvSetXPCOMProcessAttributes(
XPCOMInitData&& aXPCOMInit, const StructuredCloneData& aInitialData,
LookAndFeelCache&& aLookAndFeelCache,
LookAndFeelData&& aLookAndFeelData,
nsTArray<SystemFontListEntry>&& aFontList,
const Maybe<base::SharedMemoryHandle>& aSharedUASheetHandle,
const uintptr_t& aSharedUASheetAddress,
@ -611,7 +612,7 @@ class ContentChild final : public PContentChild,
bool DeallocPSessionStorageObserverChild(
PSessionStorageObserverChild* aActor);
LookAndFeelCache& BorrowLookAndFeelCache() { return mLookAndFeelCache; }
LookAndFeelData& BorrowLookAndFeelData() { return mLookAndFeelData; }
/**
* Helper function for protocols that use the GPU process when available.
@ -856,8 +857,8 @@ class ContentChild final : public PContentChild,
// parent process and used to initialize gfx in the child. Currently used
// only on MacOSX and Linux.
nsTArray<mozilla::dom::SystemFontListEntry> mFontList;
// Temporary storage for nsXPLookAndFeel cache info.
LookAndFeelCache mLookAndFeelCache;
// Temporary storage for look and feel data.
LookAndFeelData mLookAndFeelData;
// Temporary storage for list of shared-fontlist memory blocks.
nsTArray<base::SharedMemoryHandle> mSharedFontListBlocks;

View File

@ -72,6 +72,7 @@
#include "mozilla/Sprintf.h"
#include "mozilla/StaticPrefs_dom.h"
#include "mozilla/StaticPrefs_media.h"
#include "mozilla/StaticPrefs_widget.h"
#include "mozilla/StyleSheet.h"
#include "mozilla/StyleSheetInlines.h"
#include "mozilla/Telemetry.h"
@ -158,6 +159,7 @@
#include "mozilla/net/PCookieServiceParent.h"
#include "mozilla/plugins/PluginBridge.h"
#include "mozilla/RemoteLazyInputStreamParent.h"
#include "mozilla/widget/RemoteLookAndFeel.h"
#include "mozilla/widget/ScreenManager.h"
#include "nsAnonymousTemporaryFile.h"
#include "nsAppRunner.h"
@ -1484,6 +1486,21 @@ void ContentParent::BroadcastFontListChanged() {
}
}
static LookAndFeelData GetLookAndFeelData() {
if (StaticPrefs::widget_remote_look_and_feel_AtStartup()) {
return RemoteLookAndFeel::ExtractData();
}
return LookAndFeel::GetCache();
}
void ContentParent::BroadcastThemeUpdate(widget::ThemeChangeKind aKind) {
LookAndFeelData lnfData = GetLookAndFeelData();
for (auto* cp : AllProcesses(eLive)) {
Unused << cp->SendThemeChanged(lnfData, aKind);
}
}
const nsACString& ContentParent::GetRemoteType() const { return mRemoteType; }
void ContentParent::Init() {
@ -2730,7 +2747,7 @@ bool ContentParent::InitInternal(ProcessPriority aInitialPriority) {
nsTArray<SystemFontListEntry> fontList;
gfxPlatform::GetPlatform()->ReadSystemFontList(&fontList);
LookAndFeelCache lnfCache = LookAndFeel::GetCache();
LookAndFeelData lnfData = GetLookAndFeelData();
// If the shared fontlist is in use, collect its shmem block handles to pass
// to the child.
@ -2791,7 +2808,7 @@ bool ContentParent::InitInternal(ProcessPriority aInitialPriority) {
}
Unused << SendSetXPCOMProcessAttributes(
xpcomInit, initialData, lnfCache, fontList, sharedUASheetHandle,
xpcomInit, initialData, lnfData, fontList, sharedUASheetHandle,
sharedUASheetAddress, sharedFontListBlocks);
ipc::WritableSharedMap* sharedData =

View File

@ -255,6 +255,8 @@ class ContentParent final
static void BroadcastFontListChanged();
static void BroadcastThemeUpdate(widget::ThemeChangeKind);
const nsACString& GetRemoteType() const override;
virtual void DoGetRemoteType(nsACString& aRemoteType,

View File

@ -580,7 +580,7 @@ child:
* Tell the child that the system theme has changed, and that a repaint is
* necessary.
*/
async ThemeChanged(LookAndFeelCache aCache, ThemeChangeKind aKind);
async ThemeChanged(LookAndFeelData lookAndFeelData, ThemeChangeKind aKind);
async UpdateSystemParameters(SystemParameterKVPair[] aUpdates);
@ -688,7 +688,7 @@ child:
async SetXPCOMProcessAttributes(XPCOMInitData xpcomInit,
StructuredCloneData initialData,
LookAndFeelCache lookAndFeelCache,
LookAndFeelData lookAndFeeldata,
/* used on MacOSX/Linux/Android only: */
SystemFontListEntry[] systemFontList,
SharedMemoryHandle? sharedUASheetHandle,

View File

@ -1398,12 +1398,7 @@ void nsPresContext::ThemeChangedInternal() {
image::SurfaceCacheUtils::DiscardAll();
if (XRE_IsParentProcess()) {
nsTArray<ContentParent*> cp;
ContentParent::GetAll(cp);
widget::LookAndFeelCache lnfCache = LookAndFeel::GetCache();
for (ContentParent* c : cp) {
Unused << c->SendThemeChanged(lnfCache, kind);
}
ContentParent::BroadcastThemeUpdate(kind);
}
}

View File

@ -9579,9 +9579,9 @@
#if defined(XP_LINUX) && defined(MOZ_SANDBOX)
# Run content processes in headless mode and disallow connections to
# the X server. Experimental; breaks WebGL and Flash, and requires
# `widget.disable-native-theme-for-content`. Changing it requires a
# restart because sandbox policy information dependent on it is cached.
# See bug 1640345 for details.
# `widget.disable-native-theme-for-content` and `widget.remote-look-and-feel`.
# Changing it requires a restart because sandbox policy information dependent
# on it is cached. See bug 1640345 for details.
- name: security.sandbox.content.headless
type: bool
value: false
@ -10417,6 +10417,19 @@
mirror: always
#endif
# Enable the RemoteLookAndFeel in content processes, which will cause all
# LookAndFeel values to be queried in the parent process and sent to content
# processes using IPC. This is required for widgets to paint and behave
# correctly when `security.sandbox.content.headless` is enabled.
- name: widget.remote-look-and-feel
type: bool
#ifdef MOZ_WIDGET_GTK
value: true
#else
value: false
#endif
mirror: once
#---------------------------------------------------------------------------
# Prefs starting with "xul."
#---------------------------------------------------------------------------

View File

@ -21,6 +21,7 @@ struct gfxFontStyle;
namespace mozilla {
namespace widget {
class FullLookAndFeel;
class LookAndFeelCache;
} // namespace widget
@ -400,6 +401,9 @@ class LookAndFeel {
// The width/height ratio of the cursor. If used, the CaretWidth int metric
// should be added to the calculated caret width.
CaretAspectRatio,
// Not an ID; used to define the range of valid IDs. Must be last.
End,
};
// These constants must be kept in 1:1 correspondence with the
@ -555,6 +559,7 @@ class LookAndFeel {
*/
static widget::LookAndFeelCache GetCache();
static void SetCache(const widget::LookAndFeelCache& aCache);
static void SetData(widget::FullLookAndFeel&& aTables);
static void NotifyChangedAllWindows(widget::ThemeChangeKind);
};

View File

@ -16,7 +16,7 @@ struct LookAndFeelInt {
int32_t value;
};
struct LookAndFeelFont {
comparable struct LookAndFeelFont {
bool haveFont;
nsString name;
float size;
@ -35,5 +35,45 @@ struct LookAndFeelCache {
LookAndFeelColor[] mColors;
};
/**
* Stores the entirety of a LookAndFeel's data.
*
* The format allows for some compression compared with having fixed
* length arrays for each value type and some indication of whether
* a value is present. This is because not all values are present on
* a given platform, and because there is also substantial repetition
* of specific values.
*
* Each of ints, floats, colors, and fonts is an array that stores the
* unique values that occur in the LookAndFeel. intMap, floatMap,
* colorMap, and fontMap map from value IDs (LookAndFeel::IntID, etc.)
* to indexes into the value arrays. The map arrays are of fixed
* length, determined by the maximum ID value. If a value for a
* particular ID is not present, the entry in the map is set to -1.
*
* (Note that fontMap is different from the others since it maps from a
* LookAndFeel::FontID value minus 1, as 1 is the minimum value of that
* enum.)
*/
struct FullLookAndFeel {
int32_t[] ints;
float[] floats;
nscolor[] colors;
LookAndFeelFont[] fonts;
uint8_t[] intMap;
uint8_t[] floatMap;
uint8_t[] colorMap;
uint8_t[] fontMap;
uint16_t passwordChar;
bool passwordEcho;
};
union LookAndFeelData {
LookAndFeelCache;
FullLookAndFeel;
};
} // namespace widget
} // namespace mozilla

View File

@ -0,0 +1,195 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=8 et :
*/
/* 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 "RemoteLookAndFeel.h"
#include "gfxFont.h"
#include "MainThreadUtils.h"
#include "mozilla/Assertions.h"
#include "mozilla/Result.h"
#include "mozilla/ResultExtensions.h"
#include "nsXULAppAPI.h"
#include <limits>
#include <type_traits>
#include <utility>
namespace mozilla::widget {
RemoteLookAndFeel::RemoteLookAndFeel(FullLookAndFeel&& aTables)
: mTables(std::move(aTables)) {
MOZ_ASSERT(XRE_IsContentProcess(),
"Only content processes should be using a RemoteLookAndFeel");
}
RemoteLookAndFeel::~RemoteLookAndFeel() = default;
void RemoteLookAndFeel::SetDataImpl(FullLookAndFeel&& aTables) {
MOZ_ASSERT(XRE_IsContentProcess(),
"Only content processes should be using a RemoteLookAndFeel");
MOZ_ASSERT(NS_IsMainThread());
mTables = std::move(aTables);
}
namespace {
template <typename Item, typename UInt, typename ID>
Result<const Item*, nsresult> MapLookup(const nsTArray<Item>& aItems,
const nsTArray<UInt>& aMap, ID aID,
ID aMinimum = ID(0)) {
UInt mapped = aMap[static_cast<size_t>(aID) - static_cast<size_t>(aMinimum)];
if (mapped == std::numeric_limits<UInt>::max()) {
return Err(NS_ERROR_NOT_IMPLEMENTED);
}
return &aItems[static_cast<size_t>(mapped)];
}
template <typename Item, typename UInt>
void AddToMap(nsTArray<Item>* aItems, nsTArray<UInt>* aMap,
Maybe<Item>&& aNewItem) {
if (aNewItem.isNothing()) {
aMap->AppendElement(std::numeric_limits<UInt>::max());
return;
}
size_t newIndex = aItems->Length();
MOZ_ASSERT(newIndex < std::numeric_limits<UInt>::max());
// Check if there is an existing value in aItems that we can point to.
//
// The arrays should be small enough and contain few enough unique
// values that sequential search here is reasonable.
for (size_t i = 0; i < newIndex; ++i) {
if ((*aItems)[i] == aNewItem.ref()) {
aMap->AppendElement(static_cast<UInt>(i));
return;
}
}
aItems->AppendElement(aNewItem.extract());
aMap->AppendElement(static_cast<UInt>(newIndex));
}
} // namespace
nsresult RemoteLookAndFeel::NativeGetColor(ColorID aID, nscolor& aResult) {
const nscolor* result;
MOZ_TRY_VAR(result, MapLookup(mTables.colors(), mTables.colorMap(), aID));
aResult = *result;
return NS_OK;
}
nsresult RemoteLookAndFeel::NativeGetInt(IntID aID, int32_t& aResult) {
const int32_t* result;
MOZ_TRY_VAR(result, MapLookup(mTables.ints(), mTables.intMap(), aID));
aResult = *result;
return NS_OK;
}
nsresult RemoteLookAndFeel::NativeGetFloat(FloatID aID, float& aResult) {
const float* result;
MOZ_TRY_VAR(result, MapLookup(mTables.floats(), mTables.floatMap(), aID));
aResult = *result;
return NS_OK;
}
bool RemoteLookAndFeel::NativeGetFont(FontID aID, nsString& aFontName,
gfxFontStyle& aFontStyle) {
auto result =
MapLookup(mTables.fonts(), mTables.fontMap(), aID, FontID::MINIMUM);
if (result.isErr()) {
return false;
}
const LookAndFeelFont& font = *result.unwrap();
MOZ_ASSERT(font.haveFont());
aFontName = font.name();
aFontStyle = gfxFontStyle();
aFontStyle.size = font.size();
aFontStyle.weight = FontWeight(font.weight());
aFontStyle.style =
font.italic() ? FontSlantStyle::Italic() : FontSlantStyle::Normal();
return true;
}
char16_t RemoteLookAndFeel::GetPasswordCharacterImpl() {
return static_cast<char16_t>(mTables.passwordChar());
}
bool RemoteLookAndFeel::GetEchoPasswordImpl() { return mTables.passwordEcho(); }
// static
FullLookAndFeel RemoteLookAndFeel::ExtractData() {
MOZ_ASSERT(XRE_IsParentProcess(),
"Only parent processes should be extracting LookAndFeel data");
FullLookAndFeel lf{};
nsXPLookAndFeel* impl = nsXPLookAndFeel::GetInstance();
for (auto id : MakeEnumeratedRange(IntID::End)) {
int32_t theInt;
nsresult rv = impl->NativeGetInt(id, theInt);
AddToMap(&lf.ints(), &lf.intMap(),
NS_SUCCEEDED(rv) ? Some(theInt) : Nothing{});
}
for (auto id : MakeEnumeratedRange(FloatID::End)) {
float theFloat;
nsresult rv = impl->NativeGetFloat(id, theFloat);
AddToMap(&lf.floats(), &lf.floatMap(),
NS_SUCCEEDED(rv) ? Some(theFloat) : Nothing{});
}
for (auto id : MakeEnumeratedRange(ColorID::End)) {
nscolor theColor;
nsresult rv = impl->NativeGetColor(id, theColor);
AddToMap(&lf.colors(), &lf.colorMap(),
NS_SUCCEEDED(rv) ? Some(theColor) : Nothing{});
}
for (auto id :
MakeInclusiveEnumeratedRange(FontID::MINIMUM, FontID::MAXIMUM)) {
LookAndFeelFont font{};
gfxFontStyle fontStyle{};
bool rv = impl->NativeGetFont(id, font.name(), fontStyle);
Maybe<LookAndFeelFont> maybeFont;
if (rv) {
font.haveFont() = true;
font.size() = fontStyle.size;
font.weight() = fontStyle.weight.ToFloat();
font.italic() = fontStyle.style.IsItalic();
MOZ_ASSERT(fontStyle.style.IsNormal() || fontStyle.style.IsItalic(),
"Cannot handle oblique font style");
#ifdef DEBUG
{
// Assert that all the remaining font style properties have their
// default values.
gfxFontStyle candidate = fontStyle;
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
maybeFont = Some(std::move(font));
}
AddToMap(&lf.fonts(), &lf.fontMap(), std::move(maybeFont));
}
lf.passwordChar() = impl->GetPasswordCharacterImpl();
lf.passwordEcho() = impl->GetEchoPasswordImpl();
return lf;
}
} // namespace mozilla::widget

View File

@ -0,0 +1,53 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=8 et :
*/
/* 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/. */
#ifndef mozilla_widget_RemoteLookAndFeel_h__
#define mozilla_widget_RemoteLookAndFeel_h__
#include "mozilla/widget/nsXPLookAndFeel.h"
#include "mozilla/widget/LookAndFeelTypes.h"
namespace mozilla::widget {
/**
* A LookAndFeel implementation whose native values are provided by the
* parent process.
*/
class RemoteLookAndFeel final : public nsXPLookAndFeel {
public:
explicit RemoteLookAndFeel(FullLookAndFeel&& aTables);
virtual ~RemoteLookAndFeel();
void NativeInit() override {}
nsresult NativeGetInt(IntID aID, int32_t& aResult) override;
nsresult NativeGetFloat(FloatID aID, float& aResult) override;
nsresult NativeGetColor(ColorID aID, nscolor& aResult) override;
bool NativeGetFont(FontID aID, nsString& aFontName,
gfxFontStyle& aFontStyle) override;
char16_t GetPasswordCharacterImpl() override;
bool GetEchoPasswordImpl() override;
// Sets the LookAndFeel data to be used by this content process' singleton
// RemoteLookAndFeel object.
void SetDataImpl(FullLookAndFeel&& aTables) override;
// Extracts the data from the platform's default LookAndFeel implementation.
//
// This is called in the parent process to obtain the data to send down to
// content processes when they are created (and when the OS theme changes).
static FullLookAndFeel ExtractData();
private:
FullLookAndFeel mTables;
};
} // namespace mozilla::widget
#endif // mozilla_widget_RemoteLookAndFeel_h__

View File

@ -20,7 +20,11 @@ using mozilla::dom::ContentChild;
static const char16_t UNICODE_BULLET = 0x2022;
nsLookAndFeel::nsLookAndFeel() : nsXPLookAndFeel() {}
nsLookAndFeel::nsLookAndFeel(const LookAndFeelCache* aCache) {
if (aCache) {
DoSetCache(*aCache);
}
}
nsLookAndFeel::~nsLookAndFeel() {}
@ -505,6 +509,10 @@ widget::LookAndFeelCache nsLookAndFeel::GetCacheImpl() {
}
void nsLookAndFeel::SetCacheImpl(const LookAndFeelCache& aCache) {
DoSetCache(aCache);
}
void nsLookAndFeel::DoSetCache(const LookAndFeelCache& aCache) {
for (const auto& entry : aCache.mInts()) {
switch (entry.id()) {
case IntID::PrefersReducedMotion:

View File

@ -10,7 +10,7 @@
class nsLookAndFeel final : public nsXPLookAndFeel {
public:
nsLookAndFeel();
explicit nsLookAndFeel(const LookAndFeelCache* aCache);
virtual ~nsLookAndFeel();
void NativeInit() final;
@ -27,6 +27,8 @@ class nsLookAndFeel final : public nsXPLookAndFeel {
void SetCacheImpl(const LookAndFeelCache& aCache) override;
protected:
void DoSetCache(const LookAndFeelCache& aCache);
bool mInitializedSystemColors = false;
mozilla::AndroidSystemColors mSystemColors;
bool mInitializedShowPassword = false;

View File

@ -9,7 +9,7 @@
class nsLookAndFeel final : public nsXPLookAndFeel {
public:
nsLookAndFeel();
explicit nsLookAndFeel(const LookAndFeelCache* aCache);
virtual ~nsLookAndFeel();
void NativeInit() final;
@ -31,6 +31,7 @@ class nsLookAndFeel final : public nsXPLookAndFeel {
void SetCacheImpl(const LookAndFeelCache& aCache) override;
protected:
void DoSetCache(const LookAndFeelCache& aCache);
static bool AllowOverlayScrollbarsOverlap();
static bool SystemWantsDarkTheme();

View File

@ -27,7 +27,7 @@
@property(readonly) BOOL accessibilityDisplayShouldReduceMotion;
@end
nsLookAndFeel::nsLookAndFeel()
nsLookAndFeel::nsLookAndFeel(const LookAndFeelCache* aCache)
: nsXPLookAndFeel(),
mUseOverlayScrollbars(-1),
mUseOverlayScrollbarsCached(false),
@ -69,7 +69,11 @@ nsLookAndFeel::nsLookAndFeel()
mColorEvenTreeRow(0),
mColorOddTreeRow(0),
mColorActiveSourceListSelection(0),
mInitialized(false) {}
mInitialized(false) {
if (aCache) {
DoSetCache(*aCache);
}
}
nsLookAndFeel::~nsLookAndFeel() {}
@ -671,7 +675,9 @@ mozilla::widget::LookAndFeelCache nsLookAndFeel::GetCacheImpl() {
return cache;
}
void nsLookAndFeel::SetCacheImpl(const LookAndFeelCache& aCache) {
void nsLookAndFeel::SetCacheImpl(const LookAndFeelCache& aCache) { DoSetCache(aCache); }
void nsLookAndFeel::DoSetCache(const LookAndFeelCache& aCache) {
for (auto entry : aCache.mInts()) {
switch (entry.id()) {
case IntID::UseOverlayScrollbars:

View File

@ -59,7 +59,11 @@ extern mozilla::LazyLogModule gWidgetLog;
((nscolor)NS_RGBA((int)((c).red * 255), (int)((c).green * 255), \
(int)((c).blue * 255), (int)((c).alpha * 255)))
nsLookAndFeel::nsLookAndFeel() = default;
nsLookAndFeel::nsLookAndFeel(const LookAndFeelCache* aCache) {
if (aCache) {
DoSetCache(*aCache);
}
}
nsLookAndFeel::~nsLookAndFeel() = default;
@ -295,6 +299,10 @@ widget::LookAndFeelCache nsLookAndFeel::GetCacheImpl() {
}
void nsLookAndFeel::SetCacheImpl(const LookAndFeelCache& aCache) {
DoSetCache(aCache);
}
void nsLookAndFeel::DoSetCache(const LookAndFeelCache& aCache) {
for (const auto& entry : aCache.mInts()) {
switch (entry.id()) {
case IntID::SystemUsesDarkTheme:

View File

@ -18,7 +18,7 @@ struct _GtkStyle;
class nsLookAndFeel final : public nsXPLookAndFeel {
public:
nsLookAndFeel();
explicit nsLookAndFeel(const LookAndFeelCache* aCache);
virtual ~nsLookAndFeel();
void NativeInit() final;
@ -41,6 +41,7 @@ class nsLookAndFeel final : public nsXPLookAndFeel {
static const nscolor kWhite = NS_RGB(255, 255, 255);
protected:
void DoSetCache(const LookAndFeelCache& aCache);
bool WidgetUsesImage(WidgetNodeType aNodeType);
void RecordLookAndFeelSpecificTelemetry() override;
bool ShouldHonorThemeScrollbarColors();

View File

@ -4744,6 +4744,21 @@ nsresult nsWindow::Create(nsIWidget* aParent, nsNativeWidget aNativeParent,
G_CALLBACK(settings_changed_cb), this);
g_signal_connect_after(default_settings, "notify::gtk-xft-dpi",
G_CALLBACK(settings_xft_dpi_changed_cb), this);
// For remote LookAndFeel, to refresh the content processes' copies:
g_signal_connect_after(default_settings, "notify::gtk-cursor-blink-time",
G_CALLBACK(settings_changed_cb), this);
g_signal_connect_after(default_settings, "notify::gtk-cursor-blink",
G_CALLBACK(settings_changed_cb), this);
g_signal_connect_after(default_settings,
"notify::gtk-entry-select-on-focus",
G_CALLBACK(settings_changed_cb), this);
g_signal_connect_after(default_settings,
"notify::gtk-primary-button-warps-slider",
G_CALLBACK(settings_changed_cb), this);
g_signal_connect_after(default_settings, "notify::gtk-menu-popup-delay",
G_CALLBACK(settings_changed_cb), this);
g_signal_connect_after(default_settings, "notify::gtk-dnd-drag-threshold",
G_CALLBACK(settings_changed_cb), this);
}
if (mContainer) {

View File

@ -15,12 +15,27 @@ namespace widget {
#if defined(MOZ_WIDGET_GTK)
// Our nsLookAndFeel for GTK relies on APIs that aren't available in headless
// mode, so we use an implementation with hardcoded values.
// Our nsLookAndFeel for Gtk relies on APIs that aren't available in headless
// mode, so for processes that are unable to connect to a display server, we use
// an implementation with hardcoded values.
//
// HeadlessLookAndFeel is used:
//
// * in the parent process, when full headless mode (MOZ_HEADLESS=1) is
// enabled
// * in content processes, when full headless mode or headless content
// mode (security.sandbox.content.headless) is enabled, unless
// widget.remote-look-and-feel is also enabled, in which case
// RemoteLookAndFeel is used instead.
//
// The result of this is that when headless content mode is enabled, content
// processes use values derived from the parent's nsLookAndFeel (i.e., values
// derived from Gtk APIs) while still refraining from making any display server
// connections.
class HeadlessLookAndFeel : public nsXPLookAndFeel {
public:
HeadlessLookAndFeel();
explicit HeadlessLookAndFeel(const LookAndFeelCache* aCache);
virtual ~HeadlessLookAndFeel();
void NativeInit() final{};

View File

@ -15,7 +15,7 @@ namespace widget {
static const char16_t UNICODE_BULLET = 0x2022;
HeadlessLookAndFeel::HeadlessLookAndFeel() = default;
HeadlessLookAndFeel::HeadlessLookAndFeel(const LookAndFeelCache* aCache) {}
HeadlessLookAndFeel::~HeadlessLookAndFeel() = default;

View File

@ -177,7 +177,9 @@ EXPORTS.mozilla.widget += [
"InProcessCompositorWidget.h",
"MediaKeysEventSourceFactory.h",
"nsAutoRollup.h",
"nsXPLookAndFeel.h",
"PuppetBidiKeyboard.h",
"RemoteLookAndFeel.h",
"Screen.h",
"ScreenManager.h",
"ThemeChangeKind.h",
@ -215,6 +217,7 @@ UNIFIED_SOURCES += [
"nsXPLookAndFeel.cpp",
"PuppetBidiKeyboard.cpp",
"PuppetWidget.cpp",
"RemoteLookAndFeel.cpp",
"Screen.cpp",
"ScrollbarDrawingMac.cpp",
"SharedWidgetUtils.cpp",

View File

@ -10,6 +10,7 @@
#include "nsXPLookAndFeel.h"
#include "nsLookAndFeel.h"
#include "HeadlessLookAndFeel.h"
#include "RemoteLookAndFeel.h"
#include "nsContentUtils.h"
#include "nsCRT.h"
#include "nsFont.h"
@ -254,11 +255,44 @@ nsXPLookAndFeel* nsXPLookAndFeel::GetInstance() {
NS_ENSURE_TRUE(!sShutdown, nullptr);
if (gfxPlatform::IsHeadless()) {
sInstance = new widget::HeadlessLookAndFeel();
} else {
sInstance = new nsLookAndFeel();
// If we're in a content process, then the parent process will have supplied
// us with an initial FullLookAndFeel object (for when the RemoteLookAndFeel
// is to be used) or an initial LookAndFeelCache object (for regular
// LookAndFeel implementations). We grab this data from the ContentChild,
// where it's been temporarily stashed, and initialize our new LookAndFeel
// object with it.
LookAndFeelCache* lnfCache = nullptr;
FullLookAndFeel* fullLnf = nullptr;
widget::LookAndFeelData* lnfData = nullptr;
if (auto* cc = mozilla::dom::ContentChild::GetSingleton()) {
lnfData = &cc->BorrowLookAndFeelData();
switch (lnfData->type()) {
case widget::LookAndFeelData::TLookAndFeelCache:
lnfCache = &lnfData->get_LookAndFeelCache();
break;
case widget::LookAndFeelData::TFullLookAndFeel:
fullLnf = &lnfData->get_FullLookAndFeel();
break;
default:
MOZ_ASSERT_UNREACHABLE("unexpected LookAndFeelData type");
}
}
if (fullLnf) {
sInstance = new widget::RemoteLookAndFeel(std::move(*fullLnf));
} else if (gfxPlatform::IsHeadless()) {
sInstance = new widget::HeadlessLookAndFeel(lnfCache);
} else {
sInstance = new nsLookAndFeel(lnfCache);
}
// This is only ever used once during initialization, and can be cleared now.
if (lnfData) {
*lnfData = widget::LookAndFeelData{};
}
return sInstance;
}
@ -461,15 +495,6 @@ void nsXPLookAndFeel::Init() {
for (i = 0; i < ArrayLength(sColorPrefs); ++i) {
InitColorFromPref(i);
}
if (XRE_IsContentProcess()) {
mozilla::dom::ContentChild* cc = mozilla::dom::ContentChild::GetSingleton();
LookAndFeel::SetCache(cc->BorrowLookAndFeelCache());
// This is only ever used once during initialization, and can be cleared
// now.
cc->BorrowLookAndFeelCache() = LookAndFeelCache{};
}
}
nsXPLookAndFeel::~nsXPLookAndFeel() {
@ -1088,4 +1113,9 @@ void LookAndFeel::SetCache(const widget::LookAndFeelCache& aCache) {
nsLookAndFeel::GetInstance()->SetCacheImpl(aCache);
}
// static
void LookAndFeel::SetData(widget::FullLookAndFeel&& aTables) {
nsLookAndFeel::GetInstance()->SetDataImpl(std::move(aTables));
}
} // namespace mozilla

View File

@ -79,6 +79,7 @@ class nsXPLookAndFeel : public mozilla::LookAndFeel {
virtual uint32_t GetPasswordMaskDelayImpl() { return 600; }
using FullLookAndFeel = mozilla::widget::FullLookAndFeel;
using LookAndFeelCache = mozilla::widget::LookAndFeelCache;
using LookAndFeelInt = mozilla::widget::LookAndFeelInt;
using LookAndFeelFont = mozilla::widget::LookAndFeelFont;
@ -86,6 +87,7 @@ class nsXPLookAndFeel : public mozilla::LookAndFeel {
virtual LookAndFeelCache GetCacheImpl();
virtual void SetCacheImpl(const LookAndFeelCache& aCache) {}
virtual void SetDataImpl(FullLookAndFeel&& aTables) {}
virtual void NativeInit() = 0;

View File

@ -10,7 +10,7 @@
class nsLookAndFeel final : public nsXPLookAndFeel {
public:
nsLookAndFeel();
explicit nsLookAndFeel(const LookAndFeelCache* aCache);
virtual ~nsLookAndFeel();
void NativeInit() final;

View File

@ -13,7 +13,7 @@
#include "gfxFont.h"
#include "gfxFontConstants.h"
nsLookAndFeel::nsLookAndFeel() : nsXPLookAndFeel(), mInitialized(false) {}
nsLookAndFeel::nsLookAndFeel(LookAndFeelCache* aCache) : nsXPLookAndFeel(), mInitialized(false) {}
nsLookAndFeel::~nsLookAndFeel() {}

View File

@ -89,7 +89,7 @@ static nsresult SystemWantsDarkTheme(int32_t& darkThemeEnabled) {
return rv;
}
nsLookAndFeel::nsLookAndFeel()
nsLookAndFeel::nsLookAndFeel(const LookAndFeelCache* aCache)
: nsXPLookAndFeel(),
mUseAccessibilityTheme(0),
mUseDefaultTheme(0),
@ -103,6 +103,9 @@ nsLookAndFeel::nsLookAndFeel()
mInitialized(false) {
mozilla::Telemetry::Accumulate(mozilla::Telemetry::TOUCH_ENABLED_DEVICE,
WinUtils::IsTouchDeviceSupportPresent());
if (aCache) {
DoSetCache(*aCache);
}
}
nsLookAndFeel::~nsLookAndFeel() {}
@ -839,6 +842,10 @@ LookAndFeelCache nsLookAndFeel::GetCacheImpl() {
}
void nsLookAndFeel::SetCacheImpl(const LookAndFeelCache& aCache) {
DoSetCache(aCache);
}
void nsLookAndFeel::DoSetCache(const LookAndFeelCache& aCache) {
MOZ_ASSERT(XRE_IsContentProcess());
MOZ_RELEASE_ASSERT(aCache.mFonts().Length() == mFontCache.length());

View File

@ -46,7 +46,7 @@ class nsLookAndFeel final : public nsXPLookAndFeel {
static OperatingSystemVersion GetOperatingSystemVersion();
public:
nsLookAndFeel();
explicit nsLookAndFeel(const LookAndFeelCache* aCache);
virtual ~nsLookAndFeel();
void NativeInit() final;
@ -62,6 +62,8 @@ class nsLookAndFeel final : public nsXPLookAndFeel {
void SetCacheImpl(const LookAndFeelCache& aCache) override;
private:
void DoSetCache(const LookAndFeelCache& aCache);
/**
* Fetches the Windows accent color from the Windows settings if
* the accent color is set to apply to the title bar, otherwise