Nathan Willis | 2da567e | 2019-05-24 11:13:53 +0100 | [diff] [blame] | 1 | <?xml version="1.0"?> |
| 2 | <!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN" |
| 3 | "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [ |
| 4 | <!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'"> |
| 5 | <!ENTITY version SYSTEM "version.xml"> |
| 6 | ]> |
| 7 | <chapter id="integration"> |
| 8 | <title>Platform Integration Guide</title> |
| 9 | <para> |
| 10 | HarfBuzz was first developed for use with the GNOME and GTK |
| 11 | software stack commonly found in desktop Linux |
| 12 | distributions. Nevertheless, it can be used on other operating |
| 13 | systems and platforms, from iOS and macOS to Windows. It can also |
| 14 | be used with other application frameworks and components, such as |
| 15 | Android, Qt, or application-specific widget libraries. |
| 16 | </para> |
| 17 | <para> |
| 18 | This chapter will look at how HarfBuzz fits into a typical |
| 19 | text-rendering pipeline, and will discuss the APIs available to |
| 20 | integrate HarfBuzz with contemporary Linux, Mac, and Windows |
| 21 | software. It will also show how HarfBuzz integrates with popular |
Nathan Willis | dd1c765 | 2019-05-24 14:30:15 +0100 | [diff] [blame] | 22 | external libraries like FreeType and International Components for |
Nathan Willis | 2da567e | 2019-05-24 11:13:53 +0100 | [diff] [blame] | 23 | Unicode (ICU) and describe the HarfBuzz language bindings for |
| 24 | Python. |
| 25 | </para> |
| 26 | <para> |
| 27 | On a GNOME system, HarfBuzz is designed to tie in with several |
| 28 | other common system libraries. The most common architecture uses |
| 29 | Pango at the layer directly "above" HarfBuzz; Pango is responsible |
| 30 | for text segmentation and for ensuring that each input |
| 31 | <type>hb_buffer_t</type> passed to HarfBuzz for shaping contains |
| 32 | Unicode code points that share the same segment properties |
| 33 | (namely, direction, language, and script, but also higher-level |
n8willis | a29578c | 2020-04-13 15:30:18 +0100 | [diff] [blame] | 34 | properties like the active font, font style, and so on). |
Nathan Willis | 2da567e | 2019-05-24 11:13:53 +0100 | [diff] [blame] | 35 | </para> |
| 36 | <para> |
| 37 | The layer directly "below" HarfBuzz is typically FreeType, which |
| 38 | is used to rasterize glyph outlines at the necessary optical size, |
| 39 | hinting settings, and pixel resolution. FreeType provides APIs for |
| 40 | accessing font and face information, so HarfBuzz includes |
| 41 | functions to create <type>hb_face_t</type> and |
| 42 | <type>hb_font_t</type> objects directly from FreeType |
n8willis | c241e82 | 2020-04-13 15:28:42 +0100 | [diff] [blame] | 43 | objects. HarfBuzz can use FreeType's built-in functions for |
Nathan Willis | 2da567e | 2019-05-24 11:13:53 +0100 | [diff] [blame] | 44 | <structfield>font_funcs</structfield> vtable in an <type>hb_font_t</type>. |
| 45 | </para> |
| 46 | <para> |
| 47 | FreeType's output is bitmaps of the rasterized glyphs; on a |
| 48 | typical Linux system these will then be drawn by a graphics |
| 49 | library like Cairo, but those details are beyond HarfBuzz's |
| 50 | control. On the other hand, at the top end of the stack, Pango is |
| 51 | part of the larger GNOME framework, and HarfBuzz does include APIs |
| 52 | for working with key components of GNOME's higher-level libraries |
| 53 | — most notably GLib. |
| 54 | </para> |
| 55 | <para> |
| 56 | For other operating systems or application frameworks, the |
| 57 | critical integration points are where HarfBuzz gets font and face |
| 58 | information about the font used for shaping and where HarfBuzz |
| 59 | gets Unicode data about the input-buffer code points. |
| 60 | </para> |
| 61 | <para> |
| 62 | The font and face information is necessary for text shaping |
| 63 | because HarfBuzz needs to retrieve the glyph indices for |
| 64 | particular code points, and to know the extents and advances of |
| 65 | glyphs. Note that, in an OpenType variable font, both of those |
| 66 | types of information can change with different variation-axis |
| 67 | settings. |
| 68 | </para> |
| 69 | <para> |
| 70 | The Unicode information is necessary for shaping because the |
n8willis | 3a47921 | 2020-04-13 15:42:00 +0100 | [diff] [blame] | 71 | properties of a code point (such as its General Category (gc), |
Nathan Willis | 2da567e | 2019-05-24 11:13:53 +0100 | [diff] [blame] | 72 | Canonical Combining Class (ccc), and decomposition) can directly |
| 73 | impact the shaping moves that HarfBuzz performs. |
| 74 | </para> |
| 75 | |
| 76 | <section id="integration-glib"> |
| 77 | <title>GNOME integration, GLib, and GObject</title> |
| 78 | <para> |
| 79 | As mentioned in the preceding section, HarfBuzz offers |
| 80 | integration APIs to help client programs using the |
| 81 | GNOME and GTK framework commonly found in desktop Linux |
| 82 | distributions. |
| 83 | </para> |
| 84 | <para> |
| 85 | GLib is the main utility library for GNOME applications. It |
| 86 | provides basic data types and conversions, file abstractions, |
| 87 | string manipulation, and macros, as well as facilities like |
| 88 | memory allocation and the main event loop. |
| 89 | </para> |
| 90 | <para> |
| 91 | Where text shaping is concerned, GLib provides several utilities |
| 92 | that HarfBuzz can take advantage of, including a set of |
| 93 | Unicode-data functions and a data type for script |
| 94 | information. Both are useful when working with HarfBuzz |
| 95 | buffers. To make use of them, you will need to include the |
| 96 | <filename>hb-glib.h</filename> header file. |
| 97 | </para> |
| 98 | <para> |
| 99 | GLib's <ulink |
| 100 | url="https://developer.gnome.org/glib/stable/glib-Unicode-Manipulation.html">Unicode |
| 101 | manipulation API</ulink> includes all the functionality |
| 102 | necessary to retrieve Unicode data for the |
| 103 | <structfield>unicode_funcs</structfield> structure of a HarfBuzz |
| 104 | <type>hb_buffer_t</type>. |
| 105 | </para> |
| 106 | <para> |
| 107 | The function <function>hb_glib_get_unicode_funcs()</function> |
| 108 | sets up a <type>hb_unicode_funcs_t</type> structure configured |
| 109 | with the GLib Unicode functions and returns a pointer to it. |
| 110 | </para> |
| 111 | <para> |
| 112 | You can attach this Unicode-functions structure to your buffer, |
| 113 | and it will be ready for use with GLib: |
| 114 | </para> |
| 115 | <programlisting language="C"> |
| 116 | #include <hb-glib.h> |
| 117 | ... |
| 118 | hb_unicode_funcs_t *glibufunctions; |
| 119 | glibufunctions = hb_glib_get_unicode_funcs(); |
| 120 | hb_buffer_set_unicode_funcs(buf, glibufunctions); |
| 121 | </programlisting> |
| 122 | <para> |
| 123 | For script information, GLib uses the |
| 124 | <type>GUnicodeScript</type> type. Like HarfBuzz's own |
| 125 | <type>hb_script_t</type>, this data type is an enumeration |
| 126 | of Unicode scripts, but text segments passed in from GLib code |
| 127 | will be tagged with a <type>GUnicodeScript</type>. Therefore, |
| 128 | when setting the script property on a <type>hb_buffer_t</type>, |
| 129 | you will need to convert between the <type>GUnicodeScript</type> |
| 130 | of the input provided by GLib and HarfBuzz's |
| 131 | <type>hb_script_t</type> type. |
| 132 | </para> |
| 133 | <para> |
| 134 | The <function>hb_glib_script_to_script()</function> function |
| 135 | takes an <type>GUnicodeScript</type> script identifier as its |
| 136 | sole argument and returns the corresponding <type>hb_script_t</type>. |
| 137 | The <function>hb_glib_script_from_script()</function> does the |
| 138 | reverse, taking an <type>hb_script_t</type> and returning the |
| 139 | <type>GUnicodeScript</type> identifier for GLib. |
| 140 | </para> |
| 141 | <para> |
| 142 | Finally, GLib also provides a reference-counted object type called <ulink |
| 143 | url="https://developer.gnome.org/glib/stable/glib-Byte-Arrays.html#GBytes"><type>GBytes</type></ulink> |
| 144 | that is used for accessing raw memory segments with the benefits |
| 145 | of GLib's lifecycle management. HarfBuzz provides a |
| 146 | <function>hb_glib_blob_create()</function> function that lets |
| 147 | you create an <type>hb_blob_t</type> directly from a |
| 148 | <type>GBytes</type> object. This function takes only the |
| 149 | <type>GBytes</type> object as its input; HarfBuzz registers the |
| 150 | GLib <function>destroy</function> callback automatically. |
| 151 | </para> |
| 152 | <para> |
| 153 | The GNOME platform also features an object system called |
| 154 | GObject. For HarfBuzz, the main advantage of GObject is a |
| 155 | feature called <ulink |
| 156 | url="https://gi.readthedocs.io/en/latest/">GObject |
| 157 | Introspection</ulink>. This is a middleware facility that can be |
| 158 | used to generate language bindings for C libraries. HarfBuzz uses it |
| 159 | to build its Python bindings, which we will look at in a separate section. |
| 160 | </para> |
| 161 | </section> |
| 162 | |
| 163 | <section id="integration-freetype"> |
| 164 | <title>FreeType integration</title> |
| 165 | <para> |
| 166 | FreeType is the free-software font-rendering engine included in |
| 167 | desktop Linux distributions, Android, ChromeOS, iOS, and multiple Unix |
| 168 | operating systems, and used by cross-platform programs like |
| 169 | Chrome, Java, and GhostScript. Used together, HarfBuzz can |
| 170 | perform shaping on Unicode text segments, outputting the glyph |
| 171 | IDs that FreeType should rasterize from the active font as well |
| 172 | as the positions at which those glyphs should be drawn. |
| 173 | </para> |
| 174 | <para> |
| 175 | HarfBuzz provides integration points with FreeType at the |
| 176 | face-object and font-object level and for the font-functions |
| 177 | virtual-method structure of a font object. To use the |
| 178 | FreeType-integration API, include the |
| 179 | <filename>hb-ft.h</filename> header. |
| 180 | </para> |
| 181 | <para> |
| 182 | In a typical client program, you will create your |
| 183 | <type>hb_face_t</type> face object and <type>hb_font_t</type> |
| 184 | font object from a FreeType <type>FT_Face</type>. HarfBuzz |
| 185 | provides a suite of functions for doing this. |
| 186 | </para> |
| 187 | <para> |
| 188 | In the most common case, you will want to use |
| 189 | <function>hb_ft_font_create_referenced()</function>, which |
| 190 | creates both an <type>hb_face_t</type> face object and |
| 191 | <type>hb_font_t</type> font object (linked to that face object), |
| 192 | and provides lifecycle management. |
| 193 | </para> |
| 194 | <para> |
| 195 | It is important to note, |
| 196 | though, that while HarfBuzz makes a distinction between its face and |
| 197 | font objects, FreeType's <type>FT_Face</type> does not. After |
| 198 | you create your <type>FT_Face</type>, you must set its size |
| 199 | parameter using <function>FT_Set_Char_Size()</function>, because |
| 200 | an <type>hb_font_t</type> is defined as an instance of an |
| 201 | <type>hb_face_t</type> with size specified. |
| 202 | </para> |
| 203 | <programlisting language="C"> |
| 204 | #include <hb-ft.h> |
| 205 | ... |
Nathan Willis | dd1c765 | 2019-05-24 14:30:15 +0100 | [diff] [blame] | 206 | FT_New_Face(ft_library, font_path, index, &face); |
Nathan Willis | 2da567e | 2019-05-24 11:13:53 +0100 | [diff] [blame] | 207 | FT_Set_Char_Size(face, 0, 1000, 0, 0); |
| 208 | hb_font_t *font = hb_ft_font_create(face); |
| 209 | </programlisting> |
| 210 | <para> |
n8willis | d6edd9a | 2020-04-19 15:26:28 +0100 | [diff] [blame] | 211 | <function>hb_ft_font_create_referenced()</function> is |
| 212 | the recommended function for creating an <type>hb_face_t</type> face |
| 213 | object. This function calls <function>FT_Reference_Face()</function> |
| 214 | before using the <type>FT_Face</type> and calls |
| 215 | <function>FT_Done_Face()</function> when it is finished using the |
| 216 | <type>FT_Face</type>. Consequently, your client program does not need |
| 217 | to worry about destroying the <type>FT_Face</type> while HarfBuzz |
| 218 | is still using it. |
| 219 | </para> |
| 220 | <para> |
Nathan Willis | 2da567e | 2019-05-24 11:13:53 +0100 | [diff] [blame] | 221 | Although <function>hb_ft_font_create_referenced()</function> is |
n8willis | d6edd9a | 2020-04-19 15:26:28 +0100 | [diff] [blame] | 222 | the recommended function, there is another variant for client code |
| 223 | where special circumstances make it necessary. The simpler |
| 224 | version of the function is <function>hb_ft_font_create()</function>, |
| 225 | which takes an <type>FT_Face</type> and an optional destroy callback |
| 226 | as its arguments. Because <function>hb_ft_font_create()</function> |
| 227 | does not offer lifecycle management, however, your client code will |
| 228 | be responsible for tracking references to the <type>FT_Face</type> |
| 229 | objects and destroying them when they are no longer needed. If you |
| 230 | do not have a valid reason for doing this, use |
Nathan Willis | 2da567e | 2019-05-24 11:13:53 +0100 | [diff] [blame] | 231 | <function>hb_ft_font_create_referenced()</function>. |
| 232 | </para> |
| 233 | <para> |
| 234 | After you have created your font object from your |
| 235 | <type>FT_Face</type>, you can set or retrieve the |
| 236 | <structfield>load_flags</structfield> of the |
| 237 | <type>FT_Face</type> through the <type>hb_font_t</type> |
| 238 | object. HarfBuzz provides |
| 239 | <function>hb_ft_font_set_load_flags()</function> and |
| 240 | <function>hb_ft_font_get_load_flags()</function> for this |
| 241 | purpose. The ability to set the |
| 242 | <structfield>load_flags</structfield> through the font object |
| 243 | could be useful for enabling or disabling hinting, for example, |
| 244 | or to activate vertical layout. |
| 245 | </para> |
| 246 | <para> |
| 247 | HarfBuzz also provides a utility function called |
| 248 | <function>hb_ft_font_has_changed()</function> that you should |
| 249 | call whenever you have altered the properties of your underlying |
| 250 | <type>FT_Face</type>, as well as a |
| 251 | <function>hb_ft_get_face()</function> that you can call on an |
| 252 | <type>hb_font_t</type> font object to fetch its underlying <type>FT_Face</type>. |
| 253 | </para> |
| 254 | <para> |
| 255 | With an <type>hb_face_t</type> and <type>hb_font_t</type> both linked |
| 256 | to your <type>FT_Face</type>, you will typically also want to |
| 257 | use FreeType for the <structfield>font_funcs</structfield> |
| 258 | vtable of your <type>hb_font_t</type>. As a reminder, this |
| 259 | font-functions structure is the set of methods that HarfBuzz |
| 260 | will use to fetch important information from the font, such as |
| 261 | the advances and extents of individual glyphs. |
| 262 | </para> |
| 263 | <para> |
| 264 | All you need to do is call |
| 265 | </para> |
| 266 | <programlisting language="C"> |
| 267 | hb_ft_font_set_funcs(font); |
| 268 | </programlisting> |
| 269 | <para> |
| 270 | and HarfBuzz will use FreeType for the font-functions in |
| 271 | <literal>font</literal>. |
| 272 | </para> |
| 273 | <para> |
| 274 | As we noted above, an <type>hb_font_t</type> is derived from an |
| 275 | <type>hb_face_t</type> with size (and, perhaps, other |
| 276 | parameters, such as variation-axis coordinates) |
| 277 | specified. Consequently, you can reuse an <type>hb_face_t</type> |
| 278 | with several <type>hb_font_t</type> objects, and HarfBuzz |
| 279 | provides functions to simplify this. |
| 280 | </para> |
| 281 | <para> |
| 282 | The <function>hb_ft_face_create_referenced()</function> |
| 283 | function creates just an <type>hb_face_t</type> from a FreeType |
| 284 | <type>FT_Face</type> and, as with |
| 285 | <function>hb_ft_font_create_referenced()</function> above, |
| 286 | provides lifecycle management for the <type>FT_Face</type>. |
| 287 | </para> |
| 288 | <para> |
| 289 | Similarly, there is an <function>hb_ft_face_create()</function> |
| 290 | function variant that does not provide the lifecycle-management |
| 291 | feature. As with the font-object case, if you use this version |
| 292 | of the function, it will be your client code's respsonsibility |
| 293 | to track usage of the <type>FT_Face</type> objects. |
| 294 | </para> |
| 295 | <para> |
| 296 | A third variant of this function is |
| 297 | <function>hb_ft_face_create_cached()</function>, which is the |
| 298 | same as <function>hb_ft_face_create()</function> except that it |
| 299 | also uses the <structfield>generic</structfield> field of the |
| 300 | <type>FT_Face</type> structure to save a pointer to the newly |
| 301 | created <type>hb_face_t</type>. Subsequently, function calls |
| 302 | that pass the same <type>FT_Face</type> will get the same |
| 303 | <type>hb_face_t</type> returned — and the |
| 304 | <type>hb_face_t</type> will be correctly reference |
| 305 | counted. Still, as with |
| 306 | <function>hb_ft_face_create()</function>, your client code must |
| 307 | track references to the <type>FT_Face</type> itself, and destroy |
| 308 | it when it is unneeded. |
| 309 | </para> |
| 310 | </section> |
| 311 | |
| 312 | <section id="integration-uniscribe"> |
| 313 | <title>Uniscribe integration</title> |
| 314 | <para> |
Nathan Willis | c0bb66e | 2019-05-24 18:49:40 +0100 | [diff] [blame] | 315 | If your client program is running on Windows, HarfBuzz offers |
| 316 | an additional API that can help integrate with Microsoft's |
| 317 | Uniscribe engine and the Windows GDI. |
Nathan Willis | 2da567e | 2019-05-24 11:13:53 +0100 | [diff] [blame] | 318 | </para> |
| 319 | <para> |
Nathan Willis | dd1c765 | 2019-05-24 14:30:15 +0100 | [diff] [blame] | 320 | Overall, the Uniscribe API covers a broader set of typographic |
| 321 | layout functions than HarfBuzz implements, but HarfBuzz's |
Nathan Willis | c0bb66e | 2019-05-24 18:49:40 +0100 | [diff] [blame] | 322 | shaping API can serve as a drop-in replacement for Uniscribe's shaping |
Nathan Willis | dd1c765 | 2019-05-24 14:30:15 +0100 | [diff] [blame] | 323 | functionality. In fact, one of HarfBuzz's design goals is to |
| 324 | accurately reproduce the same output for shaping a given text |
| 325 | segment that Uniscribe produces — even to the point of |
| 326 | duplicating known shaping bugs or deviations from the |
n8willis | 9457b60 | 2020-04-13 17:01:15 +0100 | [diff] [blame] | 327 | specification — so you can be confident that your users' |
| 328 | documents with their existing fonts will not be affected adversely by |
Nathan Willis | dd1c765 | 2019-05-24 14:30:15 +0100 | [diff] [blame] | 329 | switching to HarfBuzz. |
Nathan Willis | 2da567e | 2019-05-24 11:13:53 +0100 | [diff] [blame] | 330 | </para> |
| 331 | <para> |
Nathan Willis | dd1c765 | 2019-05-24 14:30:15 +0100 | [diff] [blame] | 332 | At a basic level, HarfBuzz's <function>hb_shape()</function> |
| 333 | function replaces both the <ulink url=""><function>ScriptShape()</function></ulink> |
Nathan Willis | c0bb66e | 2019-05-24 18:49:40 +0100 | [diff] [blame] | 334 | and <ulink |
| 335 | url="https://docs.microsoft.com/en-us/windows/desktop/api/Usp10/nf-usp10-scriptplace"><function>ScriptPlace()</function></ulink> |
| 336 | functions from Uniscribe. |
Nathan Willis | dd1c765 | 2019-05-24 14:30:15 +0100 | [diff] [blame] | 337 | </para> |
| 338 | <para> |
| 339 | However, whereas <function>ScriptShape()</function> returns the |
| 340 | glyphs and clusters for a shaped sequence and |
| 341 | <function>ScriptPlace()</function> returns the advances and |
| 342 | offsets for those glyphs, <function>hb_shape()</function> |
| 343 | handles both. After <function>hb_shape()</function> shapes a |
| 344 | buffer, the output glyph IDs and cluster IDs are returned as |
| 345 | an array of <structname>hb_glyph_info_t</structname> structures, and the |
| 346 | glyph advances and offsets are returned as an array of |
| 347 | <structname>hb_glyph_position_t</structname> structures. |
| 348 | </para> |
| 349 | <para> |
| 350 | Your client program only needs to ensure that it coverts |
| 351 | correctly between HarfBuzz's low-level data types (such as |
| 352 | <type>hb_position_t</type>) and Windows's corresponding types |
| 353 | (such as <type>GOFFSET</type> and <type>ABC</type>). Be sure you |
| 354 | read the <xref linkend="buffers-language-script-and-direction" |
| 355 | /> |
| 356 | chapter for a full explanation of how HarfBuzz input buffers are |
| 357 | used, and see <xref linkend="shaping-buffer-output" /> for the |
| 358 | details of what <function>hb_shape()</function> returns in the |
| 359 | output buffer when shaping is complete. |
| 360 | </para> |
| 361 | <para> |
| 362 | Although <function>hb_shape()</function> itself is functionally |
| 363 | equivalent to Uniscribe's shaping routines, there are two |
| 364 | additional HarfBuzz functions you may want to use to integrate |
| 365 | the libraries in your code. Both are used to link HarfBuzz font |
| 366 | objects to the equivalent Windows structures. |
| 367 | </para> |
| 368 | <para> |
| 369 | The <function>hb_uniscribe_font_get_logfontw()</function> |
| 370 | function takes a <type>hb_font_t</type> font object and returns |
| 371 | a pointer to the <ulink |
| 372 | url="https://docs.microsoft.com/en-us/windows/desktop/api/wingdi/ns-wingdi-logfontw"><type>LOGFONTW</type></ulink> |
| 373 | "logical font" that corresponds to it. A <type>LOGFONTW</type> |
| 374 | structure holds font-wide attributes, including metrics, size, |
| 375 | and style information. |
| 376 | </para> |
Nathan Willis | c0bb66e | 2019-05-24 18:49:40 +0100 | [diff] [blame] | 377 | <!-- |
| 378 | <para> |
| 379 | In Uniscribe's model, the <type>SCRIPT_CACHE</type> holds the |
| 380 | device context, including the logical font that the shaping |
| 381 | functions apply. |
| 382 | https://docs.microsoft.com/en-us/windows/desktop/Intl/script-cache |
| 383 | </para> |
| 384 | --> |
Nathan Willis | dd1c765 | 2019-05-24 14:30:15 +0100 | [diff] [blame] | 385 | <para> |
| 386 | The <function>hb_uniscribe_font_get_hfont()</function> function |
| 387 | also takes a <type>hb_font_t</type> font object, but it returns |
| 388 | an <type>HFONT</type> — a handle to the underlying logical |
| 389 | font — instead. |
| 390 | </para> |
| 391 | <para> |
| 392 | <type>LOGFONTW</type>s and <type>HFONT</type>s are both needed |
| 393 | by other Uniscribe functions. |
| 394 | </para> |
| 395 | <para> |
| 396 | As a final note, you may notice a reference to an optional |
| 397 | <literal>uniscribe</literal> shaper back-end in the <xref |
| 398 | linkend="configuration" /> section of the HarfBuzz manual. This |
| 399 | option is not a Uniscribe-integration facility. |
| 400 | </para> |
| 401 | <para> |
| 402 | Instead, it is a internal code path used in the |
| 403 | <command>hb-shape</command> command-line utility, which hands |
| 404 | shaping functionality over to Uniscribe entirely, when run on a |
| 405 | Windows system. That allows testing HarfBuzz's native output |
| 406 | against the Uniscribe engine, for tracking compatibility and |
| 407 | debugging. |
| 408 | </para> |
| 409 | <para> |
| 410 | Because this back-end is only used when testing HarfBuzz |
| 411 | functionality, it is disabled by default when building the |
| 412 | HarfBuzz binaries. |
Nathan Willis | 2da567e | 2019-05-24 11:13:53 +0100 | [diff] [blame] | 413 | </para> |
| 414 | </section> |
Nathan Willis | dd1c765 | 2019-05-24 14:30:15 +0100 | [diff] [blame] | 415 | |
Nathan Willis | 2da567e | 2019-05-24 11:13:53 +0100 | [diff] [blame] | 416 | <section id="integration-coretext"> |
Nathan Willis | c0bb66e | 2019-05-24 18:49:40 +0100 | [diff] [blame] | 417 | <title>Core Text integration</title> |
Nathan Willis | 2da567e | 2019-05-24 11:13:53 +0100 | [diff] [blame] | 418 | <para> |
Nathan Willis | c0bb66e | 2019-05-24 18:49:40 +0100 | [diff] [blame] | 419 | If your client program is running on macOS or iOS, HarfBuzz offers |
| 420 | an additional API that can help integrate with Apple's |
| 421 | Core Text engine and the underlying Core Graphics |
| 422 | framework. HarfBuzz does not attempt to offer the same |
| 423 | drop-in-replacement functionality for Core Text that it strives |
n8willis | 17b60ef | 2020-04-13 16:51:58 +0100 | [diff] [blame] | 424 | for with Uniscribe on Windows, but you can still use HarfBuzz |
Nathan Willis | c0bb66e | 2019-05-24 18:49:40 +0100 | [diff] [blame] | 425 | to perform text shaping in native macOS and iOS applications. |
Nathan Willis | 2da567e | 2019-05-24 11:13:53 +0100 | [diff] [blame] | 426 | </para> |
| 427 | <para> |
Nathan Willis | c0bb66e | 2019-05-24 18:49:40 +0100 | [diff] [blame] | 428 | Note, though, that if your interest is just in using fonts that |
| 429 | contain Apple Advanced Typography (AAT) features, then you do |
| 430 | not need to add Core Text integration. HarfBuzz natively |
| 431 | supports AAT features and will shape AAT fonts (on any platform) |
| 432 | automatically, without requiring additional work on your |
| 433 | part. This includes support for AAT-specific TrueType tables |
| 434 | such as <literal>mort</literal>, <literal>morx</literal>, and |
| 435 | <literal>kerx</literal>, which AAT fonts use instead of |
| 436 | <literal>GSUB</literal> and <literal>GPOS</literal>. |
Nathan Willis | 2da567e | 2019-05-24 11:13:53 +0100 | [diff] [blame] | 437 | </para> |
| 438 | <para> |
Nathan Willis | c0bb66e | 2019-05-24 18:49:40 +0100 | [diff] [blame] | 439 | On a macOS or iOS system, the primary integration points offered |
| 440 | by HarfBuzz are for face objects and font objects. |
Nathan Willis | 2da567e | 2019-05-24 11:13:53 +0100 | [diff] [blame] | 441 | </para> |
Nathan Willis | dd1c765 | 2019-05-24 14:30:15 +0100 | [diff] [blame] | 442 | <para> |
Nathan Willis | c0bb66e | 2019-05-24 18:49:40 +0100 | [diff] [blame] | 443 | The Apple APIs offer a pair of data structures that map well to |
| 444 | HarfBuzz's face and font objects. The Core Graphics API, which |
| 445 | is slightly lower-level than Core Text, provides |
| 446 | <ulink url="https://developer.apple.com/documentation/coregraphics/cgfontref"><type>CGFontRef</type></ulink>, which enables access to typeface |
| 447 | properties, but does not include size information. Core Text's |
| 448 | <ulink url="https://developer.apple.com/documentation/coretext/ctfont-q6r"><type>CTFontRef</type></ulink> is analagous to a HarfBuzz font object, |
| 449 | with all of the properties required to render text at a specific |
| 450 | size and configuration. |
| 451 | Consequently, a HarfBuzz <type>hb_font_t</type> font object can |
| 452 | be hooked up to a Core Text <type>CTFontRef</type>, and a HarfBuzz |
| 453 | <type>hb_face_t</type> face object can be hooked up to a |
| 454 | <type>CGFontRef</type>. |
Nathan Willis | dd1c765 | 2019-05-24 14:30:15 +0100 | [diff] [blame] | 455 | </para> |
| 456 | <para> |
Nathan Willis | c0bb66e | 2019-05-24 18:49:40 +0100 | [diff] [blame] | 457 | You can create a <type>hb_face_t</type> from a |
| 458 | <type>CGFontRef</type> by using the |
| 459 | <function>hb_coretext_face_create()</function>. Subsequently, |
| 460 | you can retrieve the <type>CGFontRef</type> from a |
| 461 | <type>hb_face_t</type> with <function>hb_coretext_face_get_cg_font()</function>. |
Nathan Willis | dd1c765 | 2019-05-24 14:30:15 +0100 | [diff] [blame] | 462 | </para> |
| 463 | <para> |
Nathan Willis | c0bb66e | 2019-05-24 18:49:40 +0100 | [diff] [blame] | 464 | Likewise, you create a <type>hb_font_t</type> from a |
| 465 | <type>CTFontRef</type> by calling |
| 466 | <function>hb_coretext_font_create()</function>, and you can |
| 467 | fetch the associated <type>CTFontRef</type> from a |
| 468 | <type>hb_font_t</type> font object with |
| 469 | <function>hb_coretext_face_get_ct_font()</function>. |
Nathan Willis | dd1c765 | 2019-05-24 14:30:15 +0100 | [diff] [blame] | 470 | </para> |
| 471 | <para> |
Nathan Willis | c0bb66e | 2019-05-24 18:49:40 +0100 | [diff] [blame] | 472 | HarfBuzz also offers a <function>hb_font_set_ptem()</function> |
| 473 | that you an use to set the nominal point size on any |
| 474 | <type>hb_font_t</type> font object. Core Text uses this value to |
| 475 | implement optical scaling. |
Nathan Willis | dd1c765 | 2019-05-24 14:30:15 +0100 | [diff] [blame] | 476 | </para> |
| 477 | <para> |
Nathan Willis | c0bb66e | 2019-05-24 18:49:40 +0100 | [diff] [blame] | 478 | When integrating your client code with Core Text, it is |
| 479 | important to recognize that Core Text <literal>points</literal> |
| 480 | are not typographic points (standardized at 72 per inch) as the |
| 481 | term is used elsewhere in OpenType. Instead, Core Text points |
| 482 | are CSS points, which are standardized at 96 per inch. |
| 483 | </para> |
| 484 | <para> |
| 485 | HarfBuzz's font functions take this distinction into account, |
| 486 | but it can be an easy detail to miss in cross-platform |
| 487 | code. |
| 488 | </para> |
| 489 | <para> |
| 490 | As a final note, you may notice a reference to an optional |
| 491 | <literal>coretext</literal> shaper back-end in the <xref |
| 492 | linkend="configuration" /> section of the HarfBuzz manual. This |
n8willis | f782d73 | 2020-04-13 16:57:36 +0100 | [diff] [blame] | 493 | option is not a Core Text-integration facility. |
Nathan Willis | c0bb66e | 2019-05-24 18:49:40 +0100 | [diff] [blame] | 494 | </para> |
| 495 | <para> |
| 496 | Instead, it is a internal code path used in the |
| 497 | <command>hb-shape</command> command-line utility, which hands |
n8willis | f782d73 | 2020-04-13 16:57:36 +0100 | [diff] [blame] | 498 | shaping functionality over to Core Text entirely, when run on a |
Nathan Willis | c0bb66e | 2019-05-24 18:49:40 +0100 | [diff] [blame] | 499 | macOS system. That allows testing HarfBuzz's native output |
n8willis | f782d73 | 2020-04-13 16:57:36 +0100 | [diff] [blame] | 500 | against the Core Text engine, for tracking compatibility and debugging. |
Nathan Willis | c0bb66e | 2019-05-24 18:49:40 +0100 | [diff] [blame] | 501 | </para> |
| 502 | <para> |
| 503 | Because this back-end is only used when testing HarfBuzz |
| 504 | functionality, it is disabled by default when building the |
| 505 | HarfBuzz binaries. |
Nathan Willis | dd1c765 | 2019-05-24 14:30:15 +0100 | [diff] [blame] | 506 | </para> |
Nathan Willis | 2da567e | 2019-05-24 11:13:53 +0100 | [diff] [blame] | 507 | </section> |
| 508 | |
| 509 | <section id="integration-icu"> |
| 510 | <title>ICU integration</title> |
| 511 | <para> |
Nathan Willis | 773c85f | 2019-05-24 19:23:19 +0100 | [diff] [blame] | 512 | Although HarfBuzz includes its own Unicode-data functions, it |
| 513 | also provides integration APIs for using the International |
| 514 | Components for Unicode (ICU) library as a source of Unicode data |
| 515 | on any supported platform. |
| 516 | </para> |
| 517 | <para> |
n8willis | 05b7bdb | 2020-04-13 16:59:41 +0100 | [diff] [blame] | 518 | The principal integration point with ICU is the |
Nathan Willis | 773c85f | 2019-05-24 19:23:19 +0100 | [diff] [blame] | 519 | <type>hb_unicode_funcs_t</type> Unicode-functions structure |
| 520 | attached to a buffer. This structure holds the virtual methods |
| 521 | used for retrieving Unicode character properties, such as |
| 522 | General Category, Script, Combining Class, decomposition |
| 523 | mappings, and mirroring information. |
| 524 | </para> |
| 525 | <para> |
| 526 | To use ICU in your client program, you need to call |
| 527 | <function>hb_icu_get_unicode_funcs()</function>, which creates a |
| 528 | Unicode-functions structure populated with the ICU function for |
| 529 | each included method. Subsequently, you can attach the |
| 530 | Unicode-functions structure to your buffer: |
| 531 | </para> |
| 532 | <programlisting language="C"> |
| 533 | hb_unicode_funcs_t *icufunctions; |
| 534 | icufunctions = hb_icu_get_unicode_funcs(); |
| 535 | hb_buffer_set_unicode_funcs(buf, icufunctions); |
| 536 | </programlisting> |
| 537 | <para> |
| 538 | and ICU will be used for Unicode-data access. |
| 539 | </para> |
| 540 | <para> |
| 541 | HarfBuzz also supplies a pair of functions |
| 542 | (<function>hb_icu_script_from_script()</function> and |
| 543 | <function>hb_icu_script_to_script()</function>) for converting |
| 544 | between ICU's and HarfBuzz's internal enumerations of Unicode |
| 545 | scripts. The <function>hb_icu_script_from_script()</function> |
| 546 | function converts from a HarfBuzz <type>hb_script_t</type> to an |
| 547 | ICU <type>UScriptCode</type>. The |
| 548 | <function>hb_icu_script_to_script()</function> function does the |
| 549 | reverse: converting from a <type>UScriptCode</type> identifier |
| 550 | to a <type>hb_script_t</type>. |
| 551 | </para> |
| 552 | <para> |
n8willis | 1ed3051 | 2020-04-19 15:38:52 +0100 | [diff] [blame] | 553 | By default, HarfBuzz's ICU support is built as a separate shared |
| 554 | library (<filename class="libraryfile">libharfbuzz-icu.so</filename>) |
| 555 | when compiling HarfBuzz from source. This allows client programs |
| 556 | that do not need ICU to link against HarfBuzz without unnecessarily |
| 557 | adding ICU as a dependency. You can also build HarfBuzz with ICU |
| 558 | support built directly into the main HarfBuzz shared library |
| 559 | (<filename class="libraryfile">libharfbuzz.so</filename>), |
| 560 | by specifying the <literal>--with-icu=builtin</literal> |
| 561 | compile-time option. |
Nathan Willis | 2da567e | 2019-05-24 11:13:53 +0100 | [diff] [blame] | 562 | </para> |
Nathan Willis | 773c85f | 2019-05-24 19:23:19 +0100 | [diff] [blame] | 563 | |
Nathan Willis | 2da567e | 2019-05-24 11:13:53 +0100 | [diff] [blame] | 564 | </section> |
| 565 | |
| 566 | <section id="integration-python"> |
| 567 | <title>Python bindings</title> |
| 568 | <para> |
Nathan Willis | 322df80 | 2019-05-24 19:49:19 +0100 | [diff] [blame] | 569 | As noted in the <xref linkend="integration-glib" /> section, |
| 570 | HarfBuzz uses a feature called <ulink |
| 571 | url="https://wiki.gnome.org/Projects/GObjectIntrospection">GObject |
| 572 | Introspection</ulink> (GI) to provide bindings for Python. |
Nathan Willis | 2da567e | 2019-05-24 11:13:53 +0100 | [diff] [blame] | 573 | </para> |
| 574 | <para> |
Nathan Willis | 322df80 | 2019-05-24 19:49:19 +0100 | [diff] [blame] | 575 | At compile time, the GI scanner analyzes the HarfBuzz C source |
| 576 | and builds metadata objects connecting the language bindings to |
| 577 | the C library. Your Python code can then use the HarfBuzz binary |
| 578 | through its Python interface. |
Nathan Willis | 2da567e | 2019-05-24 11:13:53 +0100 | [diff] [blame] | 579 | </para> |
| 580 | <para> |
Nathan Willis | 322df80 | 2019-05-24 19:49:19 +0100 | [diff] [blame] | 581 | HarfBuzz's Python bindings support Python 2 and Python 3. To use |
| 582 | them, you will need to have the <literal>pygobject</literal> |
| 583 | package installed. Then you should import |
| 584 | <literal>HarfBuzz</literal> from |
| 585 | <literal>gi.repository</literal>: |
Nathan Willis | 2da567e | 2019-05-24 11:13:53 +0100 | [diff] [blame] | 586 | </para> |
Nathan Willis | 322df80 | 2019-05-24 19:49:19 +0100 | [diff] [blame] | 587 | <programlisting language="Python"> |
| 588 | from gi.repository import HarfBuzz |
| 589 | </programlisting> |
Nathan Willis | 2da567e | 2019-05-24 11:13:53 +0100 | [diff] [blame] | 590 | <para> |
Nathan Willis | 322df80 | 2019-05-24 19:49:19 +0100 | [diff] [blame] | 591 | and you can call HarfBuzz functions from Python. Sample code can |
| 592 | be found in the <filename>sample.py</filename> script in the |
| 593 | HarfBuzz <filename>src</filename> directory. |
Nathan Willis | 2da567e | 2019-05-24 11:13:53 +0100 | [diff] [blame] | 594 | </para> |
| 595 | <para> |
Nathan Willis | 322df80 | 2019-05-24 19:49:19 +0100 | [diff] [blame] | 596 | Do note, however, that the Python API is subject to change |
| 597 | without advance notice. GI allows the bindings to be |
| 598 | automatically updated, which is one of its advantages, but you |
| 599 | may need to update your Python code. |
Nathan Willis | 2da567e | 2019-05-24 11:13:53 +0100 | [diff] [blame] | 600 | </para> |
| 601 | </section> |
| 602 | |
| 603 | </chapter> |