Closed Bug 1081142 Opened 10 years ago Closed 10 years ago

[HiDPI] select an appropriate scale factor on Linux

Categories

(Core :: Widget: Gtk, defect)

x86_64
Linux
defect
Not set
normal

Tracking

()

RESOLVED FIXED
mozilla38

People

(Reporter: nical, Unassigned)

References

Details

(Whiteboard: [fixed in bug 1097897])

Attachments

(3 files, 2 obsolete files)

Currently linux users get a scale factor of 1 regardless of whether or not they are use a HiDPI screen. As a result the UI looks broken (because a few icons from the native theme are scaled but most of the chrome is not) and the fix is to manually set a pref, which is a bad experience. We should ideally detect the setting of the system, but my understanding is that this requires gtk3. In the mean time I think that we should select the appropriate default scale depending on the dpi (unless the pref was set manually).
Component: Widget → Widget: Gtk
The attached patch computes the default scale automatically on HiDPI screens on Linux (where HiDPI is currently defined as dpi > 96). To reduce the issues with blurriness, it only uses integer scaling (so you'd get 1 or 2 device pixels per CSS pixel, but not 1.25 or 1.75).
New version of the patch. Now we also look at Xft.dpi to determine the scaling factor, which should give Firefox consistency with the most common DEs (at least GNOME, which always sets Xft.dpi, and KDE, which sets it if the user chooses to override the autodetected (physical) DPI). It might be necessary to extend this if other DEs do things differently.
Attachment #8503735 - Attachment is obsolete: true
Attachment #8503946 - Flags: review?(karlt)
Attachment #8503946 - Flags: feedback?(roc)
Comment on attachment 8503946 [details] [diff] [review] Automatically set scaling factor on Linux (v2) Review of attachment 8503946 [details] [diff] [review]: ----------------------------------------------------------------- This looks like it could be slow. Can we cache the result? ::: widget/gtk/nsWindow.cpp @@ +753,5 @@ > + // We want to set the default CSS to device pixel ratio as the > + // closest _integer_ multiple, so round the ratio of actual dpi > + // to CSS dpi (96) > + if (dpi > 96) > + scale = round(dpi/96.0); {} If Xft.dpi is set, shouldn't we use that to drive our scale without rounding? What does GTK3 do?
Attachment #8503946 - Flags: feedback?(roc) → feedback+
(In reply to Robert O'Callahan (:roc) (Mozilla Corporation) from comment #3) > Comment on attachment 8503946 [details] [diff] [review] > Automatically set scaling factor on Linux (v2) > > Review of attachment 8503946 [details] [diff] [review]: > ----------------------------------------------------------------- > > This looks like it could be slow. Can we cache the result? > > ::: widget/gtk/nsWindow.cpp > @@ +753,5 @@ > > + // We want to set the default CSS to device pixel ratio as the > > + // closest _integer_ multiple, so round the ratio of actual dpi > > + // to CSS dpi (96) > > + if (dpi > 96) > > + scale = round(dpi/96.0); > > {} It depends on whether we want to support dynamic display settings (e.g. user plugs a different monitor with a different DPI and switches to it) and mixed-DPI environments (e.g. built-in HiDPI laptop display plus standard-DPI external monitor). If we don't plan on supporting these situation, we can have a system-wide cache (static member variable). At a later stage, we could implement some support for xrandr and hook on display configuration changes to “refresh” the global value. If we want to suport mixed-DPI environments, the cache should be widget-specific, and might need to be refreshed when moving from one screen (or xrandr output) to another.
I haven't forgotten about this, but I need to review the issues involved here.
Blocks: 712898
Unlike Chrome/Chromium, UI text in Firefox and SeaMonkey using their current default scale factor behave perfectly well on Linux when the KDE, LXDE, IceWM and other non-Gnome DEs are obeying DPI from 96 up to any value below 192 appropriately configured via the Xorg foundation those DEs depend on, and with Xft.dpi unset. Please do not "fix" what is not broken.
(In reply to Felix Miata from comment #7) > Unlike Chrome/Chromium, UI text in Firefox and SeaMonkey using their current > default scale factor behave perfectly well on Linux when the KDE, LXDE, > IceWM and other non-Gnome DEs are obeying DPI from 96 up to any value below > 192 appropriately configured via the Xorg foundation those DEs depend on, > and with Xft.dpi unset. Please do not "fix" what is not broken. The problem is not with DPIs < 192, it's with higher DPIs, i.e. when scaling (x2, x3, etc) is necessary to actually make things legible. In these cases, e.g. KDE will by default scale things up, even with Xft.dpi unset, whereas Firefox does not. However, you point an interesting thing, which is that up to 192 (exclusive) no scaling is applied in these environments. I can change the patch to only scale to the lowest multiple of 96 that is _not greater than_ the actual DPI. So we would have 1 device pixel per CSS pixel for DPIs up to 192 _exclusive_, 2 device pixels for DPIs from 192 (inclusive) to 288 (exclusive), and so on.
(In reply to Felix Miata from comment #7) > Unlike Chrome/Chromium, UI text in Firefox and SeaMonkey using their current > default scale factor behave perfectly well on Linux when the KDE, LXDE, > IceWM and other non-Gnome DEs are obeying DPI from 96 up to any value below > 192 appropriately configured via the Xorg foundation those DEs depend on, > and with Xft.dpi unset. Please do not "fix" what is not broken. Changes proposed here can be tested by setting layout.css.devPixelsPerPx in about:config. If you have a logical dpi > 144, does setting devPixelsPerPx to something like dpi / 96 make things worse for you?
(In reply to Giuseppe Bilotta from comment #8) > However, you point an interesting thing, which is that up to 192 (exclusive) > no scaling is applied in these environments. Where are you seeing this decision re the point at which to start scaling? This is what gsd-xsettings-manager does, but it uses physical dpi instead of logical dpi. I suspect there may be more cases on high physical dpi screens where logical dpi is smaller than physical dpi. > I can change the patch to only > scale to the lowest multiple of 96 that is _not greater than_ the actual > DPI. So we would have 1 device pixel per CSS pixel for DPIs up to 192 > _exclusive_, 2 device pixels for DPIs from 192 (inclusive) to 288 > (exclusive), and so on. I'm would be fine with that. It is hard to choose between the options of 1 and 2 for dpi's from 144 to somewhere approaching 192, because neither produces particularly good icon sizes. Ideally Gecko would ask GTK for icon sizes, and this wouldn't be a (or at least our) problem. However, my impression (to which I assume there are counter-examples), is that the UI generally expands OKish to larger fonts, but doesn't compact too well if the scale factor is too large, so my inclination is that we should err on the side of too small a scale factor. Perhaps there's some debatably better heuristics but there is also value in predictability. Both rounding to nearest and rounding down are reasonably predictable, so I think those are the options. If choosing to round to nearest, then I think breaking ties to round down would be safer. The other issue is the effect of the default scale on web content. Page zoom can compensate for that somewhat, but perhaps an additional step of 1.5 would be useful. We don't need to stick with GTK3 scale factors because natively themed UI elements are drawn at the size indicated by the theme, regardless of what GetDefaultScale() returns. If adding a step of 1.5 then I think any dpi < 144 should use a scale of 1, so as to keep images sharp. I'm fine if we leave out the 1.5 step for now, though. I think snapping to one in a set of "standard" scale factors is good. I don't know that Gecko provides a good way for content (or UI) to specify that images are rendered at their unscaled resolution, and, even if it did, I'm not sure that pages would in general be designed well enough to accommodate variations in the ratio between image sizes and CSS px.
Comment on attachment 8503946 [details] [diff] [review] Automatically set scaling factor on Linux (v2) >+ Display *dpy = GDK_DISPLAY_XDISPLAY(gdk_display_get_default()); >+ const char *xft_dpi = XGetDefault(dpy, "Xft", "dpi"); >+ if (xft_dpi == NULL) { >+ // no Xft.dpi, use physical DPI >+ dpi = GetDPI(); >+ } else { >+ dpi = PR_strtod(xft_dpi, nullptr); >+ } I agree, this is the logic we want. I don't know whether or not this is efficient, but GTK caches this for us anyway. gfxPlatformGtk::GetDPI() should be used here. It will also do the right thing by reducing the dpi when GTK3 is already scaling, and will be one piece of code to modify if/when we handle dynamic changes. Yes, its unfortunately the same name as nsWindow::GetDPI(), but does something quite different. Feel free to rename it and/or move it out of gfxPlatformGtk to nsWindow or nsLookAndFeel. The only blocker, I'm aware of, to doing this by default, is bug 1097897. But we can add the code now, if the default value of the pref is changed to 1.
Attachment #8503946 - Flags: review?(karlt) → review-
Apparently we should use gesettings' org.gnome.desktop.interface scaling-factor.
Although apparently that only allows integer ratios :-(.
Looks like bug 975919 does it for GTK3.
Depends on: 975919
GSettings is very awkward to use because it was designed for application prefs where applications know what keys are supported. When used for system prefs, it is hard to use because it is hard to query for which keys are supported. Querying for a unsupported key is a programming error, possibly a crash. org.gnome.desktop.interface scaling-factor is used by GNOME and provides the same value irrespective of Screens (and Displays). gsd-xsettings-manager translates this to Gdk/WindowScalingFactor, which is conveyed to GDK3 by XSettings, which can differ across different Screens, but not different monitors on one Screen. Some non-GNOME environments support XSettings, but I don't recall which. We could read the XSettings through X11 properties and events, but there is no need to, and not all DEs support Gdk/WindowScalingFactor. gsd-xsettings-manager will double the dpi we get when org.gnome.desktop.interface scaling-factor is 2, so we get the right answer from a dpi calculation like in the patch here, and that works even on systems without Gdk/WindowScalingFactor.
(In reply to Robert O'Callahan (:roc) (Mozilla Corporation) from comment #14) > Although apparently that only allows integer ratios :-(. That's actually a good thing honestly. A non-integer ratio between device and CSS pixels leads to a blurrier look for any bitmap. That's also the reason why my patch doesn't just return the physical to CSS ratio as-is, but rounded. The only question is if it makes more sense to round to nearest or always round down.
With font settings appropriately personalized, layout.css.devPixelsPerPx: -1.0 does an adequate job for those like me for whom: 1-Icons are typically dismal micro-blobs anyway (certainly better than Chrom*). 2-Xorg's arbitrary default forcing to 96 logical DPI is overridden globally to produce a logical DPI better matched to physical DPI and user needs.
(In reply to Karl Tomlinson (:karlt) from comment #9) > Changes proposed here can be tested by setting layout.css.devPixelsPerPx in > about:config. If you have a logical dpi > 144, does setting > devPixelsPerPx to something like dpi / 96 make things worse for you? Clearly worse as things stand. In practical terms, I don't see non-default layout.css.devPixelsPerPx as much other than a way to restore the problems that bugs like bug 424375 and bug 394103 had to fix, and a producer of bugs like bug 248648 or bug 269304 that lie fallow nearly a decade, or more. Something to consider as a foundation going forward, for which a recent search located no existing bug, is as Roc stated in https://bugzilla.mozilla.org/show_bug.cgi?id=712898#c5: "We *should* be automatically making fonts and form elements match those used by your desktop. If those automatically change size when you change screen resolution, we should follow suit." I don't get the apparently universal notion that the baseline size for text and other objects or baseline font family within a browser viewport should vary materially, if at all, from elsewhere across the DE. Maybe layout.css.devPixelsPerPx can be or morph into the knob users need to scale stylists' tunnel vision into usable pages, or even do it automatically, but I only see it as a much too crude band-aid on an unacknowledged fundamental problem that web page stylists are predominantly using a sizing unit that completely disregards user preferences, and is an arbitrary size over which the user and his browser do not have fine-grained (continuously variable) physical size control. The X server has no similar limitation. Its logical density can be arbitrarily configured in tiny steps with no apparent impact on visual response from increment to increment. Until the question of whether automatic scaling on the browser canvas should be triggered at a value larger than something in the 0.05-0.10 neighborhood, certainly much less than a crude 0.5 or worse, the very idea should be deferred, if not abandoned. No one lacking the eyes of a raptor should be able to spot any significant difference between two nearly identical screens, one at 143 DPI and its neighbor at 145, or another at 191 and its neighbor at 193. (In reply to Karl Tomlinson (:karlt) from comment #10) > Where are you seeing this decision re the point at which to start scaling? Could this be reference to the fallout from fixing bug 177805 that eventually resulted in the first threshold being raised from 144 to 192, truncating instead of rounding up beyond 149.9999% of 96? (In reply to Giuseppe Bilotta from comment #17) > A non-integer ratio between device > and CSS pixels leads to a blurrier look for any bitmap. A "blurrier look" as a practical matter for users is not materially different in overall detriment to an unscaled too-small-to-see-details-in bitmap.
Comment 19 reference to bug 269304 was supposed to be to bug 296304
(In reply to Felix Miata from comment #19) > (In reply to Giuseppe Bilotta from comment #17) > > A non-integer ratio between device > > and CSS pixels leads to a blurrier look for any bitmap. > > A "blurrier look" as a practical matter for users is not materially > different in overall detriment to an unscaled too-small-to-see-details-in > bitmap. I would say that's debatable. I've seen people complaining about blurriness more often than font size, but that might just be what I've come across. However, if this is indeed the case, we can just round to the next integer (i.e. using 2.0 instead of 1.75).
Attached patch scale v.3Splinter Review
Karl, something like that?
Attachment #8503946 - Attachment is obsolete: true
Attachment #8555223 - Flags: review?(karlt)
Comment on attachment 8555223 [details] [diff] [review] scale v.3 >+ // Determine default scale based on DPI settings. We look first >+ // at the Xft.dpi resource and, if unset, rely on the actual >+ // display DPI. >+ static double scale = 0; >+ >+ if (scale == 0) { >+ float dpi; >+ Display *dpy = GDK_DISPLAY_XDISPLAY(gdk_display_get_default()); >+ const char *xft_dpi = XGetDefault(dpy, "Xft", "dpi"); >+ if (xft_dpi == NULL) { >+ // no Xft.dpi, use physical DPI >+ dpi = gfxPlatformGtk::GetDPI(); >+ } else { >+ dpi = PR_strtod(xft_dpi, nullptr); >+ } No need to use XGetDefault at all here. Instead always use gfxPlatformGtk::GetDPI(), which will use physical dpi or XGetDefault() or XSettings as appropriate. It also caches the result, updating when XSettings change, so better not to use a static variable. With GTK3, I think this scale should be determined by rounding (GdkScaleFactor() * gfxPlatformGtk::GetDPI()), which is the unscaled font dpi. In some environments, Gdk/WindowScalingFactor won't be set, but Xft dpi may be set to indicate desired scaling. (I'm happy to accept a GTK2-only patch like this if you'd prefer not to think about GTK3 for now.) (In reply to Karl Tomlinson (back 2 Feb:karlt) from comment #11) > The only blocker, I'm aware of, to doing this by default, is bug 1097897. > But we can add the code now, if the default value of the pref is > changed to 1. I'm still concerned about bug 1097897, so think layout.css.devPixelsPerPx should default to 1.0 until that is fixed, but only for GTK2. GTK3 will need this scale factor, so keep -1.0 there.
Attachment #8555223 - Flags: review?(karlt) → review-
I believe this bug is fixed by Bug 1097897, right?
Status: NEW → RESOLVED
Closed: 10 years ago
Depends on: 1097897
Resolution: --- → FIXED
Whiteboard: [fixed in bug 1097897]
Target Milestone: --- → mozilla38
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: