I was hoping to wrap up my Pango work after the previous update, but unexpected trouble came in from the side – Benjamin made GtkLabel more serious about height-for-width, and that uncovered some inaccuracies in Pango’s line wrapping implementation. Sometimes, we would make our lines shorter than necessary, and sometimes, we would let a hyphen leak out of the allotted width, creating an overlong line.
Fixing all this up took some serious effort, but I think it was time well spent. One of the outcomes is that Pango now has APIs to serialize PangoLayout objects, and these are used in the testsuite.
A Layout Editor
To get some (visual) insight into what was going wrong with line breaking, I wrote a quick utility called layout-editor. This is how it looks:
It lets you tweak all the parameters of a PangoLayout object and shows you the results of your changes. It can also show details about pango’s analysis of the text. And it can overlay extra information, such as extents of lines, runs, glyphs, caret positions, and more.
Since the layout editor also uses the serialization APIs to load and save your layouts, you can directly use it to inspect the test cases in Pango’s testsuite and create new ones. This should help improve test coverage, going forward.
If you want to gain more insight into what is happening inside Pango, this tool might be for you.
With this new tool in hands, I felt the urge to see if it can help for feature development too. One long-standing feature gap in Pango is the lack of support for tab stops with alignments other than left.
Amazingly, an almost 15 year old patch found in this bug still mostly applied, and worked, after some small adaptations. The new tool was indeed very helpful in working out some of the finer points.
If you always felt like you should be able to line up numbers properly at their decimal point, instead of picking a monospace font and hoping for the best, voila! now you can.
Here is another update on what will appear in Pango 1.50 soon. Quite a few things, as it turns out. (This is a continuation of my last Pango update)
Pango has long claimed to have good support for bidirectional text rendering and editing. But until recently, there were some annoying bugs: you could end up in loops when moving the cursor through mixed-direction text.
The relevant code has been rewritten, closing a very old bug (#157).
Modern fonts can contain a lot of different information – there can be colormaps, and glyphs can be represented not just as splines, but also as pngs or svgs.
For GTK, an important piece of information for each glyph is whether it is colored or monochrome. With the new PangoGlyphVisAttr.is_color field, GTK no longer needs to poke directly at the font data to find out.
Another case where GTK needed data that wasn’t available through Pango APIs has been closed with pango_font_get_languages(). This data is used in the font chooser filter popup:
Superscripts and subscripts
Superscripts and subscripts now use font metrics information for size changes and baseline shift. They can also be properly nested, so markup like
yields the expected rendering:
Pango determines word and sentence boundaries according to the Unicode Text Segmentation Spec (TR29). The specification can’t deal with all the complexities of formatted text, so sometimes its results need tailoring, which can now be done with the new word and sentence attributes:
Besides the new attributes that have been mentioned, Pango markup now lets you specify many attributes in more natural units.
For example, you can now say
Pango has had the PangoVariant enumeration with its PANGO_VARIANT_SMALL_CAPS value since forever, but it has never done anything. Since we’ve added support for OpenType features (in Pango 1.37), it has been possible to produce Small Caps by using the smcp=1 feature, if the font supports it. Sadly, most fonts don’t.
With the text transformation and font scaling infrastructure now in place, it was easy to emulate Small Caps for fonts that don’t support this natively:
While at it, we’ve expanded the PangoVariant enumeration to cover all the CSS casing variants, and made the GTK CSS engine use them instead of OpenType features.
Pango ships with a versatile test utility called pango-view, which has options to test many of Pangos layout features. It has recently learned to show more auxiliary information in visual form, like glyph extents, caret positions and slopes:
I’ve spent some time on Pango, recently. Here is a little update on the feature work that I’ve done there. All of these changes will appear in Pango 1.50 and GTK 4.6.
The general directions of this work are:
Take advantage of the fact that we are now using harfbuzz on all platforms. Among other things, this gives us much easier access to font information.
Match CSS where it makes sense. If nothing else, this makes it much easier to connect new Pango features to the CSS machinery in GTK.
Lets start with the second point: matching CSS.
Line spacing has historically been a bit painful in GtkTextView. You can set distances before and after paragraphs, and between wrapped lines inside a paragraph. But this does not take font sizes into account—it is a fixed number of pixels.
A while ago, I added a line-spacing factor to Pango, which was meant to help with the font size dependency. You basically tell Pango: I want the baselines of this paragraph spaced apart 1.33 times as wide as they would normally be. The remaining problem is that Pango handles text one paragraph at a time. So as far as it is concerned, there is not previous baseline above the first line in a paragraph, and it does not increase the spacing between paragraphs.
The CSS solution to this problem is to just make the lines themselves taller, and place them flush next to each other. With this approach, you need to be a little careful to make sure that you still get consistent baseline-to-baseline distances. But at least it solves the paragraph spacing issue.
Pango recently gained a line-height attribute that does just that, and GTK now supports the corresponding CSS property.
Another feature that has come to Pango from the CSS side is support for text transformation (also in the screenshot). This lets you change the capitalization of text. Note that this is just for presentation purposes—if you select STRASSE in the example and copy it to the clipboard, you get the original straße.
And again, GTK supports the corresponding CSS property.
As I said, harfbuzz makes it much easier for us to access features of the fonts we use. One of these that I have recently looked into is caret metrics. High-quality italic fonts can contain information about the slope at which the text caret is best drawn to match the text:
I’ve added a new api to get this information, and made GTK use it, with this result:
Another useful bit of font information concerns placement or carets inside ligatures.
Historically, Pango has just divided the width of the glyph evenly among the characters that are forming the ligature (w and i, in this example), but high-quality fonts can provide this information. This is most relevant for scripts using many ligatures, such as Arabic.I’ve made Pango use the ligature caret data if it is available from the font, and got this result:
The wi ligature in this test is what I could come up with after a struggling for a few hours with fontforge (clearly, font design is not in my future). The only other fonts I’ve found with ligature caret information are Arabic, and I sadly can’t read or write that script.
The last feature closed a 15 year old bug – not something you get to do every day!
The last time I talked about flatpak updates, I explained how flatpak apps can detect that a newer version has been installed, and restart themselves. That is great, and may almost be good enough when you have automatic updates. But that is not always the case.
Thankfully, we can do better. Since 1.5, Flatpak has a portal API that lets applications monitor for updates, and request updating themselves.
Here is how this looks when it is all put together:
In the terminal, I’m building a new version of the the portal test app, and update my (local) repository. The flatpak portal is noticing that the update appeared (I’m running it with a short poll timeout here, instead of the usual 30 minutes), and sends out a D-Bus signal to the application, which requests to be updated, and then restarts itself.
Using the portal API directly is not very convenient, since you have to listen to D-Bus signals and whatnot. Therefore, we now have a library called libportal, which is providing simple async wrappers for most portals. That is what the portal test app in the demo is using, and you should be using it too in your applications.
The first stable release of libportal will appear very soon, with Flatpak 1.6, and then it will find its way into runtimes.
Update: Since this is a portal, users are in control of what apps are allowed to do. If you don’t want an application to update itself, you can put an end to it with
flatpak permission-set flatpak updates $APPID no
Use ‘ask’ instead of ‘no’ to get a confirmation dialog. The permission-set command is new in flatpak 1.6.
Flatpak development is not standing still. Here is a quick summary of recent and coming changes.
In 1.4.2, Flatpak gained the ability to use extra-data for extensions. This mechanism has been around for applications for a long time, but it is a new feature for extensions.
The 19.08 version of the freedesktop runtime uses it for its new org.freedesktop.Platform.openh264 extension, which uses the Cisco openh264 builds.
Since we are taking the ‘run everywhere’ aspect of Flatpak seriously, we’ve backported this feature from the 1.4 branch to older stable branches and released 1.2.4 and 1.0.9, so even users on very stable distributions can enjoy this new feature.
We’ve quietly started to work on Flatpak 1.6, which should be out before the end of the year.
On the roadmap for the this release, we have
Support for masking updates and pinning apps. This gives users more control about what updates Flatpak installs, without having to answer questions every time.
Parental controls. This optional feature uses libmalcontent to implement policies about what applications users can install and run, based on OARS content ratings.
Disk space checks. This is an ongoing effort to improve the accuracy of our disk- and download-size handling and to handle low disk space situations more gracefully.
Infrastructure for purchases/donations. This is still a bit of a research topic.
You can follow the discussion around these features, the flatpak roadmap and general flatpak topics on the flatpak mailing list.
Coming soon to portals
Things are happening on the portal side too. Some of these have already landed, and will appear in a release soon.
We have a secrets portal now. It works by providing a master secret to the sandboxed app, which is then used to store the applications secrets in an encrypted file inside the sandbox . The master secret is stored in the session keyring.
This is nice in that applications don’t leave their secrets behind in the keyring when they are uninstalled, and the application secrets are safe from others.
The backend for this portal will be provided by gnome-keyring and libsecret will automatically use it inside a sandbox. Backend implementations for other environments are more than welcome.
The secret portal is the work of Daiki Ueno, who gave a talk about it at Guadec.
The Flatpak commandline and tools like Discover or the Elementary app store do a fine job of handling updates for Flatpak apps and runtimes.
But the reality is that self-updating is a popular feature for applications, so we added an update portal that lets them do this in a clean way, with proper integration in the Flatpak machinery.
The background portal monitors applications that are running in the background (without open windows). It gives apps a way to request permission to run in the background, and it notifies users when apps are trying to do so sneakily without permission. The portal also lets applications request to be started automatically when the user logs in.
To implement this, the portal needs information from the compositor about open windows, and which applications they belong to. Currently, this is implemented for gnome-shell, other backends are more than welcome.
The screencast portal now lets you select individual windows, in addition to screens, if the application asks for this.
For now, the portal identifies windows by the application icon and window title. We are looking to improve this by using thumbnails.
We will add a small bit of desktop integration with a portal for setting desktop wallpapers.
A portal library
In the ideal case, portal functionality is used transparently by existing desktop libraries without the need for apps to do anything special. Examples for this are GtkFileChooserNative using the file chooser portal, or libsecret using the new secret portal.
But for some portals, there is no natural library api, and in these cases, doing the portal interaction with D-Bus calls can be a bit cumbersome.
Therefore, we are working on a libportal library that will provide GIO-style async apis for portal requests.
Open for contribution
If you want to get involved with Flatpak development, or are just curious, check out the flatpak project on github, chime in on the Flatpak mailing list, or find us on IRC in #flatpak on freenode.
In my last post discussing changes in Pango 1.44, I’ve asked for feedback. We’ve received some, thanks to everybody who reported issues!
We tried to address some of the fallout in several follow-up releases. I’ll do a 1.44.4 release with the last round of fixes before too long.
Here is a summary.
As expected, not supporting Type 1 and BDF fonts anymore is an unwelcome change for people whose favorite fonts are in these formats.
Clearly, a robust conversion script would be a very good thing to have; people have had mixed success with fontforge-based scripts (see this issue). I hope that we can get some help from the font packager community with this.
One follow-up fix that we did here is to make sure that Pango’s font enumeration code does not return fonts in formats that we don’t support. This makes font fallback work to replace bitmap fonts, and helps to avoid ‘black box’ output.
Font rendering is a sensitive topic; every change here is likely to upset some people (in particular those with carefully tuned font setups).
We did not help things by enabling subpixel positioning unconditionally in Pango, when it is only supported in cairo master. When used with the released cairo, this leads to unpleasantly uneven glyph placement. Even with cairo master, some compositors have not been updated to support subpixel positioning (e.g. win32, xcb).
To address this problem, subpixel positioning is now optional, and off by default. Use
Even without subpixel positioning, there is are still small differences in glyph positioning between Pango 1.43 and 1.44. These are caused by differences in glyph extent calculations between cairo and harfbuzz; see this issue for the ongoing discussion.
I was a bit overzealous in my attempt to reduce our dependency on freetype when I changed the return type of pango_fc_font_lock_face() to gpointer. This is a harmless change for the C API, but it broke some users of Pango in C++. The next release will have the old return type back.
Another new feature that turned out to be better of being off by default is the new line spacing. In the initial 1.44 release, it was on by default, causing line spacing UIs (e.g. in the GIMP) to stop working, which is not acceptable. It is now off by default. Call
pango_layout_set_line_spacing (layout, factor)
to enable it.
We’ve received one bug report pointing out that hyphens could be confusing in some contexts, for example when breaking filenames. As a consequence, there is now a text attribute to suppress the insertion of hyphens.
Naturally, some bugs crept in; there were some crash fixes, and some hyphens got inserted in the wrong place (such as: hyphens after hyphens, or hyphens after spaces). These were easy.
One bug that took me a while to track down was making lines grow higher when they are ellipsized, causing misrendering. It turned out to be a mixup with text attributes, that let us to pick the wrong font for the ellipsis character. This will be fixed in the next release.
There is a Pango 1.44 release now. It contains all the changes I outlined recently. We also managed to sneak in a few features and fixes for longstanding bugs. That is the topic of this post.
One area for improvements in this release is line breaking.
We don’t have TeX-style automatic hyphenation yet (although it may happen eventually). But at least, Pango inserts hyphens now when it breaks a line in the middle of a word (for example, at a soft hyphen character).
This is something i have wanted to do for a very long time, so I am quite happy that switching to harfbuzz for shaping on all platforms has finally enabled us to do this without too much effort.
Better line breaks
Pango follows Unicode UAX14 and UAX29 for finding word boundaries and line break opportunities. The algorithm described in there is language-independent, but allows for language-specific tweaks. The Unicode standard calls this tailoring.
While Pango has had implementations for both the language-independent and -dependent parts before, we didn’t have them clearly separated in the API, until now.
In the hyphenation example above, the words showing possible hyphenation points (like im‧peachment) are marked up in this way.
Another area with significant changes is placement, both of lines and of individual glyphs.
Up to now, Pango has been placing the lines of a paragraph directly below each other, possibly with a fixed amount of spacing between them. While this works ok most of the time, a more typographically correct way to go about this is to control the baseline-to-baseline distance between lines.
To make use of it, we added a new parameter to PangoLayout that tells it to place lines according to baseline-to-baseline distance. Once we had this, it was very easy to turn the parameter into a floating point number and allow things like double-spaced lines, by saying
pango_layout_set_line_spacing (layout, 2.0)
You can still use the old way of spacing if you set line-spacing to 0.
Pango no longer rounds glyph positions and font metrics to integral pixel numbers. This lets consumers of the formatted glyphs (basically, implementations of PangoRenderer) decide for themselves if they want to place glyphs at subpixel positions or pixel-aligned.
The cairo renderer in libpangocairo will do subpixel positioning, but you need cairo master for best results. GTK master will soon have the necessary changes to take advantage of it for its GL and Vulkan renderers too.
This is likely one of the more controversial changes in this release—any change to font rendering causes strong reactions. One of the reasons for doing the release now is that it gives us enough time to make sure it works ok for all users of Pango before going out in the next round of upstream and distro releases in the fall.
Finally, I spent some time implementing some long-requested features around missing glyphs, and their rendering as hex boxes. These are also known as tofu (which is the origin of the name for the Noto fonts – ‘no tofu’).
Some fonts don’t have a glyph for the space character – after all, there is nothing to draw. In the past, Pango would sometimes draw a hex box in this case. This is entirely unnecessary – we can just leave a gap of the right size and pretend that nothing happened. Pango 1.44 will do just that: no more hex boxes for space.
On the other hand, sometimes you do want to see where spaces and other whitespace characters such as tabs, are. We’ve added an attribute that lets you request visible rendering of whitespace:
<span show="spaces">Some space here</span>
This is implemented in the cairo backend, so you will need to use pangocairo to see it.
In the same vein, sometimes it is helpful to see special characters such as left-to-right controls in the output. Unicode calls these characters default-ignorable.
The show attribute also lets you make default-ignorables visible:
<span show=”ignorables”>Hidden treasures</span>
As you can see, we use nicknames for ignorables.
Pango has been shipping a simple tool called pango-list for a while. It produces a list of all the fonts Pango can find. This can be very helpful in tracking down changes between systems that are caused by differences in the available fonts.
In 1.44, pango-list can optionally show font metrics and variation axes as well. This may be a little obsure, but it has helped me fix the CI tests for Pango.
This release contains a significant amount of change; I’ve closed a good number of ‘teenage’ bugs while working on it. Please let us know if you see problems or unexpected changes with it!
After Behdad left, Christian and I turned our attention to GtkTextView, and made some progress.
GtkTextView is a very old widget. It started out as a port of the tk text widget, and it has not seen a lot of architectural updates over the years. A few years ago, we added a pixel cache to it, to improve its scrolling, but on a high resolution display, its still a lot of pixels to shovel around.
As we’ve moved widgets to GTK4’s rendering models, everybody avoided GtkTextView, so it was using the fallback cairo rendering path, even as we ported other text rendering in GTK to a new pango renderer which produces render nodes.
Until yesterday. We decided to just have a look at how hard it would be to switch the text view over to the new pango renderer. This went much more smoothly than we expected, and the new code is in master today.
So far, this is just a straight port with no optimizations (we want to look at smarter caching of render nodes for the visible range). But it is already noticeably smoother to scroll text.
The video does not really do it justice. If you want to try for yourself, the commit is here.
After this unexpected success, we looked for another small thing we could to make text editing in GTK feel more modern: better blinking cursors.
For the last 20 years, our cursor blinking was very simple: We turn it off, and then we turn it on again. With GTK4, it is very straightforward to do a little better, and fade the cursor in and out smoothly.
I have recently spent some time on Pango again, in preparation for the Westcoast hackfest. Behdad is here, and we’ve made great progress on the first day.
My last Pango update laid out our plans for Pango. Today I’ll summarize the major changes that will be in the next Pango release, 1.44.
I had a planned to replace PangoScript by GUnicodeScript outright, but doing so caused breakage in introspection and elsewhere. So, for now, we’ve just deprecated it and recommend that everybody should use GUnicodeScript instead. We did get a registered GType for this (and other) enumerations into GObject, so the lack of a type is no longer an obstacle.
We have added an api to get a Harfbuzz font object from a PangoFont:
hb_font_t *pango_font_get_hb_font (PangoFont *f)
This makes technologies such as OpenType features or variations available to applications without adding more Pango apis in the future.
Reduced freetype dependency
Pango uses harfbuzz for getting font and glyph metrics , glyph IDs and other kinds of font information now, so we don’t need an FT_Face anymore, and pango_fc_font_lock_face() has been deprecated.
We are using harfbuzz for shaping on all platforms now. This has allowed us to drop the remaining internal uses of shape and language engines.
Pango no longer forces glyph positions and sizes to be on integral pixel positions. This allows renderers to place glyphs on a subpixel grid. cairo master has the necessary changes to make this work.
GNOME applications (and others) are commonly using the GSettings API for storing their application settings.
GSettings has many nice aspects:
flexible data types, with GVariant
schemas, so others can understand your settings (e.,g. dconf-editor)
overrides, so distros can tweak defaults they don’t like
And it has different backends, so it can be adapted to work transparently in many situations. One example for where this comes in handy is when we use a memory backend to avoid persisting any settings while running tests.
The GSettings backend that is typically used for normal operation is the DConf one.
DConf features include profiles, a stack of databases, a facility for locking down keys so they are not writable, and a single-writer design with a central service.
The DConf design is flexible and enterprisey – we have taken advantage of this when we created fleet commander to centrally manage application and desktop settings for large deployments.
But it is not a great fit for sandboxing, where we want to isolate applications from each other and from the host system. In DConf, all settings are stored in a single database, and apps are free to read and write any keys, not just their own – plenty of potential for mischief and accidents.
Most of the apps that are available as flatpaks today are poking a ‘DConf hole’ into their sandbox to allow the GSettings code to keep talking to the dconf daemon on the session bus, and mmap the dconf database.
Here is how the DConf hole looks in the flatpak metadata file:
[Session Bus Policy]
Ideally, we want sandboxed apps to only have access to their own settings, and maybe readonly access to a limited set of shared settings (for things like the current font, or accessibility settings). It would also be nice if uninstalling a sandboxed app did not leave traces behind, like leftover settings in some central database.
It might be possible to retrofit some of this into DConf. But when we looked, it did not seem easy, and would require reconsidering some of the central aspects of the DConf design. Instead of going down that road, we decided to take advantage of another GSettings backend that already exists, and stores settings in a keyfile.
Unsurprisingly, it is called the keyfile backend.
The keyfile backend was originally created to facilitate the migration from GConf to GSettings, and has been a bit neglected, but we’ve given it some love and attention, and it can now function as the default GSettings backend inside sandboxes.
It provides many of the isolation aspects we want: Apps can only read and write their own settings, and the settings are in a single file, in the same place as all the application data:
One of the things we added to the keyfile backend is support for locks and overrides, so that fleet commander can keep working for apps that are in flatpaks.
For shared desktop-wide settings, there is a companion Settings portal, which provides readonly access to some global settings. It is used transparently by GTK and Qt for toolkit-level settings.
What does all this mean for flatpak apps?
If your application is not yet available as a flatpak, and you want to provide one, you don’t have to do anything in particular. Things will just work. Don’t poke a hole in your sandbox for DConf, and GSettings will use the keyfile backend without any extra work on your part.
If your flatpak is currently shipping with a DConf hole, you can keep doing that for now. When you are ready for it, you should
Remove the DConf hole from your flatpak metadata
Instruct flatpak to migrate existing DConf settings, by adding a migrate-path setting to the X-DConf section in your flatpak metadata. The value fo the migrate-path key is the DConf path prefix where your application’s settings are stored.
Note that this is a one-time migration; it will only happen if the keyfile does not exist. The existing settings will be left in the DConf database, so if you need to do the migration again for whatever reason, you can simply remove the the keyfile.
This is how the migrate-path key looks in the metadata file:
Closing the DConf hole is what makes GSettings use the keyfile backend, and the migrate-path key tells flatpak to migrate settings from DConf – you need both parts for a seamless transition.
There were some recent fixes to the keyfile backend code, so you want to make sure that the runtime has GLib 2.60.6, for best results.
Update: One of the most recent fixes in the keyfile backend was to correct under what circumstances GSettings will choose it as the default backend. If you have problems where the wrong backend is chosen, as a short-term workaround, you can override the choice with the GSETTINGS_BACKEND environment variable.
Update 2: To add the migrate-path setting with flatpak-builder, use the following option: