Bug 1812868 - Expose scrollbar-inline-size as a CSS variable to chrome code. r=mstange

For that we need to:

 * Make GetDPIRatioForScrollbarPart thread-safe: This was using the
   widget for bug 1727289, but just looking at the print preview scale
   is enough to fix that.

 * Make nsPresContext::UseOverlayScrollbars() thread-safe: We store the
   RDM pane stuff in the pres context.

The rest is pretty straight-forward.

Differential Revision: https://phabricator.services.mozilla.com/D168148
This commit is contained in:
Emilio Cobos Álvarez 2023-02-17 21:15:06 +00:00
parent 42ef1bc602
commit ad4bd6a3ba
13 changed files with 121 additions and 50 deletions

View File

@ -2757,21 +2757,7 @@ void BrowsingContext::DidSet(FieldIndex<IDX_InRDMPane>, bool aOldValue) {
if (GetInRDMPane() == aOldValue) {
return;
}
PreOrderWalk([&](BrowsingContext* aContext) {
if (nsIDocShell* shell = aContext->GetDocShell()) {
if (nsPresContext* pc = shell->GetPresContext()) {
pc->RecomputeTheme();
// This is a bit of a lie, but this affects the overlay-scrollbars
// media query and it's the code-path that gets taken for regular system
// metrics changes via ThemeChanged().
pc->MediaFeatureValuesChanged(
{MediaFeatureChangeReason::SystemMetricsChange},
MediaFeatureChangePropagation::JustThisDocument);
}
}
});
PresContextAffectingFieldChanged();
}
bool BrowsingContext::CanSet(FieldIndex<IDX_PageAwakeRequestCount>,

View File

@ -278,6 +278,7 @@ nsPresContext::nsPresContext(dom::Document* aDocument, nsPresContextType aType)
mFontFeatureValuesDirty(true),
mFontPaletteValuesDirty(true),
mIsVisual(false),
mInRDMPane(false),
mHasWarnedAboutTooLargeDashedOrDottedRadius(false),
mQuirkSheetAdded(false),
mHadNonBlankPaint(false),
@ -858,6 +859,8 @@ void nsPresContext::AttachPresShell(mozilla::PresShell* aPresShell) {
// have a presshell, and hence a document.
GetUserPreferences();
EnsureTheme();
nsIURI* docURI = doc->GetDocumentURI();
if (IsDynamic() && docURI) {
@ -933,6 +936,8 @@ void nsPresContext::RecomputeBrowsingContextDependentData() {
return browsingContext->GetEmbedderColorSchemes().mPreferred;
}());
SetInRDMPane(top->GetInRDMPane());
if (doc == mDocument) {
// Medium doesn't apply to resource documents, etc.
RefPtr<nsAtom> mediumToEmulate;
@ -1286,6 +1291,14 @@ void nsPresContext::UpdateEffectiveTextZoom() {
MediaFeatureChangePropagation::JustThisDocument);
}
void nsPresContext::SetInRDMPane(bool aInRDMPane) {
if (mInRDMPane == aInRDMPane) {
return;
}
mInRDMPane = aInRDMPane;
RecomputeTheme();
}
float nsPresContext::GetDeviceFullZoom() {
return mDeviceContext->GetFullZoom();
}
@ -1629,8 +1642,7 @@ void nsPresContext::RecordInteractionTime(InteractionType aType,
nsITheme* nsPresContext::EnsureTheme() {
MOZ_ASSERT(!mTheme);
if (Document()->ShouldAvoidNativeTheme()) {
BrowsingContext* bc = Document()->GetBrowsingContext();
if (bc && bc->Top()->InRDMPane()) {
if (mInRDMPane) {
mTheme = do_GetRDMThemeDoNotUseDirectly();
} else {
mTheme = do_GetBasicNativeThemeDoNotUseDirectly();
@ -1651,17 +1663,21 @@ void nsPresContext::RecomputeTheme() {
if (oldTheme == mTheme) {
return;
}
// Theme only affects layout information, not style, so we just need to
// reframe (as it affects whether we create scrollbar buttons for example).
RebuildAllStyleData(nsChangeHint_ReconstructFrame, RestyleHint{0});
// Theme affects layout information (as it affects whether we create
// scrollbar buttons for example) and also style (affects the
// scrollbar-inline-size env var).
RebuildAllStyleData(nsChangeHint_ReconstructFrame,
RestyleHint::RecascadeSubtree());
// This is a bit of a lie, but this affects the overlay-scrollbars
// media query and it's the code-path that gets taken for regular system
// metrics changes via ThemeChanged().
MediaFeatureValuesChanged({MediaFeatureChangeReason::SystemMetricsChange},
MediaFeatureChangePropagation::JustThisDocument);
}
bool nsPresContext::UseOverlayScrollbars() const {
if (LookAndFeel::GetInt(LookAndFeel::IntID::UseOverlayScrollbars)) {
return true;
}
BrowsingContext* bc = Document()->GetBrowsingContext();
return bc && bc->Top()->InRDMPane();
return LookAndFeel::GetInt(LookAndFeel::IntID::UseOverlayScrollbars) ||
mInRDMPane;
}
void nsPresContext::ThemeChanged(widget::ThemeChangeKind aKind) {

View File

@ -502,7 +502,9 @@ class nsPresContext : public nsISupports, public mozilla::SupportsWeakPtr {
*
* XXX Temporary: see http://wiki.mozilla.org/Gecko:PrintPreview
*/
float GetPrintPreviewScaleForSequenceFrame() { return mPPScale; }
float GetPrintPreviewScaleForSequenceFrameOrScrollbars() const {
return mPPScale;
}
void SetPrintPreviewScale(float aScale) { mPPScale = aScale; }
nsDeviceContext* DeviceContext() const { return mDeviceContext; }
@ -573,6 +575,7 @@ class nsPresContext : public nsISupports, public mozilla::SupportsWeakPtr {
}
void SetFullZoom(float aZoom);
void SetOverrideDPPX(float);
void SetInRDMPane(bool aInRDMPane);
public:
float GetFullZoom() { return mFullZoom; }
@ -824,17 +827,9 @@ class nsPresContext : public nsISupports, public mozilla::SupportsWeakPtr {
*/
uint32_t GetBidi() const;
/*
* Obtain a native theme for rendering our widgets (both form controls and
* html)
*
* Guaranteed to return non-null.
*/
nsITheme* Theme() MOZ_NONNULL_RETURN {
if (MOZ_LIKELY(mTheme)) {
return mTheme;
}
return EnsureTheme();
nsITheme* Theme() const MOZ_NONNULL_RETURN {
MOZ_ASSERT(mTheme);
return mTheme;
}
void RecomputeTheme();
@ -907,6 +902,8 @@ class nsPresContext : public nsISupports, public mozilla::SupportsWeakPtr {
return mType == eContext_Print || mType == eContext_PrintPreview;
}
bool IsPrintPreview() const { return mType == eContext_PrintPreview; }
// Is this presentation in a chrome docshell?
bool IsChrome() const;
@ -1352,6 +1349,9 @@ class nsPresContext : public nsISupports, public mozilla::SupportsWeakPtr {
unsigned mIsVisual : 1;
// Are we in the RDM pane?
unsigned mInRDMPane : 1;
unsigned mHasWarnedAboutTooLargeDashedOrDottedRadius : 1;
// Have we added quirk.css to the style set?

View File

@ -146,7 +146,7 @@ NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
float nsPageSequenceFrame::GetPrintPreviewScale() const {
nsPresContext* pc = PresContext();
float scale = pc->GetPrintPreviewScaleForSequenceFrame();
float scale = pc->GetPrintPreviewScaleForSequenceFrameOrScrollbars();
WritingMode wm = GetWritingMode();
if (pc->IsScreen() && MOZ_LIKELY(mScrollportSize.ISize(wm) > 0 &&

View File

@ -305,6 +305,16 @@ bool Gecko_AnimationNameMayBeReferencedFromStyle(
return aPresContext->AnimationManager()->AnimationMayBeReferenced(aName);
}
float Gecko_GetScrollbarInlineSize(const nsPresContext* aPc) {
MOZ_ASSERT(aPc);
AutoWriteLock guard(*sServoFFILock); // We read some look&feel values.
auto overlay = aPc->UseOverlayScrollbars() ? nsITheme::Overlay::Yes
: nsITheme::Overlay::No;
LayoutDeviceIntCoord size =
aPc->Theme()->GetScrollbarSize(aPc, StyleScrollbarWidth::Auto, overlay);
return aPc->DevPixelsToFloatCSSPixels(size);
}
PseudoStyleType Gecko_GetImplementedPseudo(const Element* aElement) {
return aElement->GetPseudoElementType();
}

View File

@ -350,6 +350,8 @@ void Gecko_NoteAnimationOnlyDirtyElement(const mozilla::dom::Element*);
bool Gecko_AnimationNameMayBeReferencedFromStyle(const nsPresContext*,
nsAtom* name);
float Gecko_GetScrollbarInlineSize(const nsPresContext*);
// Incremental restyle.
mozilla::PseudoStyleType Gecko_GetImplementedPseudo(
const mozilla::dom::Element*);

View File

@ -22,6 +22,7 @@ tags = fullscreen
[test_display_mode_reflow.html]
support-files = display_mode_reflow.html
tags = fullscreen
[test_scrollbar_inline_size.html]
[test_hover.html]
skip-if = true # bug 1346353
[test_moz_document_rules.html]

View File

@ -0,0 +1,35 @@
<!DOCTYPE HTML>
<meta charset="utf-8">
<title>Test for env(scrollbar-inline-size)</title>
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" href="chrome://global/skin"/>
<link rel="stylesheet" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
<div id="scroller" style="width: 100px; height: 100px; overflow: scroll"></div>
<div id="ref" style="width: env(scrollbar-inline-size, 1000px)"></div>
<script>
SimpleTest.waitForExplicitFinish();
async function runTest() {
// We need to disable overlay scrollbars to measure the real scrollbar
// size.
await SpecialPowers.pushPrefEnv({
set: [["ui.useOverlayScrollbars", 0]],
});
runOnce();
info("with full zoom");
SpecialPowers.setFullZoom(window, 2.0);
runOnce();
}
function runOnce() {
let scroller = document.getElementById("scroller");
let ref = document.getElementById("ref");
let scrollbarSize = scroller.getBoundingClientRect().width - scroller.clientWidth;
ok(scrollbarSize > 0, "Should have a scrollbar");
is(ref.getBoundingClientRect().width, scrollbarSize, "env() should match the scrollbar size");
}
runTest().then(SimpleTest.finish);
</script>

View File

@ -10,6 +10,7 @@ const NON_CONTENT_ACCESSIBLE_ENV_VARS = [
"-moz-gtk-csd-maximize-button-position",
"-moz-gtk-csd-close-button-position",
"-moz-content-preferred-color-scheme",
"scrollbar-inline-size",
];
const div = document.querySelector("div");

View File

@ -78,6 +78,10 @@ fn get_content_preferred_color_scheme(device: &Device) -> VariableValue {
})
}
fn get_scrollbar_inline_size(device: &Device) -> VariableValue {
VariableValue::pixels(device.scrollbar_inline_size().px())
}
static ENVIRONMENT_VARIABLES: [EnvironmentVariable; 4] = [
make_variable!(atom!("safe-area-inset-top"), get_safearea_inset_top),
make_variable!(atom!("safe-area-inset-bottom"), get_safearea_inset_bottom),
@ -104,7 +108,7 @@ macro_rules! lnf_int_variable {
}};
}
static CHROME_ENVIRONMENT_VARIABLES: [EnvironmentVariable; 6] = [
static CHROME_ENVIRONMENT_VARIABLES: [EnvironmentVariable; 7] = [
lnf_int_variable!(
atom!("-moz-gtk-csd-titlebar-radius"),
TitlebarRadius,
@ -130,6 +134,10 @@ static CHROME_ENVIRONMENT_VARIABLES: [EnvironmentVariable; 6] = [
atom!("-moz-content-preferred-color-scheme"),
get_content_preferred_color_scheme
),
make_variable!(
atom!("scrollbar-inline-size"),
get_scrollbar_inline_size
),
];
impl CssEnvironment {

View File

@ -199,6 +199,18 @@ impl Device {
unsafe { bindings::Gecko_GetBaseSize(self.document(), language.as_ptr(), generic) }
}
/// Gets the size of the scrollbar in CSS pixels.
pub fn scrollbar_inline_size(&self) -> Length {
let pc = match self.pres_context() {
Some(pc) => pc,
// XXX: we could have a more reasonable default perhaps.
None => return Length::new(0.0),
};
Length::new(unsafe {
bindings::Gecko_GetScrollbarInlineSize(pc)
})
}
/// Queries font metrics
pub fn query_font_metrics(
&self,
@ -541,8 +553,11 @@ impl Device {
}
/// Return whether the document is a chrome document.
///
/// This check is consistent with how we enable chrome rules for chrome:// and resource://
/// stylesheets (and thus chrome:// documents).
#[inline]
pub fn is_chrome_document(&self) -> bool {
self.pref_sheet_prefs().mIsChrome
self.document().mDocURISchemeIsChrome()
}
}

View File

@ -24,16 +24,12 @@ using mozilla::RelativeLuminanceUtils;
/* static */
auto ScrollbarDrawing::GetDPIRatioForScrollbarPart(const nsPresContext* aPc)
-> DPIRatio {
auto ratio = [&] {
if (auto* rootPc = aPc->GetRootPresContext()) {
if (nsCOMPtr<nsIWidget> widget = rootPc->GetRootWidget()) {
return widget->GetDefaultScale();
}
}
return DPIRatio(
float(AppUnitsPerCSSPixel()) /
float(aPc->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom()));
}();
DPIRatio ratio(
float(AppUnitsPerCSSPixel()) /
float(aPc->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom()));
if (aPc->IsPrintPreview()) {
ratio.scale *= aPc->GetPrintPreviewScaleForSequenceFrameOrScrollbars();
}
if (mKind == Kind::Cocoa) {
return DPIRatio(ratio.scale >= 2.0f ? 2.0f : 1.0f);
}

View File

@ -1117,6 +1117,7 @@ STATIC_ATOMS = [
Atom("scrollbarbutton", "scrollbarbutton"),
Atom("scrollbarDownBottom", "scrollbar-down-bottom"),
Atom("scrollbarDownTop", "scrollbar-down-top"),
Atom("scrollbarInlineSize", "scrollbar-inline-size"),
Atom("scrollbarUpBottom", "scrollbar-up-bottom"),
Atom("scrollbarUpTop", "scrollbar-up-top"),
Atom("scrollbox", "scrollbox"),