Dynamically link against system fontconfig (#701)

Statically linking the fontconfig library into the flutter app can cause
(runtime) performance issues on systems where the statically linked
fontconfig is using a different [on-disk cache format
version](https://gitlab.freedesktop.org/fontconfig/fontconfig/-/blob/c2666a6d9a6ed18b1bfcef8176e25f62993e24db/fontconfig/fontconfig.h#L60-70)
from the system fontconfig version. This is particularly relevant on
systems with a large number of fonts installed:
https://github.com/flutter/flutter/issues/118911.

This pull-request fixes that by replacing the statically linked
fontconfig version with dynamic linking to the system version. For what
it's worth, by default Skia is also [dynamically linking against system
fontconfig](https://github.com/google/skia/blob/398b9ac94aa3f49e0fdab319a27584c2a2e3e63e/third_party/BUILD.gn#L10).

**Warning**: This requires a similar change to the Flutter engine
(https://github.com/flutter/engine/pull/40725).

### Underlying root issue

On a typical Linux desktop distribution[^1], the package manager
automatically updates the *system* fontconfig cache (e.g.:
`/var/cache/fontconfig`) when *system* fonts are installed.

This means that applications using a version of fontconfig with *the
same on-disk cache format as the system fontconfig* should be able to
use the system cache (and therefore have reasonably fast font
discovery).

However, when the application and system fontconfig versions do not
match, the app is unable to use the system font cache so it has to
re-index all the system fonts (which is a significantly slower
operation).

In addition to that, in an attempt to speed-up subsequent launches of
the app, the fontconfig library persists the system font cache to disk
on application startup. Since user-space apps typically do *not* have
write access to the *system* font cache directory (e.g.:
`/var/cache/fontconfig`), the fontconfig library ends up writing the
cache to the *user* fontconfig cache (e.g.: `~/.cache/fontconfig`) which
ends up slowing the application startup even futher (due to the extra
IO).

This part is a bit unclear as to *why* it happens, but it turns out
fontconfig does not attempt to read the *user* cache on the next app
startup. So the whole process starts over again on every app launch:
*system* font cache not found => fonts re-indexed => font cache written
to *user* cache (which is never to be read again).

### Benchmarks

> **Note**
> 
> These tests were performed on an ArchLinux system with approximately
6000 system fonts installed
([ttf-google-fonts-git](https://aur.archlinux.org/packages/ttf-google-fonts-git))
using version `2.14.2` of fontconfig (`FC_CACHE_VERSION: 8`).

The following graph shows the startup times (time to first frame as
reported by `flutter run --profile`) for ten consecutive runs using
statically linked fontconfig versus dynamically linked fontconfig. The
average startup time for statically linked fontconfig was 2186 ms versus
368 ms for dynamically linked.


![chart](https://user-images.githubusercontent.com/433598/228365920-1f90eddb-683e-46d3-9aec-4df22fa222db.png)

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read the [Flutter Style Guide] _recently_, and have followed its
advice.
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [ ] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/wiki/Tree-hygiene#overview
[Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene
[test-exempt]:
https://github.com/flutter/flutter/wiki/Tree-hygiene#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes
[Discord]: https://github.com/flutter/flutter/wiki/Chat
[^1]: This has only been tested on ArchLinux but I would expect other
Linux distributions to work in a similar way.
1 file changed
tree: 54e4d7877f51570c03fe4babf4a60baa5688b5f3
  1. .github/
  2. build/
  3. build_overrides/
  4. gpu/
  5. tools/
  6. .clang-format
  7. .gitattributes
  8. .gitignore
  9. .gn
  10. .ycm_extra_conf.py
  11. AUTHORS
  12. BUILD.gn
  13. CODEOWNERS
  14. LICENSE
  15. README.md
README.md

OpenSSF Scorecard

buildroot

Build environment for the Flutter engine

This repository is used by the flutter/engine repository. For instructions on how to use it, see that repository's CONTRIBUTING.md file.

To update your checkout to use the latest buildroot, run gclient sync.

To submit patches to this buildroot repository, create a branch, push to that branch, then submit a PR on GitHub for that branch.

To point the engine to a new version of buildroot after your patch is merged, update the buildroot hash in the engine's DEPS file.