[prev in list] [next in list] [prev in thread] [next in thread] 

List:       freedesktop-fontconfig
Subject:    [Fontconfig] Revisiting FcFontMatch and FcFontSort
From:       Matthias Clasen <matthias.clasen () gmail ! com>
Date:       2021-02-23 5:21:48
Message-ID: CAFwd_vBvR1i_BhsTefgZ_pJvPQxTWrc0J_t7kQK77cJurW1AbA () mail ! gmail ! com
[Download RAW message or body]

[Attachment #2 (multipart/alternative)]


Hey,

Behdad and I have a longstanding discussion about better apis for font
enumeration.

Looking at https://gitlab.gnome.org/GNOME/pango/-/issues/53, it appears to
go back
as far as 2006. I've revisited fontconfig performance last summer. Some of
the results
from that work are mentioned in the last comments in that Pango issue.

To summarize the performance problem:

- Sorting all the system fonts is too expensive to it multiple times per
paragraph, when
  the goal is to render text at 60fps. As a datapoint, after installing all
the Noto fonts, my
  system has ~4000 fonts, and even after the aforementioned performance
fixes, a
  single FcFontSort call averages 7ms - half of a frame.

- Most of the sorting work is wasted, since we only access the first few
members of
  the returned list (in the vast majority of cases, Pango only ever uses
the first one or
  two members of the sorted list).

- In the case where we do access more than the first few members, the exact
order
  of fonts in 'the long tail' hardly matters - all of these are fonts that
have little relation
  to the pattern we are interested in, and we might just as well have a
generic fallback.

Our thoughts on improving this generally revolve around doing less work up
front.
Basically, switch to an incremental sorting approach, where Pango can ask
for the
"next best" font, one at a time.

As very rough api sketch could be something like this:

/* Create a sorted fontset that is sorted by matching against p */
FcSortedFontSet *FcSortedFontSetCreate (FcFontSet *s, FcPattern *p);

/* Return the n-th element of the sorted fontset s */
FcPattern *FcSortedFontSetGet (FcSortedFontSet *s, int n);

With this api, FcFontSetMatch could be implemented like this:

FcPattern *
FcFontSetMatch (FcFontSet *s, FcPattern *p)
{
  FcSortedFontSet *sorted;
  sorted = FcSortedFontSetCreate (s, p);
  match = FcSortedFontSet (sorted, 0);
  FcSortedFontSetDestroy (sorted);
  return match;
}

-----------------

In a recent call, Behdad pointed out a related, but distinct issue with the
current
pipeline approach to font rendering, as implemented in pango:

First, pick fonts for all characters ("itemize")
Second, select glyphs for the resulting runs ("Shape")

The first step is where we use fontconfig to find candidate fonts, and then
we
check their coverage for each character to make a choice. fontconfig
currently uses
freetype to determine coverage information for fonts.

But what characters are reasonably 'covered' by font very much depends on
what use
the second step makes of the font. The harfbuzz shaper can decompose and
compose
glyphs and thereby extend coverage in ways that freetype has no idea about.

There are different ways in which this could be improved. One would be to
give up
on the approach of making all font selection choices up-front, and instead
use a recursive
approach in which the shaper can ask for more fonts if it can make do with
the ones it
was given initially.

Another, maybe simpler approach would be to make fontconfig use harfbuzz
instead
of freetype for finding font coverage.

Matthias

[Attachment #5 (text/html)]

<div dir="ltr"><div>Hey,<br></div><div><br></div><div>Behdad and I have a \
longstanding discussion about better apis for font \
enumeration.</div><div><br></div><div>Looking at <a \
href="https://gitlab.gnome.org/GNOME/pango/-/issues/53">https://gitlab.gnome.org/GNOME/pango/-/issues/53</a>, \
it appears to go back</div><div>as far as 2006. I&#39;ve revisited fontconfig \
performance last summer. Some of the results</div><div>from that work are mentioned \
in the last comments in that Pango issue.</div><div><br></div><div>To summarize the \
performance problem:</div><div><br></div><div>- Sorting all the system fonts is too \
expensive to it multiple times per paragraph, when</div><div>   the goal is to render \
text at 60fps. As a datapoint, after installing all the Noto fonts, my</div><div>   \
system has ~4000 fonts, and even after the aforementioned performance fixes, \
a</div><div>   single FcFontSort call averages 7ms - half of a \
frame.<br></div><div><br></div><div>- Most of the sorting work is wasted, since we \
only access the first few members of</div><div>   the returned list (in the vast \
majority of cases, Pango only ever uses the first one or</div><div>   two members of \
the sorted list).<br></div><div><br></div><div>- In the case where we do access more \
than the first few members, the exact order</div><div>   of fonts in &#39;the long \
tail&#39; hardly matters - all of these are fonts that have little \
relation</div><div>   to the pattern we are interested in, and we might just as well \
have a generic fallback.</div><div><br></div><div>Our thoughts on improving this \
generally revolve around doing less work up front.</div><div>Basically, switch to an \
incremental sorting approach, where Pango can ask for the</div><div>&quot;next \
best&quot; font, one at a time. <br></div><div><br></div><div>As very rough api \
sketch could be something like this:</div><div><br></div><div>/* Create a sorted \
fontset that is sorted by matching against p */<br></div><div>FcSortedFontSet \
*FcSortedFontSetCreate (FcFontSet *s, FcPattern *p);<br></div><div><br></div><div>/* \
Return the n-th element of the sorted fontset s */<br></div><div>FcPattern \
*FcSortedFontSetGet (FcSortedFontSet *s, int n);<br></div><div><br></div><div>With \
this api, FcFontSetMatch could be implemented like \
this:<br></div><div><br></div><div>FcPattern *</div><div>FcFontSetMatch (FcFontSet \
*s, FcPattern *p)</div><div>{</div><div>   FcSortedFontSet *sorted;</div><div>   \
sorted = FcSortedFontSetCreate (s, p); <br></div><div>   match = FcSortedFontSet \
(sorted, 0);<br></div><div>   FcSortedFontSetDestroy (sorted);</div><div>   return \
match;<br></div><div>}</div><div><br></div><div>-----------------<br></div><div><br></div><div>In \
a recent call, Behdad pointed out a related, but distinct issue with the \
current</div><div>pipeline approach to font rendering, as implemented in \
pango:<br></div><div><br></div><div>First, pick fonts for all characters \
(&quot;itemize&quot;)</div><div>Second, select glyphs for the resulting runs \
(&quot;Shape&quot;)<br></div><div><br></div><div>The first step is where we use \
fontconfig to find candidate fonts, and then we</div><div>check their coverage for \
each character to make a choice. fontconfig currently uses</div><div>freetype to \
determine coverage information for fonts.<br></div><div><br></div><div>But what \
characters are reasonably &#39;covered&#39; by font very much depends on what use \
<br></div><div>the second step makes of the font. The harfbuzz shaper can decompose \
and compose</div><div>glyphs and thereby extend coverage in ways that freetype has no \
idea about.</div><div><br></div><div>There are different ways in which this could be \
improved. One would be to give up <br></div><div>on the approach of making all font \
selection choices up-front, and instead use a recursive</div><div>approach in which \
the shaper can ask for more fonts if it can make do with the ones it</div><div>was \
given initially.</div><div><br></div><div>Another, maybe simpler approach would be to \
make fontconfig use harfbuzz instead</div><div>of freetype for finding font \
coverage.</div><div><br></div><div>Matthias<br></div></div>



_______________________________________________
Fontconfig mailing list
Fontconfig@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/fontconfig


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic