1 <chapter id="hello-harfbuzz"> 2 <title>Hello, Harfbuzz</title> 3 <para> 4 Here's the simplest Harfbuzz that can possibly work. We will improve 5 it later. 6 </para> 7 <orderedlist numeration="arabic"> 8 <listitem> 9 <para> 10 Create a buffer and put your text in it. 11 </para> 12 </listitem> 13 </orderedlist> 14 <programlisting language="C"> 15 #include <hb.h> 16 hb_buffer_t *buf; 17 buf = hb_buffer_create(); 18 hb_buffer_add_utf8(buf, text, strlen(text), 0, strlen(text)); 19 </programlisting> 20 <orderedlist numeration="arabic"> 21 <listitem override="2"> 22 <para> 23 Guess the script, language and direction of the buffer. 24 </para> 25 </listitem> 26 </orderedlist> 27 <programlisting language="C"> 28 hb_buffer_guess_segment_properties(buf); 29 </programlisting> 30 <orderedlist numeration="arabic"> 31 <listitem override="3"> 32 <para> 33 Create a face and a font, using FreeType for now. 34 </para> 35 </listitem> 36 </orderedlist> 37 <programlisting language="C"> 38 #include <hb-ft.h> 39 FT_New_Face(ft_library, font_path, index, &face) 40 hb_font_t *font = hb_ft_font_create(face); 41 </programlisting> 42 <orderedlist numeration="arabic"> 43 <listitem override="4"> 44 <para> 45 Shape! 46 </para> 47 </listitem> 48 </orderedlist> 49 <programlisting> 50 hb_shape(font, buf, NULL, 0); 51 </programlisting> 52 <orderedlist numeration="arabic"> 53 <listitem override="5"> 54 <para> 55 Get the glyph and position information. 56 </para> 57 </listitem> 58 </orderedlist> 59 <programlisting language="C"> 60 hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(buf, &glyph_count); 61 hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(buf, &glyph_count); 62 </programlisting> 63 <orderedlist numeration="arabic"> 64 <listitem override="6"> 65 <para> 66 Iterate over each glyph. 67 </para> 68 </listitem> 69 </orderedlist> 70 <programlisting language="C"> 71 for (i = 0; i < glyph_count; ++i) { 72 glyphid = glyph_info[i].codepoint; 73 x_offset = glyph_pos[i].x_offset / 64.0; 74 y_offset = glyph_pos[i].y_offset / 64.0; 75 x_advance = glyph_pos[i].x_advance / 64.0; 76 y_advance = glyph_pos[i].y_advance / 64.0; 77 draw_glyph(glyphid, cursor_x + x_offset, cursor_y + y_offset); 78 cursor_x += x_advance; 79 cursor_y += y_advance; 80 } 81 </programlisting> 82 <orderedlist numeration="arabic"> 83 <listitem override="7"> 84 <para> 85 Tidy up. 86 </para> 87 </listitem> 88 </orderedlist> 89 <programlisting language="C"> 90 hb_buffer_destroy(buf); 91 hb_font_destroy(hb_ft_font); 92 </programlisting> 93 <section id="what-harfbuzz-doesnt-do"> 94 <title>What Harfbuzz doesn't do</title> 95 <para> 96 The code above will take a UTF8 string, shape it, and give you the 97 information required to lay it out correctly on a single 98 horizontal (or vertical) line using the font provided. That is the 99 extent of Harfbuzz's responsibility. 100 </para> 101 <para> 102 If you are implementing a text layout engine you may have other 103 responsibilities, that Harfbuzz will not help you with: 104 </para> 105 <itemizedlist> 106 <listitem> 107 <para> 108 Harfbuzz won't help you with bidirectionality. If you want to 109 lay out text with mixed Hebrew and English, you will need to 110 ensure that the buffer provided to Harfbuzz has those 111 characters in the correct layout order. This will be different 112 from the logical order in which the Unicode text is stored. In 113 other words, the user will hit the keys in the following 114 sequence: 115 </para> 116 <programlisting> 117 A B C [space] [space] D E F 118 </programlisting> 119 <para> 120 but will expect to see in the output: 121 </para> 122 <programlisting> 123 ABC DEF 124 </programlisting> 125 <para> 126 This reordering is called <emphasis>bidi processing</emphasis> 127 ("bidi" is short for bidirectional), and there's an 128 algorithm as an annex to the Unicode Standard which tells you how 129 to reorder a string from logical order into presentation order. 130 Before sending your string to Harfbuzz, you may need to apply the 131 bidi algorithm to it. Libraries such as ICU and fribidi can do 132 this for you. 133 </para> 134 </listitem> 135 <listitem> 136 <para> 137 Harfbuzz won't help you with text that contains different font 138 properties. For instance, if you have the string "a 139 <emphasis>huge</emphasis> breakfast", and you expect 140 "huge" to be italic, you will need to send three 141 strings to Harfbuzz: <literal>a</literal>, in your Roman font; 142 <literal>huge</literal> using your italic font; and 143 <literal>breakfast</literal> using your Roman font again. 144 Similarly if you change font, font size, script, language or 145 direction within your string, you will need to shape each run 146 independently and then output them independently. Harfbuzz 147 expects to shape a run of characters sharing the same 148 properties. 149 </para> 150 </listitem> 151 <listitem> 152 <para> 153 Harfbuzz won't help you with line breaking, hyphenation or 154 justification. As mentioned above, it lays out the string 155 along a <emphasis>single line</emphasis> of, notionally, 156 infinite length. If you want to find out where the potential 157 word, sentence and line break points are in your text, you 158 could use the ICU library's break iterator functions. 159 </para> 160 <para> 161 Harfbuzz can tell you how wide a shaped piece of text is, which is 162 useful input to a justification algorithm, but it knows nothing 163 about paragraphs, lines or line lengths. Nor will it adjust the 164 space between words to fit them proportionally into a line. If you 165 want to layout text in paragraphs, you will probably want to send 166 each word of your text to Harfbuzz to determine its shaped width 167 after glyph substitutions, then work out how many words will fit 168 on a line, and then finally output each word of the line separated 169 by a space of the correct size to fully justify the paragraph. 170 </para> 171 </listitem> 172 </itemizedlist> 173 <para> 174 As a layout engine implementor, Harfbuzz will help you with the 175 interface between your text and your font, and that's something 176 that you'll need - what you then do with the glyphs that your font 177 returns is up to you. The example we saw above enough to get us 178 started using Harfbuzz. Now we are going to use the remainder of 179 Harfbuzz's API to refine that example and improve our text shaping 180 capabilities. 181 </para> 182 </section> 183 </chapter>