[Fontconfig] Bitmap font resizing

Behdad Esfahbod behdad at behdad.org
Fri Dec 21 17:24:30 PST 2012


Hi everyone,

Say, you ask pango to render some text at 150pt at 96dpi.  That corresponds to
a pixelsize of 200.  Pango creates an FcPattern and puts 200 in the "size"
element of the pattern, populates the "dpi" element, and calls into fontconfig.

Normally, fontconfig then computes "pixelsize" from "size" and "dpi", finds a
font, copies the "pixelsize" over to the match pattern and returns it.  pango
then passes the match pattern to cairo, which would then render the font at
"pixelsize", which is 200 by this time.

Now, for bitmap-only fonts, what happens is a bit different: fontconfig
chooses the strike that is closest to the requested size, and because the
original font pattern has its "pixelsize" set to the strike size, the
"pixelsize" from the query pattern is NOT copied over.  As such, the match
pattern has the font from the bitmap strike.  Which, may be 20px, even though
you requested a font at 200px!

Note that by this time, the original pixel size request is completely lost.
There's no way to make the subsequent stages (cairo) scale bitmaps since the
desired size is lost.

Now, even if we fixed this, cairo was NOT doing the necessary scaling.  I
already fixed that earlier today.  However, for that to work, we need to fix
this glitch in fontconfig.  One way top do it is simply to recalculate
pixelsize in a config snippet.  This is working for me now:

<match target="font">
  <test name="scalable" mode="eq">
    <bool>false</bool>
  </test>
  <edit name="pixelsize" mode="assign">
    <divide>
      <times><name>size</name><name>dpi</name></times>
      <double>72</double>
    </divide>
  </edit>
</match>

This *may* break simpler clients that directly pass the resulting pixelsize to
FreeType instead of doing their own bitmap strike size matching.

Ideally I would have wanted to fix it by adjusting the "matrix" element.  But
unfortunately fontconfig doesn't really allow that right now.  The "matrix"
element can only be constructed from actual double literals.  This is what
ideally would do the job:

<match target="font">
  <test name="scalable" mode="eq">
    <bool>false</bool>
  </test>
  <edit name="pixelsizefixupfactor" mode="assign">
    <divide>
      <divide>
        <times><name>size</name><name>dpi</name></times>
        <double>72</double>
      </divide>
      <name>pixelsize</name>
    </divide>
  </edit>
  <edit name="matrix" mode="assign">
    <times>
      <name>matrix</name>
      <matrix>
        <name>pixelsizefixupfactor</name> <double>0</double>
        <double>0</double> <name>pixelsizefixupfactor</name>
       </matrix>
    </times>
  </edit>
  <edit name="size" mode="assign">
    <divide>
      <name>size</name>
      <name>pixelsizefixupfactor</name>
    </divide>
  </edit>
</match>


With this and the cairo change, I get full bitmap scaling working.

The config can be a bit smarter.  For example, if metricshinting is enabled
and the size difference is small, we may as well not scale.

The nice thing about this is that the configuration of whether and when to
scale bitmaps will be done in fontconfig, not cairo / Qt / ... code.

Thoughts?  Should we enable this by default?

Cheers,
-- 
behdad
http://behdad.org/


More information about the Fontconfig mailing list