For years, developers have lived comfortably with the assumption
that screen resolutions were in the predictable confines of a certain
pixel density—around 75 to 100 pixels-per-inch (ppi). As everyone
who sees the latest Chromebook models from Google knows, however, such
is no longer the case: the newest displays are well over 200 ppi. There have been partially-completed attempts
to modify GNOME for high-resolution display support, but with little
success. But now there appears to be a workable solution, as Alex
Larsson demonstrated at GUADEC 2013.
The latest Chromebook (the "Pixel") boasts a 239 ppi screen, Larsson
said, at which resolution GNOME's user interface elements are
unreadably tiny. Allegedly, the display resolution is configurable,
via the Xft.DPI setting, which has long been hard-coded to 96
in GNOME. But simply changing it to 239 does not work; as he showed
the audience, the result only scales the size of displayed text.
Although that improves legibility, UI elements like buttons and
scrollbars are still ridiculously tiny. In addition, text labels and
icons no longer line up, the default heights of menu bars and buttons
is no longer correct, and many other UI assumptions are broken.
Perhaps the system could be modified to scale everything according
to this DPI setting, he said. But despite the fact that the idea
seems intuitive, he continued, simply scaling all of the UI elements is not the
solution—scaling lines to a non-integer-multiple gives the user
fuzzy lines that should be sharp and blurry icons that arguably look
worse than the unscaled originals. Vector elements need to be drawn so
that they align to the pixel grid of the display, and a separate fix
needs to be available for those elements still using PNG or other
raster graphics formats.
There are a lot of places in GNOME's user interface that are
implicitly sized according to raster images and pixel-specific measurements: icons,
cursors, window borders, padding, the minimum sizes of GTK+
widgets—even the cursor speed is defined in terms of pixels.
The list of places where the code would need to change is lengthy, and
changing it holds the possibility for a lot of unexpected breakage.
But then again, he continued, scaling everything to the exact same
physical size is not strictly required; users already cope well with
the variations in size caused by the different resolutions of laptop
displays and external monitors; no one complains that a button is 6mm
high on one and 8mm high on the other. All that really matters is
that the system scales elements to approximately similar size on the
Pixel display.
Abstraction to the rescue
The notion that the correct solution only needs to approximate the
difference in resolution turned out to be one of the key insights.
Larsson's eventual answer was to treat the existing "pixel" sizes
already in use as an abstract, rather than a physical measurement, so
that high-resolution displays appear low-resolution to the top levels
of the software stack, and to set a scaling factor that multiplies the
actual pixel count rendered on high-resolution displays. For almost everything above the drawing layer, the current definition
of pixel would suffice; the pixel size itself could be scaled only
when rendered by
the lower-level libraries like Cairo and GDK, with very few side
effects. Moreover, by always scaling abstract pixels to monitor
pixels by integer factors, the pixel grid would automatically be
preserved, meaning vector images would remain sharp—and the math
would be considerably simpler, too.
He then implemented the abstract pixel scaling plan in Cairo, GDK,
and GTK+. Normal monitors are unaffected, as their scaling factor is
1. "HiDPI" monitors like the Pixel use a scaling factor of 2, which
results in a usable desktop interface, despite the on-screen elements
not quite being the same physical dimensions.
In Cairo, the high-resolution scale factor is applied when the
Cairo surface is rendered; applications can access the scaling factor
for the display with cairo_surface_get_device_scale(), but
normally GTK+ hides it completely. Similarly, in GDK, the sizes and
positions of windows, screens, and monitors is still reported in
abstract pixels; gdk_window_get_scale_factor() will report
the scaling factor, but it is usually unnecessary for applications to
know it. Wayland compositors will scale client buffers as necessary,
and will allow clients to provide double-scale buffers to cope with
the occasional window that spans both a high- and low-resolution
display. X support is less flexible; all displays must be the same
scale, which is reported via the GDK_SCALE environment
variable, but, Larsson said, Wayland is the protocol of the future, so
the development there is more important.
There are new functions like
gdk_window_create_similar_surface() to transparently create
an offscreen surface for the purpose of double-buffering, and
GtkIconTheme has been patched to support specifying both
normal-resolution and high-resolution versions of icons, but by and
large the scaling function is invisible to application code. There
are also hooks in place for use when displaying images and other
situations where scaling up window content is inappropriate. The
scaling functionality is due to land in Cairo 1.13, and Wayland
support has been added in version 1.2 of the Wayland protocol
definition. The GTK+ and GDK changes are currently available in
Larsson's wip/window-scales branch.
Larsson added that GTK+ on Mac OS X also supports the
scaling factor, using the operating system's Quartz library. Windows
support, however, remains on the to-do list. For the time being,
there are very few displays on the market that require a scaling
factor other than 1. Larsson described the Chromebook Pixel as the
primary driving factor, but Apple Retina displays are also supported,
and there are a handful of high-density netbook displays that qualify
as high-resolution as well. For the present, 1 and 2 remain the only
scaling factors in deployment. There is no telling if or when a 3 or
4 scaling factor will be required for some future display, but when it
does, the GNOME stack will be prepared well in advance.
[The author wishes to thank the GNOME Foundation for assistance
with travel to GUADEC 2013.]
(
Log in to post comments)