Shared fontconfig cache prototype

In order to make font handling a bit more robust, I put together a prototype of how we could build and share a Fontconfig cache that is known to be compatible with a particular GNOME platform snap:

Cache provider

I’ve built this as an independent snap, but could probably be built into the platform snap directly. In essence, it does the following:

  1. include a private fonts.conf file in the snap that searches for fonts in /usr/share/fonts and /usr/local/share/fonts, and sets the cache dir to a location under $SNAP_COMMON (hard coded as a /var/snap/... path).
  2. include a script that calls fc-cache -s using the binary and libraries from the platform snap.
  3. Create a content interface slot to export the generated cache:
    slots:
      fontconfig-cache-gnome-3-34-1804:
        interface: content
        read:
          - $SNAP_COMMON/cache/fontconfig
    
  4. symlink the cache generation script to act as a configure hook and prepare-slot hook for the above slot.

The intent of the hooks is to try and ensure the cache is up to date with the fonts on the host system by refreshing it whenever the snap is updated or another snap tries to connect to the cache slot. We could probably also add install a systemd timer to regularly rebuild the cache on top of this, if needed.

And since the cache was built using the fontconfig and freetype libraries from the gnome-3-34-1804 snap, we know that it will be compatible with those libraries in the applications.

Use by applications

Other snaps can then access the cache using a matching plug:

plugs:
  fontconfig-cache-gnome-3-34-1804:
    interface: content
    target: $SNAP_COMMON/cache/fontconfig
    default-provider: fontconfig-cache-prototype

Ideally, we’d have the plug mount the cache directly to /var/cache/fontconfig so the default fontconfig configuration will use it by default. However the content interface does not allow that. I tried working around this using layouts without success:

  1. If I use layouts to mount $SNAP_COMMON/cache /fontconfig -> /var/cache/fontconfig, this mount is performed before the content interface mount, leaving me with an empty directory.
  2. the desktop interface tries to mount the host system /var/cache/fontconfig to this location. One of these loses and tries to mount to /var/cache/fontconfig-2, which in turn fails due to AppArmor restrictions.

For (1), I wonder if it would make sense to adjust the content interface to allow mounting to any location we allow layouts to bind mount to? If we’re only doing a single bind mount, then the ordering issue goes away.

For (2), the desktop interface currently includes a quirk to skip the /var/cache/fontconfig mount on Fedora and Arch, where we’ve encountered cache incompatibilities in the past. Maybe it would make sense to extend this into a expose-font-cache plug attribute so snaps can opt out of that mount on all systems?

If we can get around these issues, this all looks like logic that could be folded into the existing Snapcraft extensions once we update the corresponding platform snaps to build and share a compatible cache.

6 Likes