| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467 |
- <?xml version="1.0"?>
- <!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
- "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
- <!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
- <!ENTITY version SYSTEM "version.xml">
- ]>
- <chapter id="fonts-and-faces">
- <title>Fonts, faces, and output</title>
- <para>
- In the previous chapter, we saw how to set up a buffer and fill
- it with text as Unicode code points. In order to shape this
- buffer text with HarfBuzz, you will need also need a font
- object.
- </para>
- <para>
- HarfBuzz provides abstractions to help you cache and reuse the
- heavier parts of working with binary fonts, so we will look at
- how to do that. We will also look at how to work with the
- FreeType font-rendering library and at how you can customize
- HarfBuzz to work with other libraries.
- </para>
- <para>
- Finally, we will look at how to work with OpenType variable
- fonts, the latest update to the OpenType font format, and at
- some other recent additions to OpenType.
- </para>
- <section id="fonts-and-faces-objects">
- <title>Font and face objects</title>
- <para>
- The outcome of shaping a run of text depends on the contents of
- a specific font file (such as the substitutions and positioning
- moves in the 'GSUB' and 'GPOS' tables), so HarfBuzz makes
- accessing those internals fast.
- </para>
- <para>
- An <type>hb_face_t</type> represents a <emphasis>face</emphasis>
- in HarfBuzz. This data type is a wrapper around an
- <type>hb_blob_t</type> blob that holds the contents of a binary
- font file. Since HarfBuzz supports TrueType Collections and
- OpenType Collections (each of which can include multiple
- typefaces), a HarfBuzz face also requires an index number
- specifying which typeface in the file you want to use. Most of
- the font files you will encounter in the wild include just a
- single face, however, so most of the time you would pass in
- <literal>0</literal> as the index when you create a face:
- </para>
- <programlisting language="C">
- hb_blob_t* blob = hb_blob_create_from_file(file);
- ...
- hb_face_t* face = hb_face_create(blob, 0);
- </programlisting>
- <para>
- On its own, a face object is not quite ready to use for
- shaping. The typeface must be set to a specific point size in
- order for some details (such as hinting) to work. In addition,
- if the font file in question is an OpenType Variable Font, then
- you may need to specify one or variation-axis settings (or a
- named instance) in order to get the output you need.
- </para>
- <para>
- In HarfBuzz, you do this by creating a <emphasis>font</emphasis>
- object from your face.
- </para>
- <para>
- Font objects also have the advantage of being considerably
- lighter-weight than face objects (remember that a face contains
- the contents of a binary font file mapped into memory). As a
- result, you can cache and reuse a font object, but you could
- also create a new one for each additional size you needed.
- Creating new fonts incurs some additional overhead, of course,
- but whether or not it is excessive is your call in the end. In
- contrast, face objects are substantially larger, and you really
- should cache them and reuse them whenever possible.
- </para>
- <para>
- You can create a font object from a face object:
- </para>
- <programlisting language="C">
- hb_font_t* hb_font = hb_font_create(hb_face);
- </programlisting>
- <para>
- After creating a font, there are a few properties you should
- set. Many fonts enable and disable hints based on the size it
- is used at, so setting this is important for font
- objects. <function>hb_font_set_ppem(font, x_ppem,
- y_ppem)</function> sets the pixels-per-EM value of the font. You
- can also set the point size of the font with
- <function>hb_font_set_ptem(font, ptem)</function>. HarfBuzz uses the
- industry standard 72 points per inch.
- </para>
- <para>
- HarfBuzz lets you specify the degree subpixel precision you want
- through a scaling factor. You can set horizontal and
- vertical scaling factors on the
- font by calling <function>hb_font_set_scale(font, x_scale,
- y_scale)</function>.
- </para>
- <para>
- There may be times when you are handed a font object and need to
- access the face object that it comes from. For that, you can call
- </para>
- <programlisting language="C">
- hb_face = hb_font_get_face(hb_font);
- </programlisting>
- <para>
- You can also create a font object from an existing font object
- using the <function>hb_font_create_sub_font()</function>
- function. This creates a child font object that is initiated
- with the same attributes as its parent; it can be used to
- quickly set up a new font for the purpose of overriding a specific
- font-functions method.
- </para>
- <para>
- All face objects and font objects are lifecycle-managed by
- HarfBuzz. After creating a face, you increase its reference
- count with <function>hb_face_reference(face)</function> and
- decrease it with
- <function>hb_face_destroy(face)</function>. Likewise, you
- increase the reference count on a font with
- <function>hb_font_reference(font)</function> and decrease it
- with <function>hb_font_destroy(font)</function>.
- </para>
- <para>
- You can also attach user data to face objects and font objects.
- </para>
- </section>
- <section id="fonts-and-faces-custom-functions">
- <title>Customizing font functions</title>
- <para>
- During shaping, HarfBuzz frequently needs to query font objects
- to get at the contents and parameters of the glyphs in a font
- file. It includes a built-in set of functions that is tailored
- to working with OpenType fonts. However, as was the case with
- Unicode functions in the buffers chapter, HarfBuzz also wants to
- make it easy for you to assign a substitute set of font
- functions if you are developing a program to work with a library
- or platform that provides its own font functions.
- </para>
- <para>
- Therefore, the HarfBuzz API defines a set of virtual
- methods for accessing font-object properties, and you can
- replace the defaults with your own selections without
- interfering with the shaping process. Each font object in
- HarfBuzz includes a structure called
- <literal>font_funcs</literal> that serves as a vtable for the
- font object. The virtual methods in
- <literal>font_funcs</literal> are:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- <function>hb_font_get_font_h_extents_func_t</function>: returns
- the extents of the font for horizontal text.
- </para>
- </listitem>
- <listitem>
- <para>
- <function>hb_font_get_font_v_extents_func_t</function>: returns
- the extents of the font for vertical text.
- </para>
- </listitem>
- <listitem>
- <para>
- <function>hb_font_get_nominal_glyph_func_t</function>: returns
- the font's nominal glyph for a given code point.
- </para>
- </listitem>
- <listitem>
- <para>
- <function>hb_font_get_variation_glyph_func_t</function>: returns
- the font's glyph for a given code point when it is followed by a
- given Variation Selector.
- </para>
- </listitem>
- <listitem>
- <para>
- <function>hb_font_get_nominal_glyphs_func_t</function>: returns
- the font's nominal glyphs for a series of code points.
- </para>
- </listitem>
- <listitem>
- <para>
- <function>hb_font_get_glyph_advance_func_t</function>: returns
- the advance for a glyph.
- </para>
- </listitem>
- <listitem>
- <para>
- <function>hb_font_get_glyph_h_advance_func_t</function>: returns
- the advance for a glyph for horizontal text.
- </para>
- </listitem>
- <listitem>
- <para>
- <function>hb_font_get_glyph_v_advance_func_t</function>:returns
- the advance for a glyph for vertical text.
- </para>
- </listitem>
- <listitem>
- <para>
- <function>hb_font_get_glyph_advances_func_t</function>: returns
- the advances for a series of glyphs.
- </para>
- </listitem>
- <listitem>
- <para>
- <function>hb_font_get_glyph_h_advances_func_t</function>: returns
- the advances for a series of glyphs for horizontal text .
- </para>
- </listitem>
- <listitem>
- <para>
- <function>hb_font_get_glyph_v_advances_func_t</function>: returns
- the advances for a series of glyphs for vertical text.
- </para>
- </listitem>
- <listitem>
- <para>
- <function>hb_font_get_glyph_origin_func_t</function>: returns
- the origin coordinates of a glyph.
- </para>
- </listitem>
- <listitem>
- <para>
- <function>hb_font_get_glyph_h_origin_func_t</function>: returns
- the origin coordinates of a glyph for horizontal text.
- </para>
- </listitem>
- <listitem>
- <para>
- <function>hb_font_get_glyph_v_origin_func_t</function>: returns
- the origin coordinates of a glyph for vertical text.
- </para>
- </listitem>
- <listitem>
- <para>
- <function>hb_font_get_glyph_extents_func_t</function>: returns
- the extents for a glyph.
- </para>
- </listitem>
- <listitem>
- <para>
- <function>hb_font_get_glyph_contour_point_func_t</function>:
- returns the coordinates of a specific contour point from a glyph.
- </para>
- </listitem>
- <listitem>
- <para>
- <function>hb_font_get_glyph_name_func_t</function>: returns the
- name of a glyph (from its glyph index).
- </para>
- </listitem>
- <listitem>
- <para>
- <function>hb_font_get_glyph_from_name_func_t</function>: returns
- the glyph index that corresponds to a given glyph name.
- </para>
- </listitem>
- </itemizedlist>
- <para>
- You can create new font-functions by calling
- <function>hb_font_funcs_create()</function>:
- </para>
- <programlisting language="C">
- hb_font_funcs_t *ffunctions = hb_font_funcs_create ();
- hb_font_set_funcs (font, ffunctions, font_data, destroy);
- </programlisting>
- <para>
- The individual methods can each be set with their own setter
- function, such as
- <function>hb_font_funcs_set_nominal_glyph_func(ffunctions,
- func, user_data, destroy)</function>.
- </para>
- <para>
- Font-functions structures can be reused for multiple font
- objects, and can be reference counted with
- <function>hb_font_funcs_reference()</function> and
- <function>hb_font_funcs_destroy()</function>. Just like other
- objects in HarfBuzz, you can set user-data for each
- font-functions structure and assign a destroy callback for
- it.
- </para>
- <para>
- You can also mark a font-functions structure as immutable,
- with <function>hb_font_funcs_make_immutable()</function>. This
- is especially useful if your code is a library or framework that
- will have its own client programs. By marking your
- font-functions structures as immutable, you prevent your client
- programs from changing the configuration and introducing
- inconsistencies and errors downstream.
- </para>
- <para>
- To override only some functions while using the default implementation
- for the others, you will need to create a sub-font. By default, the
- sub-font uses the font functions of its parent except for the functions
- that were explicitly set. The following code will override only the
- <function>hb_font_get_nominal_glyph_func_t</function> for the sub-font:
- </para>
- <programlisting language="C">
- hb_font_t *subfont = hb_font_create_sub_font (font)
- hb_font_funcs_t *ffunctions = hb_font_funcs_create ();
- hb_font_funcs_set_nominal_glyph_func (ffunctions, func, user_data, destroy);
- hb_font_set_funcs (subfont, ffunctions, font_data, destroy);
- hb_font_funcs_destroy (ffunctions);
- </programlisting>
- </section>
- <section id="fonts-and-faces-native-opentype">
- <title>Font objects and HarfBuzz's native OpenType implementation</title>
- <para>
- By default, whenever HarfBuzz creates a font object, it will
- configure the font to use a built-in set of font functions that
- supports contemporary OpenType font internals. If you want to
- work with OpenType or TrueType fonts, you should be able to use
- these functions without difficulty.
- </para>
- <para>
- Many of the methods in the font-functions structure deal with
- the fundamental properties of glyphs that are required for
- shaping text: extents (the maximums and minimums on each axis),
- origins (the <literal>(0,0)</literal> coordinate point which
- glyphs are drawn in reference to), and advances (the amount that
- the cursor needs to be moved after drawing each glyph, including
- any empty space for the glyph's side bearings).
- </para>
- <para>
- As you can see in the list of functions, there are separate "horizontal"
- and "vertical" variants depending on whether the text is set in
- the horizontal or vertical direction. For some scripts, fonts
- that are designed to support text set horizontally or vertically (for
- example, in Japanese) may include metrics for both text
- directions. When fonts don't include this information, HarfBuzz
- does its best to transform what the font provides.
- </para>
- <para>
- In addition to the direction-specific functions, HarfBuzz
- provides some higher-level functions for fetching information
- like extents and advances for a glyph. If you call
- </para>
- <programlisting language="C">
- hb_font_get_glyph_advance_for_direction(font, direction, extents);
- </programlisting>
- <para>
- then you can provide any <type>hb_direction_t</type> as the
- <parameter>direction</parameter> parameter, and HarfBuzz will
- use the correct function variant for the text direction. There
- are similar higher-level versions of the functions for fetching
- extents, origin coordinates, and contour-point
- coordinates. There are also addition and subtraction functions
- for moving points with respect to the origin.
- </para>
- <para>
- There are also methods for fetching the glyph ID that
- corresponds to a Unicode code point (possibly when followed by a
- variation-selector code point), fetching the glyph name from the
- font, and fetching the glyph ID that corresponds to a glyph name
- you already have.
- </para>
- <para>
- HarfBuzz also provides functions for converting between glyph
- names and string
- variables. <function>hb_font_glyph_to_string(font, glyph, s,
- size)</function> retrieves the name for the glyph ID
- <parameter>glyph</parameter> from the font object. It generates a
- generic name of the form <literal>gidDDD</literal> (where DDD is
- the glyph index) if there is no name for the glyph in the
- font. The <function>hb_font_glyph_from_string(font, s, len,
- glyph)</function> takes an input string <parameter>s</parameter>
- and looks for a glyph with that name in the font, returning its
- glyph ID in the <parameter>glyph</parameter>
- output parameter. It automatically parses
- <literal>gidDDD</literal> and <literal>uniUUUU</literal> strings.
- </para>
- </section>
- <!-- Commenting out FreeType integration section-holder for now. May move
- to the full-blown Integration Chapter. -->
-
- <!-- <section id="fonts-and-faces-freetype">
- <title>Using FreeType</title>
- <para>
- </para>
- <para>
-
- </para>
- </section> -->
- <section id="fonts-and-faces-variable">
- <title>Working with OpenType Variable Fonts</title>
- <para>
- If you are working with OpenType Variable Fonts, there are a few
- additional functions you should use to specify the
- variation-axis settings of your font object. Without doing so,
- your variable font's font object can still be used, but only at
- the default setting for every axis (which, of course, is
- sometimes what you want, but does not cover general usage).
- </para>
- <para>
- HarfBuzz manages variation settings in the
- <type>hb_variation_t</type> data type, which holds a <property>tag</property> for the
- variation-axis identifier tag and a <property>value</property> for its
- setting. You can retrieve the list of variation axes in a font
- binary from the face object (not from a font object, notably) by
- calling <function>hb_ot_var_get_axis_count(face)</function> to
- find the number of axes, then using
- <function>hb_ot_var_get_axis_infos()</function> to collect the
- axis structures:
- </para>
- <programlisting language="C">
- axes = hb_ot_var_get_axis_count(face);
- ...
- hb_ot_var_get_axis_infos(face, 0, axes, axes_array);
- </programlisting>
- <para>
- For each axis returned in the array, you can can access the
- identifier in its <property>tag</property>. HarfBuzz also has
- tag definitions predefined for the five standard axes specified
- in OpenType (<literal>ital</literal> for italic,
- <literal>opsz</literal> for optical size,
- <literal>slnt</literal> for slant, <literal>wdth</literal> for
- width, and <literal>wght</literal> for weight). Each axis also
- has a <property>min_value</property>, a
- <property>default_value</property>, and a <property>max_value</property>.
- </para>
- <para>
- To set your font object's variation settings, you call the
- <function>hb_font_set_variations()</function> function with an
- array of <type>hb_variation_t</type> variation settings. Let's
- say our font has weight and width axes. We need to specify each
- of the axes by tag and assign a value on the axis:
- </para>
- <programlisting language="C">
- unsigned int variation_count = 2;
- hb_variation_t variation_data[variation_count];
- variation_data[0].tag = HB_OT_TAG_VAR_AXIS_WIDTH;
- variation_data[1].tag = HB_OT_TAG_VAR_AXIS_WEIGHT;
- variation_data[0].value = 80;
- variation_data[1].value = 750;
- ...
- hb_font_set_variations(font, variation_data, variation_count);
- </programlisting>
- <para>
- That should give us a slightly condensed font ("normal" on the
- <literal>wdth</literal> axis is 100) at a noticeably bolder
- weight ("regular" is 400 on the <literal>wght</literal> axis).
- </para>
- <para>
- In practice, though, you should always check that the value you
- want to set on the axis is within the
- [<property>min_value</property>,<property>max_value</property>]
- range actually implemented in the font's variation axis. After
- all, a font might only provide lighter-than-regular weights, and
- setting a heavier value on the <literal>wght</literal> axis will
- not change that.
- </para>
- <para>
- Once your variation settings are specified on your font object,
- however, shaping with a variable font is just like shaping a
- static font.
- </para>
- </section>
- </chapter>
|