Bug 1967139 - [x11] CSD decoration painting shouldn't honor text scale. r=stransky

Otherwise with 1.5 scale or so we draw a too big border / radius which
causes the corner to be ugly.

Differential Revision: https://phabricator.services.mozilla.com/D249906
This commit is contained in:
Emilio Cobos Álvarez
2025-05-19 11:50:27 +00:00
committed by ealvarez@mozilla.com
parent 4e26479bc5
commit 437fba298d
8 changed files with 64 additions and 60 deletions

View File

@@ -7,10 +7,7 @@
#define _NS_DEVICECONTEXT_H_
#include <stdint.h> // for uint32_t
#include <sys/types.h> // for int32_t
#include "gfxTypes.h" // for gfxFloat
#include "gfxFont.h" // for gfxFont::Orientation
#include "mozilla/Assertions.h" // for MOZ_ASSERT_HELPER2
#include "mozilla/RefPtr.h" // for RefPtr
#include "nsCOMPtr.h" // for nsCOMPtr
#include "nsCoord.h" // for nscoord
@@ -21,8 +18,7 @@
#include "mozilla/AppUnits.h" // for AppUnits
#include "nsFontMetrics.h" // for nsFontMetrics::Params
#include "mozilla/gfx/Point.h" // for IntSize
#include "mozilla/gfx/PrintTarget.h" // for PrintTarget::PageDoneCallback
#include "mozilla/gfx/PrintPromise.h"
#include "mozilla/gfx/PrintPromise.h" // for PrintEndDocumentPromise
class gfxContext;
class gfxTextPerfMetrics;
@@ -45,6 +41,9 @@ enum class ScreenOrientation : uint32_t;
namespace widget {
class Screen;
} // namespace widget
namespace gfx {
class PrintTarget;
}
} // namespace mozilla
class nsDeviceContext final {

View File

@@ -6,13 +6,17 @@
#ifndef MOZILLA_GFX_PRINTPROMISE_H
#define MOZILLA_GFX_PRINTPROMISE_H
#include "ErrorList.h"
#include "mozilla/MozPromise.h"
#include "nscore.h"
namespace mozilla::gfx {
namespace mozilla {
template <typename ResolveValueT, typename RejectValueT, bool IsExclusive>
class MozPromise;
namespace gfx {
using PrintEndDocumentPromise = MozPromise</* unused */ bool, nsresult, false>;
} // namespace mozilla::gfx
} // namespace gfx
} // namespace mozilla
#endif

View File

@@ -28,6 +28,7 @@ headers = [
"mozilla/PresShell.h",
"mozilla/ServoTraversalStatistics.h",
"mozilla/SizeOfState.h",
"nsDeviceContext.h",
"nsCSSProps.h",
"nsNameSpaceManager.h",
]
@@ -311,6 +312,7 @@ opaque-types = [
"RefPtr_Proxy_member_function",
"nsAutoPtr_Proxy",
"nsAutoPtr_Proxy_member_function",
"nsRegion_.*",
"mozilla::detail::HashTable", # <- We should be able to remove this and
# HashSet below once
# https://github.com/rust-lang/rust-bindgen/pull/1515

View File

@@ -142,6 +142,13 @@ macro_rules! lnf_int_variable {
}};
}
fn eval_gtk_csd_titlebar_radius(device: &Device, url_data: &UrlExtraData) -> VariableValue {
let int_pixels = lnf_int!(TitlebarRadius);
let unzoomed_scale =
device.device_pixel_ratio_ignoring_full_zoom().get() / device.device_pixel_ratio().get();
VariableValue::pixels(int_pixels as f32 * unzoomed_scale, url_data)
}
static CHROME_ENVIRONMENT_VARIABLES: [EnvironmentVariable; 10] = [
lnf_int_variable!(
atom!("-moz-mac-titlebar-height"),
@@ -153,10 +160,9 @@ static CHROME_ENVIRONMENT_VARIABLES: [EnvironmentVariable; 10] = [
TitlebarButtonSpacing,
int_pixels
),
lnf_int_variable!(
make_variable!(
atom!("-moz-gtk-csd-titlebar-radius"),
TitlebarRadius,
int_pixels
eval_gtk_csd_titlebar_radius
),
lnf_int_variable!(
atom!("-moz-gtk-csd-tooltip-radius"),

View File

@@ -478,6 +478,20 @@ impl Device {
}
}
/// Returns app units per pixel at 1x full-zoom.
fn app_units_per_device_pixel_at_unit_full_zoom(&self) -> i32 {
match self.pres_context() {
Some(pc) => unsafe { (*pc.mDeviceContext.mRawPtr).mAppUnitsPerDevPixelAtUnitFullZoom },
None => AU_PER_PX,
}
}
/// Returns the device pixel ratio, ignoring the full zoom factor.
pub fn device_pixel_ratio_ignoring_full_zoom(&self) -> Scale<f32, CSSPixel, DevicePixel> {
let au_per_px = AU_PER_PX as f32;
Scale::new(au_per_px / self.app_units_per_device_pixel_at_unit_full_zoom() as f32)
}
/// Returns the device pixel ratio.
pub fn device_pixel_ratio(&self) -> Scale<f32, CSSPixel, DevicePixel> {
let pc = match self.pres_context() {

View File

@@ -28,7 +28,6 @@ enum class CSDStyle {
};
static bool gHeaderBarShouldDrawContainer = false;
static bool gMaximizedHeaderBarShouldDrawContainer = false;
static CSDStyle gCSDStyle = CSDStyle::Unknown;
static GtkWidget* sWidgetStorage[MOZ_GTK_WIDGET_NODE_COUNT];
static GtkStyleContext* sStyleStorage[MOZ_GTK_WIDGET_NODE_COUNT];
@@ -190,24 +189,12 @@ static void CreateHeaderBarWidget(WidgetNodeType aAppearance) {
gtk_style_context_add_class(headerBarStyle, "default-decoration");
sWidgetStorage[aAppearance] = headerBar;
if (aAppearance == MOZ_GTK_HEADER_BAR_MAXIMIZED) {
MOZ_ASSERT(!sWidgetStorage[MOZ_GTK_HEADERBAR_WINDOW_MAXIMIZED],
"Window widget is already created!");
MOZ_ASSERT(!sWidgetStorage[MOZ_GTK_HEADERBAR_FIXED_MAXIMIZED],
"Fixed widget is already created!");
gtk_style_context_add_class(windowStyle, "maximized");
sWidgetStorage[MOZ_GTK_HEADERBAR_WINDOW_MAXIMIZED] = window;
sWidgetStorage[MOZ_GTK_HEADERBAR_FIXED_MAXIMIZED] = fixed;
} else {
MOZ_ASSERT(!sWidgetStorage[MOZ_GTK_HEADERBAR_WINDOW],
"Window widget is already created!");
MOZ_ASSERT(!sWidgetStorage[MOZ_GTK_HEADERBAR_FIXED],
"Fixed widget is already created!");
sWidgetStorage[MOZ_GTK_HEADERBAR_WINDOW] = window;
sWidgetStorage[MOZ_GTK_HEADERBAR_FIXED] = fixed;
}
MOZ_ASSERT(!sWidgetStorage[MOZ_GTK_HEADERBAR_WINDOW],
"Window widget is already created!");
MOZ_ASSERT(!sWidgetStorage[MOZ_GTK_HEADERBAR_FIXED],
"Fixed widget is already created!");
sWidgetStorage[MOZ_GTK_HEADERBAR_WINDOW] = window;
sWidgetStorage[MOZ_GTK_HEADERBAR_FIXED] = fixed;
gtk_container_add(GTK_CONTAINER(window), fixed);
gtk_container_add(GTK_CONTAINER(fixed), headerBar);
@@ -216,10 +203,7 @@ static void CreateHeaderBarWidget(WidgetNodeType aAppearance) {
// Some themes like Elementary's style the container of the headerbar rather
// than the header bar itself.
bool& shouldDrawContainer = aAppearance == MOZ_GTK_HEADER_BAR
? gHeaderBarShouldDrawContainer
: gMaximizedHeaderBarShouldDrawContainer;
shouldDrawContainer = [&] {
gHeaderBarShouldDrawContainer = [&] {
const bool headerBarHasBackground = HasBackground(headerBarStyle);
if (headerBarHasBackground && GetBorderRadius(headerBarStyle)) {
return false;
@@ -250,7 +234,6 @@ bool IsSolidCSDStyleUsed() {
static void CreateHeaderBar() {
CreateHeaderBarWidget(MOZ_GTK_HEADER_BAR);
CreateHeaderBarWidget(MOZ_GTK_HEADER_BAR_MAXIMIZED);
}
static GtkWidget* CreateWidget(WidgetNodeType aAppearance) {
@@ -276,11 +259,8 @@ static GtkWidget* CreateWidget(WidgetNodeType aAppearance) {
case MOZ_GTK_TREE_HEADER_CELL:
return CreateTreeHeaderCellWidget();
case MOZ_GTK_HEADERBAR_WINDOW:
case MOZ_GTK_HEADERBAR_WINDOW_MAXIMIZED:
case MOZ_GTK_HEADERBAR_FIXED:
case MOZ_GTK_HEADERBAR_FIXED_MAXIMIZED:
case MOZ_GTK_HEADER_BAR:
case MOZ_GTK_HEADER_BAR_MAXIMIZED:
/* Create header bar widgets once and fill with child elements as we need
the header bar fully configured to get a correct style */
CreateHeaderBar();
@@ -536,14 +516,14 @@ static GtkStyleContext* GetCssNodeStyleInternal(WidgetNodeType aNodeType) {
break;
case MOZ_GTK_WINDOW_DECORATION: {
GtkStyleContext* parentStyle =
CreateSubStyleWithClass(MOZ_GTK_WINDOW, "csd");
CreateSubStyleWithClass(MOZ_GTK_HEADERBAR_WINDOW, "csd");
style = CreateCSSNode("decoration", parentStyle);
g_object_unref(parentStyle);
break;
}
case MOZ_GTK_WINDOW_DECORATION_SOLID: {
GtkStyleContext* parentStyle =
CreateSubStyleWithClass(MOZ_GTK_WINDOW, "solid-csd");
CreateSubStyleWithClass(MOZ_GTK_HEADERBAR_WINDOW, "solid-csd");
style = CreateCSSNode("decoration", parentStyle);
g_object_unref(parentStyle);
break;
@@ -606,9 +586,6 @@ void ResetWidgetCache() {
if (sWidgetStorage[MOZ_GTK_HEADERBAR_WINDOW]) {
gtk_widget_destroy(sWidgetStorage[MOZ_GTK_HEADERBAR_WINDOW]);
}
if (sWidgetStorage[MOZ_GTK_HEADERBAR_WINDOW_MAXIMIZED]) {
gtk_widget_destroy(sWidgetStorage[MOZ_GTK_HEADERBAR_WINDOW_MAXIMIZED]);
}
/* Clear already freed arrays */
mozilla::PodArrayZero(sWidgetStorage);
@@ -688,12 +665,9 @@ void StyleContextSetScale(GtkStyleContext* style, gint aScaleFactor) {
}
bool HeaderBarShouldDrawContainer(WidgetNodeType aNodeType) {
MOZ_ASSERT(aNodeType == MOZ_GTK_HEADER_BAR ||
aNodeType == MOZ_GTK_HEADER_BAR_MAXIMIZED);
MOZ_ASSERT(aNodeType == MOZ_GTK_HEADER_BAR);
mozilla::Unused << GetWidget(aNodeType);
return aNodeType == MOZ_GTK_HEADER_BAR
? gHeaderBarShouldDrawContainer
: gMaximizedHeaderBarShouldDrawContainer;
return gHeaderBarShouldDrawContainer;
}
gint GetBorderRadius(GtkStyleContext* aStyle) {

View File

@@ -134,20 +134,14 @@ enum WidgetNodeType : int {
MOZ_GTK_WINDOW,
/* Used only as a container for MOZ_GTK_HEADER_BAR. */
MOZ_GTK_HEADERBAR_WINDOW,
/* Used only as a container for MOZ_GTK_HEADER_BAR_MAXIMIZED. */
MOZ_GTK_HEADERBAR_WINDOW_MAXIMIZED,
/* Used only as a container for MOZ_GTK_HEADER_BAR. */
MOZ_GTK_HEADERBAR_FIXED,
/* Used only as a container for MOZ_GTK_HEADER_BAR_MAXIMIZED. */
MOZ_GTK_HEADERBAR_FIXED_MAXIMIZED,
/* Window container for all widgets */
MOZ_GTK_WINDOW_CONTAINER,
/* Used for scrolled window shell. */
MOZ_GTK_SCROLLED_WINDOW,
/* Paints a GtkHeaderBar */
MOZ_GTK_HEADER_BAR,
/* Paints a GtkHeaderBar in maximized state */
MOZ_GTK_HEADER_BAR_MAXIMIZED,
/* Client-side window decoration node. Available on GTK 3.20+. */
MOZ_GTK_WINDOW_DECORATION,

View File

@@ -62,8 +62,18 @@ static int gLastGdkError;
// Return widget scale factor of the monitor where the window is located by the
// most part. We intentionally honor the text scale factor here in order to
// have consistent scaling with other UI elements.
static inline CSSToLayoutDeviceScale GetWidgetScaleFactor(nsIFrame* aFrame) {
// have consistent scaling with other UI elements, except for the window
// decorations, which should use unscaled pixels.
static inline CSSToLayoutDeviceScale GetWidgetScaleFactor(
nsIFrame* aFrame, StyleAppearance aAppearance) {
if (aAppearance == StyleAppearance::MozWindowDecorations) {
// Window decorations can't honor the text scale.
return CSSToLayoutDeviceScale{
float(AppUnitsPerCSSPixel()) /
float(aFrame->PresContext()
->DeviceContext()
->AppUnitsPerDevPixelAtUnitFullZoom())};
}
return aFrame->PresContext()->CSSToDevPixelScale();
}
@@ -503,7 +513,7 @@ nsNativeThemeGTK::DrawWidgetBackground(gfxContext* aContext, nsIFrame* aFrame,
Transparency transparency = GetWidgetTransparency(aFrame, aAppearance);
// gdk rectangles are wrt the drawing rect.
auto scaleFactor = GetWidgetScaleFactor(aFrame);
auto scaleFactor = GetWidgetScaleFactor(aFrame, aAppearance);
LayoutDeviceIntRect gdkDevRect(-drawingRect.TopLeft(), widgetRect.Size());
auto gdkCssRect = CSSIntRect::RoundIn(gdkDevRect / scaleFactor);
@@ -632,7 +642,8 @@ LayoutDeviceIntMargin nsNativeThemeGTK::GetWidgetBorder(
GtkTextDirection direction = GetTextDirection(aFrame);
CSSIntMargin result = GetCachedWidgetBorder(aFrame, aAppearance, direction);
return (CSSMargin(result) * GetWidgetScaleFactor(aFrame)).Rounded();
return (CSSMargin(result) * GetWidgetScaleFactor(aFrame, aAppearance))
.Rounded();
}
bool nsNativeThemeGTK::GetWidgetPadding(nsDeviceContext* aContext,