<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>GraphiteNG Manual</title><link rel="stylesheet" type="text/css" href="./docbook-xsl.css" /><meta name="generator" content="DocBook XSL Stylesheets V1.76.1" /></head><body><div xml:lang="en" class="article" title="GraphiteNG Manual" lang="en"><div class="titlepage"><div><div><h2 class="title"><a id="id2544710"></a>GraphiteNG Manual</h2></div><div><div class="author"><h3 class="author"><span class="firstname">Martin</span> <span class="surname">Hosken</span></h3><code class="email"><<a class="email" href="mailto:martin_hosken@sil.org">martin_hosken@sil.org</a>></code></div></div></div><hr /></div><div class="toc"><p><strong>Table of Contents</strong></p><dl><dt><span class="section"><a href="#_introduction">1. Introduction</a></span></dt><dt><span class="section"><a href="#_building_graphiteng">2. Building GraphiteNG</a></span></dt><dd><dl><dt><span class="section"><a href="#_linux">2.1. Linux</a></span></dt></dl></dd><dt><span class="section"><a href="#_calling_graphite2">3. Calling Graphite2</a></span></dt><dd><dl><dt><span class="section"><a href="#_introduction_2">3.1. Introduction</a></span></dt><dt><span class="section"><a href="#_slots">3.2. Slots</a></span></dt><dt><span class="section"><a href="#_charinfo">3.3. CharInfo</a></span></dt><dt><span class="section"><a href="#_face">3.4. Face</a></span></dt><dt><span class="section"><a href="#_caching">3.5. Caching</a></span></dt><dt><span class="section"><a href="#_clustering">3.6. Clustering</a></span></dt><dt><span class="section"><a href="#_line_breaking_and_justification">3.7. Line Breaking and Justification</a></span></dt><dt><span class="section"><a href="#_bidi">3.8. Bidi</a></span></dt></dl></dd><dt><span class="section"><a href="#_font_features">4. Font Features</a></span></dt><dt><span class="section"><a href="#_hacking">5. Hacking</a></span></dt><dd><dl><dt><span class="section"><a href="#_compiling_and_integrating">5.1. Compiling and Integrating</a></span></dt><dt><span class="section"><a href="#_memory_allocation">5.2. Memory Allocation</a></span></dt><dt><span class="section"><a href="#_missing_features">5.3. Missing Features</a></span></dt><dt><span class="section"><a href="#_hunting_speed">5.4. Hunting Speed</a></span></dt></dl></dd><dt><span class="section"><a href="#_android">6. Android</a></span></dt></dl></div><div class="section" title="1. Introduction"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_introduction"></a>1. Introduction</h2></div></div></div><p>Graphite2 is a reimplementation of the SIL Graphite text processing engine. The reason for such a project has grown out of the experience gained in integration the Graphite engine into various applications and frameworks. The original engine was designed with different use cases in mind and optimised towards those. These optimisations get in the way of optimising for the actual use case requirements that the integration projects required. The Graphite2 engine, therefore, is designed for use where a simple shaping engine is required, much akin to the simpler OpenType engine interfaces that exist. Graphite2 has the following features over the original engine:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"> Faster </li><li class="listitem"> Smaller memory footprint </li><li class="listitem"> More resiliant to font corruption </li><li class="listitem"> Smaller code base </li></ul></div><p>What is lost is:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"> Selection support </li><li class="listitem"> Line end contextuals </li><li class="listitem"> Integrated line breaking to paragraph rendering </li></ul></div><p title="What is Graphite?"><strong>What is Graphite? </strong>Graphite is a <span class="emphasis"><em>smart font</em></span> technology designed to facilitate the process known as shaping. This process takes an input Unicode text string and returns a sequence of positioned glyphids from the font. There are other similar <span class="emphasis"><em>smart font</em></span> technologies including AAT and OpenType. While OpenType implementations are more prevalently integrated into applications than Graphite, Graphite still has a place. Graphite was developed primarily to address the generic shaping problem where current OpenType shaping engines do not address the specific needs of a font developer and the lead time on any changes to address those needs become prohibitive. This is a particular issue when creating solutions for some minority languages. In effect OpenType addresses the 80% problem and Graphite the 20% problem (or is that the 98% problem and the 2% problem?)</p><p>There are a number of reasons why someone might want to add Graphite smarts to their font:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"> There is no consistent shaping across OpenType engines for the script and writing system that a font designer wants their font to support. Not all OpenType engines support all scripts in the same way. In addition, some writing system requirements do not fit with the shaping of the script that OpenType engines support. </li><li class="listitem"> The font designer would like to implement more complex shaping and positioning than OpenType supports. For example, in Graphite one can position glyphs based on the positions and sizes of other glyphs. </li><li class="listitem"> Graphite supports user defined features. The font designer may create and support any features they want and these can be presented to the user in a standardised way. </li></ul></div><p>Graphite allows font implementors to implement their font their way. It does not require them to fit within an, often poorly specified, interface between the shaper and the font. This allows for quicker debugging and results. Graphite supports font debugging to identify what the shaper is doing all the way from input Unicode to output glyphs and positions, giving font designers better control over their font processing.</p></div><div class="section" title="2. Building GraphiteNG"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_building_graphiteng"></a>2. Building GraphiteNG</h2></div></div></div><p>GraphiteNG uses cmake for its build system. The basic build procedure is to create a directory in which to build the library and produce the products. Then cmake is run to generate build files and then the build is run.</p><div class="section" title="2.1. Linux"><div class="titlepage"><div><div><h3 class="title"><a id="_linux"></a>2.1. Linux</h3></div></div></div><pre class="screen">mkdir build cd build cmake -G "Unix Makefiles" .. make make test</pre></div></div><div class="section" title="3. Calling Graphite2"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_calling_graphite2"></a>3. Calling Graphite2</h2></div></div></div><div class="section" title="3.1. Introduction"><div class="titlepage"><div><div><h3 class="title"><a id="_introduction_2"></a>3.1. Introduction</h3></div></div></div><p>The basic model for running graphite is to pass text, font and face information to create a segment. A segment consists of a linked list of slots which each correspond to an output glyph. In addition a segment holds charinfo for each character in the input text.</p><pre class="programlisting">#include <graphite2/Segment.h> #include <stdio.h> /* usage: ./simple fontfile.ttf string */ int main(int argc, char **argv) { int rtl = 0; /* are we rendering right to left? probably not */ int pointsize = 12; /* point size in points */ int dpi = 96; /* work with this many dots per inch */ char *pError; /* location of faulty utf-8 */ gr_font *font = NULL; size_t numCodePoints = 0; gr_segment * seg = NULL; const gr_slot *s; gr_face *face = gr_make_file_face(argv[1], 0); /*<a id="CO1-1"></a><img src="./images/icons/callouts/1.png" alt="1" border="0" />*/ if (!face) return 1; font = gr_make_font(pointsize * dpi / 72.0f, face); /*<a id="CO1-2"></a><img src="./images/icons/callouts/2.png" alt="2" border="0" />*/ if (!font) return 2; numCodePoints = gr_count_unicode_characters(gr_utf8, argv[2], NULL, (const void **)(&pError)); /*<a id="CO1-3"></a><img src="./images/icons/callouts/3.png" alt="3" border="0" />*/ if (pError) return 3; seg = gr_make_seg(font, face, 0, 0, gr_utf8, argv[2], numCodePoints, rtl); /*<a id="CO1-4"></a><img src="./images/icons/callouts/4.png" alt="4" border="0" />*/ if (!seg) return 3; for (s = gr_seg_first_slot(seg); s; s = gr_slot_next_in_segment(s)) /*<a id="CO1-5"></a><img src="./images/icons/callouts/5.png" alt="5" border="0" />*/ printf("%d(%f,%f) ", gr_slot_gid(s), gr_slot_origin_X(s), gr_slot_origin_Y(s)); gr_seg_destroy(seg); gr_font_destroy(font); gr_face_destroy(face); return 0; }</pre><div class="calloutlist"><table border="0" summary="Callout list"><tr><td width="5%" valign="top" align="left"><p><a href="#CO1-1"><img src="./images/icons/callouts/1.png" alt="1" border="0" /></a> </p></td><td valign="top" align="left"> The first parameter to the program is the full path to the font file to be used for rendering. This function loads the font and reads all the graphite tables, etc. If there is a fault in the font, it will fail to load and the function will return NULL. </td></tr><tr><td width="5%" valign="top" align="left"><p><a href="#CO1-2"><img src="./images/icons/callouts/2.png" alt="2" border="0" /></a> </p></td><td valign="top" align="left"> A font is merely a face at a given size in pixels per em. It is possible to support hinted advances, but this is done via a callback function. </td></tr><tr><td width="5%" valign="top" align="left"><p><a href="#CO1-3"><img src="./images/icons/callouts/3.png" alt="3" border="0" /></a> </p></td><td valign="top" align="left"><p> For simplification of memory allocation, graphite works on characters (Unicode codepoints) rather than bytes or gr_uint16s, etc. We need to calculate the number of characters in the input string (the second parameter to the program). Very often applications already know this. If there is an error in the utf-8, the pError variable will point to it and we just exit. But it is possible to render up to that point. </p><p>If your string is null terminated, then you don’t necessarily have to calculate a precise number of characters. You can use a value that is greater than the number in the string and rely on graphite to stop at the terminating null. It is necessary to pass some value for the number of characters so that graphite can initialise its internal memory structures appropriately and not waste time updating them. Thus for UTF-16 and UTF-32 strings, one could simply pass the number of code units in the string. For UTF-8 it may be preferable to call gr_count_unicode_characters.</p></td></tr><tr><td width="5%" valign="top" align="left"><p><a href="#CO1-4"><img src="./images/icons/callouts/4.png" alt="4" border="0" /></a> </p></td><td valign="top" align="left"> Here we create a segment. A segment is the results of processing a string of text with graphite. It contains all the information necessary for final rendering including all the glyphs, their positions, relationships between glyphs and underlying characters, etc. </td></tr><tr><td width="5%" valign="top" align="left"><p><a href="#CO1-5"><img src="./images/icons/callouts/5.png" alt="5" border="0" /></a> </p></td><td valign="top" align="left"> A segment primarily consists of a linked list of slots. Each slot corresponds to a glyph in the output. The information about a glyph and its relationships is queried from the slot. </td></tr></table></div><p>Source for this program may be found in tests/examples/simple.c</p><p>Assuming that graphite2 has been built and installed, this example can be built and run on linux using:</p><pre class="screen">gcc -o simple -lgraphiteng simple.c LD_LIBRARY_PATH=/usr/local/lib ./simple ../fonts/Padauk.ttf 'Hello World!'</pre><p>Running simple gives the results:</p><pre class="screen">43(0.000000,0.000000) 72(9.859375,0.000000) 79(17.609375,0.000000) 79(20.796875,0.000000) 82(23.984375,0.000000) 3(32.203125,0.000000) 58(38.109375,0.000000) 82(51.625000,0.000000) 85(59.843750,0.000000) 79(64.875000,0.000000) 71(68.062500,0.000000) 4(76.281250,0.000000)</pre><p>Not very pretty, but reassuring! Graphite isn’t a graphical rendering engine, it merely calculates which glyphs should render where and leaves the actual process of displaying those glyphs to other libraries.</p></div><div class="section" title="3.2. Slots"><div class="titlepage"><div><div><h3 class="title"><a id="_slots"></a>3.2. Slots</h3></div></div></div><p>The primary contents of a segment is slots. These slots are organised into a doubly linked list and each corresponds to a glyph to be rendered. The linked list is terminated at each end by a NULL. There are also functions to get the first and last slot in a segment.</p><p>In addition to the main slot list, slots may be attached to each other. This means that two glyphs have been attached to each other in the GDL. Again, attached slots are held in a separate singly linked list associated with the slot to which they attach. Thus slots will be in the main linked list and may be in an attachment linked list. Each slot in an attachment linked list has the same attachment parent accessed via <code class="literal">gr_slot_attached_to()</code>. To get the start of the linked list of all the slots directly attached to a parent, one calls <code class="literal">gr_slot_first_attachment()</code> and then <code class="literal">gr_slot_next_attachment()</code> to walk forwards through that linked list. Given that a diacritic may attach to another diacritic, an attached slot may in its turn have a linked list of attached slots. In all cases, linked lists terminate with a NULL.</p><p>The core information held by a slot is the glyph id of the glyph the slot corresponds to (<code class="literal">gr_slot_gid()</code>); the position relative to the start of the segment that the glyph is to be rendered at (<code class="literal">gr_slot_origin_X()</code> and <code class="literal">gr_slot_origin_Y()</code>); the advance for the glyph which corresponds to the glyph metric advance as adjusted by kerning. In addition a slot indicates whether the font designer wants to allow a cursor to be placed before this glyph or not. This information is accessible via <code class="literal">gr_slot_can_insert_before()</code>.</p></div><div class="section" title="3.3. CharInfo"><div class="titlepage"><div><div><h3 class="title"><a id="_charinfo"></a>3.3. CharInfo</h3></div></div></div><p>For each unicode character in the input, there is a CharInfo structure that can be queried for such information as the code unit position in the input string, the before slot index (if we are before this character, which is the earliest slot we are before) and the corresponding after slot index.</p></div><div class="section" title="3.4. Face"><div class="titlepage"><div><div><h3 class="title"><a id="_face"></a>3.4. Face</h3></div></div></div><p>The <code class="literal">gr_face</code> type is the memory correspondance of a font. It holds the data structures corresponding to those in a font file as required to process text using that font. In creating a <code class="literal">gr_face</code> it is necessary to pass a function by which graphite can get hold of font tables. The tables that graphite queries for must be available for the lifetime of the <code class="literal">gr_face</code>, except when a <code class="literal">gr_face</code> is created with the faceOptions of <code class="literal">gr_face_preloadAll</code>. This then loads everything from the font at <code class="literal">gr_face</code> construction time, leaving nothing further to be read from the font when the <code class="literal">gr_face</code> is used. This reduces the required lifetime of the in memory font tables to the <code class="literal">gr_make_face</code> call. In situations where the tables are only stored for the purposes of creating a <code class="literal">gr_face</code>, it can save memory to preload everything and delete the tables.</p></div><div class="section" title="3.5. Caching"><div class="titlepage"><div><div><h3 class="title"><a id="_caching"></a>3.5. Caching</h3></div></div></div><p>Graphite2 has the capability to make use of a subsegmental cache. What this does is to chop each run of characters at a word break, as defined by the linebreaking pass. Each sub run is then looked up in the cache rather than calculating the values from scratch. The cache is most effective when similar runs of text are processed. For raw benchmark testing against wordlists, the cache can be slightly slower than uncached processing. But most people use real text in their documents and that has a much higher level of redundancy.</p><p>To use the cache, one simply creates a cached face, specifying the size of the cache in elements. A cache size of 5,000 to 10,000 has produced a good compromise between time and space.</p><p>In the example above, point 1 becomes:</p><pre class="screen"> gr_face *face = make_file_face_with_seg_cache(argv[1]);</pre></div><div class="section" title="3.6. Clustering"><div class="titlepage"><div><div><h3 class="title"><a id="_clustering"></a>3.6. Clustering</h3></div></div></div><p>It is common for applications to work with simplified clusters, these are sequences of glyphs associated with a sequence of characters, such that these simplified clusters are as small as possible and are never reordered or split in relation to each other. In addition, a cursor may occur between simplified clusters.</p><p>The following code gives an example algorithm for calculating such clusters:</p><pre class="programlisting">#include <graphite2/Segment.h> #include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct cluster_t { unsigned int base_char; unsigned int num_chars; unsigned int base_glyph; unsigned int num_glyphs; } cluster_t; /* usage: ./cluster fontfile.ttf string */ int main(int argc, char **argv) { int rtl = 0; /* are we rendering right to left? probably not */ int pointsize = 12; /* point size in points */ int dpi = 96; /* work with this many dots per inch */ char *pError; /* location of faulty utf-8 */ gr_font *font = NULL; size_t numCodePoints = 0; gr_segment * seg = NULL; cluster_t *clusters; int ic, ci = 0; const gr_slot *s, *is; FILE *log; gr_face *face = gr_make_file_face(argv[1], 0); if (!face) return 1; font = gr_make_font(pointsize * dpi / 72.0f, face); if (!font) return 2; numCodePoints = gr_count_unicode_characters(gr_utf8, argv[2], NULL, (const void **)(&pError)); if (pError || !numCodePoints) return 3; seg = gr_make_seg(font, face, 0, 0, gr_utf8, argv[2], numCodePoints, rtl); /*<a id="CO2-1"></a><img src="./images/icons/callouts/1.png" alt="1" border="0" />*/ if (!seg) return 3; clusters = (cluster_t *)malloc(numCodePoints * sizeof(cluster_t)); memset(clusters, 0, numCodePoints * sizeof(cluster_t)); for (is = gr_seg_first_slot(seg), ic = 0; is; is = gr_slot_next_in_segment(is), ic++) { unsigned int before = gr_slot_before(is); unsigned int after = gr_slot_after(is); while (clusters[ci].base_char > before && ci) /*<a id="CO2-2"></a><img src="./images/icons/callouts/2.png" alt="2" border="0" />*/ { clusters[ci-1].num_chars += clusters[ci].num_chars; clusters[ci-1].num_glyphs += clusters[ci].num_glyphs; --ci; } if (gr_slot_can_insert_before(is) && clusters[ci].num_chars && before >= clusters[ci].base_char + clusters[ci].num_chars) /*<a id="CO2-3"></a><img src="./images/icons/callouts/3.png" alt="3" border="0" />*/ { cluster_t *c = clusters + ci + 1; c->base_char = clusters[ci].base_char + clusters[ci].num_chars; c->num_chars = before - c->base_char; c->base_glyph = ic; c->num_glyphs = 0; ++ci; } ++clusters[ci].num_glyphs; if (clusters[ci].base_char + clusters[ci].num_chars < after + 1) /*<a id="CO2-4"></a><img src="./images/icons/callouts/4.png" alt="4" border="0" />*/ clusters[ci].num_chars = after + 1 - clusters[ci].base_char; } ci = 0; log = fopen("cluster.log", "w"); for (s = gr_seg_first_slot(seg); s; s = gr_slot_next_in_segment(s)) { fprintf(log, "%d(%f,%f) ", gr_slot_gid(s), gr_slot_origin_X(s), gr_slot_origin_Y(s)); if (--clusters[ci].num_glyphs == 0) /*<a id="CO2-5"></a><img src="./images/icons/callouts/5.png" alt="5" border="0" />*/ { fprintf(log, "\n"); ++ci; } } fclose(log); free(clusters); gr_seg_destroy(seg); gr_font_destroy(font); gr_face_destroy(face); return 0; }</pre><div class="calloutlist"><table border="0" summary="Callout list"><tr><td width="5%" valign="top" align="left"><p><a href="#CO2-1"><img src="./images/icons/callouts/1.png" alt="1" border="0" /></a> </p></td><td valign="top" align="left"> Create a segment as per the example in the introduction. </td></tr><tr><td width="5%" valign="top" align="left"><p><a href="#CO2-2"><img src="./images/icons/callouts/2.png" alt="2" border="0" /></a> </p></td><td valign="top" align="left"> If this slot starts before the start of this cluster, then merge this cluster with the previous one and try again until this slot is within the current cluster. </td></tr><tr><td width="5%" valign="top" align="left"><p><a href="#CO2-3"><img src="./images/icons/callouts/3.png" alt="3" border="0" /></a> </p></td><td valign="top" align="left"> If this slot starts after the end of the current cluster, then create a new cluster for it. </td></tr><tr><td width="5%" valign="top" align="left"><p><a href="#CO2-4"><img src="./images/icons/callouts/4.png" alt="4" border="0" /></a> </p></td><td valign="top" align="left"> If this slot ends after the end of this cluster then extend this cluster to include it. </td></tr><tr><td width="5%" valign="top" align="left"><p><a href="#CO2-5"><img src="./images/icons/callouts/5.png" alt="5" border="0" /></a> </p></td><td valign="top" align="left"> Output a line break between each cluster. </td></tr></table></div></div><div class="section" title="3.7. Line Breaking and Justification"><div class="titlepage"><div><div><h3 class="title"><a id="_line_breaking_and_justification"></a>3.7. Line Breaking and Justification</h3></div></div></div><p>Whilst most applications will convert glyphs and positions out of the gr_slot structure into some internal structure, if graphite is to be used for justification, then it is necessary to line break the text and justify it within graphite’s data structures. Graphite provides two functions to help with this. The first is gr_slot_linebreak_before() which will chop the slot linked list before a given slot. The application needs to keep track of the start of each of the subsequent linked lists itself, since graphite does not do that. After line breaking, the application may call gr_seg_justify() on each line linked list. The following example shows how this might be done in an application.</p><p>Notice that this example does not take into considering whitespace hanging outside the right margin.</p><pre class="programlisting">#include <graphite2/Segment.h> #include <stdio.h> #include <stdlib.h> /* usage: ./linebreak fontfile.ttf width string */ int main(int argc, char **argv) { int rtl = 0; /* are we rendering right to left? probably not */ int pointsize = 12; /* point size in points */ int dpi = 96; /* work with this many dots per inch */ int width = atoi(argv[2]) * dpi / 72; /* linewidth in points */ char *pError; /* location of faulty utf-8 */ gr_font *font = NULL; size_t numCodePoints = 0; gr_segment * seg = NULL; const gr_slot *s, *sprev; int i; int lineend = width; int numlines = 0; const gr_slot **lineslots; gr_face *face = gr_make_file_face(argv[1], 0); if (!face) return 1; font = gr_make_font(pointsize * dpi / 72.0f, face); if (!font) return 2; numCodePoints = gr_count_unicode_characters(gr_utf8, argv[3], NULL, (const void **)(&pError)); if (pError) return 3; seg = gr_make_seg(font, face, 0, 0, gr_utf8, argv[3], numCodePoints, rtl); /*<a id="CO3-1"></a><img src="./images/icons/callouts/1.png" alt="1" border="0" />*/ if (!seg) return 3; lineslots = (const gr_slot **)malloc(numCodePoints * sizeof(gr_slot *)); lineslots[numlines++] = gr_seg_first_slot(seg); /*<a id="CO3-2"></a><img src="./images/icons/callouts/2.png" alt="2" border="0" />*/ for (s = lineslots[0]; s; s = gr_slot_next_in_segment(s)) { sprev = NULL; if (gr_slot_origin_X(s) > lineend) /*<a id="CO3-3"></a><img src="./images/icons/callouts/3.png" alt="3" border="0" />*/ { for (sprev = gr_slot_prev_in_segment(s); sprev; /*<a id="CO3-4"></a><img src="./images/icons/callouts/4.png" alt="4" border="0" />*/ s = sprev, sprev = gr_slot_prev_in_segment(sprev)) { int bw = gr_cinfo_break_weight(gr_seg_cinfo(seg, gr_slot_before(s))); if (bw < -15) /*<a id="CO3-5"></a><img src="./images/icons/callouts/5.png" alt="5" border="0" />*/ continue; bw = gr_cinfo_break_weight(gr_seg_cinfo(seg, gr_slot_after(sprev))); if (bw > 15) continue; break; } lineslots[numlines++] = s; gr_slot_linebreak_before((gr_slot *)s); /*<a id="CO3-6"></a><img src="./images/icons/callouts/6.png" alt="6" border="0" />*/ lineend = gr_slot_origin_X(s) + width; /*<a id="CO3-7"></a><img src="./images/icons/callouts/7.png" alt="7" border="0" />*/ } } printf("%d:", width); for (i = 0; i < numlines; i++) { gr_seg_justify(seg, (gr_slot *)lineslots[i], font, width, 0, NULL, NULL); /*<a id="CO3-8"></a><img src="./images/icons/callouts/8.png" alt="8" border="0" />*/ for (s = lineslots[i]; s; s = gr_slot_next_in_segment(s)) /*<a id="CO3-9"></a><img src="./images/icons/callouts/9.png" alt="9" border="0" />*/ printf("%d(%.2f,%.2f@%d) ", gr_slot_gid(s), gr_slot_origin_X(s), gr_slot_origin_Y(s), gr_slot_attr(s, seg, gr_slatJWidth, 0)); printf("\n"); } free(lineslots); gr_font_destroy(font); gr_face_destroy(face); return 0; }</pre><div class="calloutlist"><table border="0" summary="Callout list"><tr><td width="5%" valign="top" align="left"><p><a href="#CO3-1"><img src="./images/icons/callouts/1.png" alt="1" border="0" /></a> </p></td><td valign="top" align="left"> Create a segment as per the example in the introduction </td></tr><tr><td width="5%" valign="top" align="left"><p><a href="#CO3-2"><img src="./images/icons/callouts/2.png" alt="2" border="0" /></a> </p></td><td valign="top" align="left"> Create an area to store line starts. There won’t be more line starts than characters in the text. The first line starts at the start of the segment. </td></tr><tr><td width="5%" valign="top" align="left"><p><a href="#CO3-3"><img src="./images/icons/callouts/3.png" alt="3" border="0" /></a> </p></td><td valign="top" align="left"> Scan through the slots, if we are past the end of the line then find somewhere to chop. </td></tr><tr><td width="5%" valign="top" align="left"><p><a href="#CO3-4"><img src="./images/icons/callouts/4.png" alt="4" border="0" /></a> </p></td><td valign="top" align="left"> Scan backwards for a valid linebreak location. </td></tr><tr><td width="5%" valign="top" align="left"><p><a href="#CO3-5"><img src="./images/icons/callouts/5.png" alt="5" border="0" /></a> </p></td><td valign="top" align="left"> We use 15 (syllable break) as an appropriate break value. A negative value means the break constraint is before the slot, so we test that. Likewise for after we test for a positive value. </td></tr><tr><td width="5%" valign="top" align="left"><p><a href="#CO3-6"><img src="./images/icons/callouts/6.png" alt="6" border="0" /></a> </p></td><td valign="top" align="left"> Break the line here. </td></tr><tr><td width="5%" valign="top" align="left"><p><a href="#CO3-7"><img src="./images/icons/callouts/7.png" alt="7" border="0" /></a> </p></td><td valign="top" align="left"> Update the line width for the new line based on the start of the new line. </td></tr><tr><td width="5%" valign="top" align="left"><p><a href="#CO3-8"><img src="./images/icons/callouts/8.png" alt="8" border="0" /></a> </p></td><td valign="top" align="left"> Justify each line to be width wide. And tell it to skip final whitespace (as if that whitespace were outside the width). </td></tr><tr><td width="5%" valign="top" align="left"><p><a href="#CO3-9"><img src="./images/icons/callouts/9.png" alt="9" border="0" /></a> </p></td><td valign="top" align="left"> Each line is a complete linked list that we can iterate over. We can no longer iterate over the whole segment. We have to do it line by line now. </td></tr></table></div></div><div class="section" title="3.8. Bidi"><div class="titlepage"><div><div><h3 class="title"><a id="_bidi"></a>3.8. Bidi</h3></div></div></div><p>Bidirectional processing is complex not so much because of any algorithms involved, but because of the tendency for applications to address bidi text processing differently. Some try to do everything themselves, inverting the text order, etc. While others do nothing, expecting the shaper to resolve all the orders. In addition, there is the question of mirroring characters and where that is done. Graphite2 adds the complexity that it tries to enable extensions to the bidi algorithm by giving PUA characters directionality. To facilitate all these different ways of working, Graphite2 uses the <code class="literal">rtl</code> attribute to pass various bits to control bidi processing within the Graphite engine.</p><div class="informaltable"><table cellpadding="4px" style="border-collapse: collapse;border-top: 2px solid #527bbd; border-bottom: 2px solid #527bbd; border-left: 2px solid #527bbd; border-right: 2px solid #527bbd; "><colgroup><col width="42pt" class="col_1" /><col width="63pt" class="col_2" /><col width="318pt" class="col_3" /></colgroup><thead><tr><th style="border-right: 1px solid ; border-bottom: 1px solid ; " align="center" valign="top">gr_nobidi </th><th style="border-right: 1px solid ; border-bottom: 1px solid ; " align="center" valign="top">gr_nomirror </th><th style="border-bottom: 1px solid ; " align="left" valign="top">Description</th></tr></thead><tbody><tr><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="center" valign="top"><p>0</p></td><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="center" valign="top"><p>0</p></td><td style="border-bottom: 1px solid ; " align="left" valign="top"><p>Runs the bidi algorithm and does all mirroring</p></td></tr><tr><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="center" valign="top"><p>0</p></td><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="center" valign="top"><p>1</p></td><td style="border-bottom: 1px solid ; " align="left" valign="top"><p>Runs the bidi algorithm and mirrors those chars that don’t have char replacements. It also un/remirrors anything that ends up in the opposite direction to the stated text direction on input.</p></td></tr><tr><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="center" valign="top"><p>1</p></td><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="center" valign="top"><p>0</p></td><td style="border-bottom: 1px solid ; " align="left" valign="top"><p>Doesn’t run the bidi algorithm but does do mirroring of all characters if direction is rtl.</p></td></tr><tr><td style="border-right: 1px solid ; " align="center" valign="top"><p>1</p></td><td style="border-right: 1px solid ; " align="center" valign="top"><p>1</p></td><td style="" align="left" valign="top"><p>Doesn’t run the bidi algorithm and only mirrors those glyphs for which there is no corresponding mirroring character.</p></td></tr></tbody></table></div></div></div><div class="section" title="4. Font Features"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_font_features"></a>4. Font Features</h2></div></div></div><p>Graphite fonts have user features. These are values that can be set to control all kinds of rendering effects from choosing particular glyph styles for a group of languages to how bad sequences should be displayed to almost anything.</p><p>A font (strictly speaking a face) has a set of features. Each feature has an identifier which is a 32-bit number which can take the form of a tag (4 characters) or if the top byte is 0 a number. Also each feature can take one of a set of values. Each feature has a UI name from the name table. In addition each value also has a UI name associated with it. This allows an application to list all the features in a font and to show their names and values in a user interface to allow user selection.</p><p>Feature values are held in a FeatureVal which is a compressed map of feature id to value. The map is indexed via a FeatureRef which may be quered from a face given an id. It is also possible to iterate over all the FeatureRefs in a face.</p><p>A face has a default featureVal corresponding to each language the face supports along with a default for other languages. A face may be asked for a copy of one of these default featureVals and then it may be modified to account for the specific feature settings for a run.</p><pre class="programlisting">#include <graphite2/Font.h> #include <stdio.h> int main(int argc, char **argv) { gr_uint16 i; gr_uint16 langId = 0x0409; gr_uint32 lang = 0; char idtag[5] = {0, 0, 0, 0, 0}; /*<a id="CO4-1"></a><img src="./images/icons/callouts/1.png" alt="1" border="0" />*/ gr_feature_val *features = NULL; gr_face *face = gr_make_file_face(argv[1], 0); int num = gr_face_n_fref(face); if (!face) return 1; if (argc > 2) lang = gr_str_to_tag(argv[2]); features = gr_face_featureval_for_lang(face, lang); /*<a id="CO4-2"></a><img src="./images/icons/callouts/2.png" alt="2" border="0" />*/ if (!features) return 2; for (i = 0; i < num; ++i) { const gr_feature_ref *fref = gr_face_fref(face, i); /*<a id="CO4-3"></a><img src="./images/icons/callouts/3.png" alt="3" border="0" />*/ gr_uint32 length = 0; char *label = gr_fref_label(fref, &langId, gr_utf8, &length); /*<a id="CO4-4"></a><img src="./images/icons/callouts/4.png" alt="4" border="0" />*/ gr_uint32 id = gr_fref_id(fref); /*<a id="CO4-5"></a><img src="./images/icons/callouts/5.png" alt="5" border="0" />*/ gr_uint16 val = gr_fref_feature_value(fref, features); int numval = gr_fref_n_values(fref); int j; printf("%s ", label); gr_label_destroy(label); if (id <= 0x00FFFFFF) printf("(%d)\n", id); else { gr_tag_to_str(id, idtag); printf("(%s)\n", idtag); } for (j = 0; j < numval; ++j) { if (gr_fref_value(fref, j) == val) /*<a id="CO4-6"></a><img src="./images/icons/callouts/6.png" alt="6" border="0" />*/ { label = gr_fref_value_label(fref, j, &langId, gr_utf8, &length); printf("\t%s (%d)\n", label, val); gr_label_destroy(label); } } } gr_featureval_destroy(features); gr_face_destroy(face); return 0; }</pre><div class="calloutlist"><table border="0" summary="Callout list"><tr><td width="5%" valign="top" align="left"><p><a href="#CO4-1"><img src="./images/icons/callouts/1.png" alt="1" border="0" /></a> </p></td><td valign="top" align="left"> The easiest way to turn a char[4] into a string is to append a nul, hence we make a char[5]. </td></tr><tr><td width="5%" valign="top" align="left"><p><a href="#CO4-2"><img src="./images/icons/callouts/2.png" alt="2" border="0" /></a> </p></td><td valign="top" align="left"> Query the face for the default featureVal of the given lang or 0 for the default. The lang is a uint32 which has been converted from the string and is 0 padded (as opposed to space padded). </td></tr><tr><td width="5%" valign="top" align="left"><p><a href="#CO4-3"><img src="./images/icons/callouts/3.png" alt="3" border="0" /></a> </p></td><td valign="top" align="left"> Iterate over all the features in a font querying for the featureRef. </td></tr><tr><td width="5%" valign="top" align="left"><p><a href="#CO4-4"><img src="./images/icons/callouts/4.png" alt="4" border="0" /></a> </p></td><td valign="top" align="left"> Get the label in US English, for the feature name. </td></tr><tr><td width="5%" valign="top" align="left"><p><a href="#CO4-5"><img src="./images/icons/callouts/5.png" alt="5" border="0" /></a> </p></td><td valign="top" align="left"> Get the id for the feature name so that applications can refer to it. The id may be numeric or a string tag. </td></tr><tr><td width="5%" valign="top" align="left"><p><a href="#CO4-6"><img src="./images/icons/callouts/6.png" alt="6" border="0" /></a> </p></td><td valign="top" align="left"> Iterate over all the possible values for this feature and find the one the is equal to the value for the feature in the default featureVal. Then print out its details. </td></tr></table></div><p>A sample run of.</p><pre class="screen">./features ../fonts/Padauk.ttf ksw</pre><p>Gives this output.</p><pre class="screen">Khamti style dots (kdot) False (0) Filled dots (fdot) False (0) Lower dot shifts left (lldt) True (1) Tear drop style washwe (wtri) True (1) Long U with Yayit, long UU with Hato (ulon) False (0) U and UU always full height (utal) False (0) Insert dotted circles for errors (dotc) True (1) Slanted hato (hsln) Sgaw style slanted leg with horizontal foot (1) Disable great nnya (nnya) False (0) Variant tta (vtta) False (0)</pre></div><div class="section" title="5. Hacking"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_hacking"></a>5. Hacking</h2></div></div></div><p>In this section we look at coding conventions and some of the design models used in coding graphiteng.</p><div class="section" title="5.1. Compiling and Integrating"><div class="titlepage"><div><div><h3 class="title"><a id="_compiling_and_integrating"></a>5.1. Compiling and Integrating</h3></div></div></div><p>To compile the graphite2 library for integration into another application framework, there are some useful utilities and also various definitions that need to be defined. The file src/files.mk will create three make variables containing lists of files that someone will want to build in order to build graphite2 from source as part of an application build. The variable names are controlled by setting _NS to a prefix that is then applied to the variable names _SOURCES, _PRIVATE_HEADERS and _PUBLIC_HEADERS. All files are listed relative to the variable _BASE (with its _NS expansion prefix). The _MACHINE variable with its _NS expansion prefix, must be set to <span class="emphasis"><em>call</em></span> or <span class="emphasis"><em>direct</em></span> depending on which kind of virtual machine to use inside the engine. gcc supports direct call, while all other compilers without a computed goto should use the call style virtual machine. See src/direct_machine.cpp and src/call_machine.cpp for details.</p><p>Various C preprocessor definitions are also used as part of compiling graphite2:</p><div class="variablelist"><dl><dt><span class="term"> DISABLE_SEGCACHE </span></dt><dd> If set, the segment caching code is not compiled into the library. This can be used to save space if the engine is under space constraints both for code and memory. The default is that this is not defined. </dd><dt><span class="term"> DISABLE_TRACING </span></dt><dd> If set, no tracing code is compiled into the library, to save code space and increase speed. By default this is not set. </dd><dt><span class="term"> ENABLE_DEEP_TRACING </span></dt><dd> Only used if DISABLE_TRACING is undefined. It enables extra tracing code that will give considerable output at considerable time cost. By default this is not set. </dd><dt><span class="term"> DISABLE_FILEFACE </span></dt><dd> If set, the code to support creating a face directly from a font file is not included in the library. By default this is not set. </dd></dl></div></div><div class="section" title="5.2. Memory Allocation"><div class="titlepage"><div><div><h3 class="title"><a id="_memory_allocation"></a>5.2. Memory Allocation</h3></div></div></div><p>While GraphiteNG is written in C++, it is targetted at environments where libstdc++ is not present. While this can be problematic since functions used in C++ may be arbitrarily placed in libc and libstdc++, there are general approaches that can help. To this end we use a mixed memory allocation model. For graphiteng classes, we declare our own new() methods and friends, allowing the use of C++ new() and all that it gives us in terms of constructors. For types that are not classes we use malloc() or the type safe version gralloc().</p></div><div class="section" title="5.3. Missing Features"><div class="titlepage"><div><div><h3 class="title"><a id="_missing_features"></a>5.3. Missing Features</h3></div></div></div><p>There are various facilities that silgraphite provides that graphite2 as yet does not. The primary motivation in developing graphite2 is that it be use case driven. Thus only those facilities that have a proven use case in the target applications into which graphite is to be integrated will be implemented.</p><div class="variablelist"><dl><dt><span class="term"> Justification </span></dt><dd> Silgraphite has the ability to handle complex justification. This is not part of graphite2 yet. But then neither were any external applications making use of this facility within silgraphite. </dd><dt><span class="term"> Line End Contextuals </span></dt><dd> The cost of implementing line end contextuals is high and no fonts actually make use of it or need to make use of it. If the need were to rearise, line end contextuals could be integrated with a justification pass. </dd><dt><span class="term"> Ligature Components </span></dt><dd> Graphite has the ability to track ligature components and this feature is used in some fonts. But application support has yet to be proven and this is an issue looking for a use case and appropriate API. </dd><dt><span class="term"> SegmentPainter </span></dt><dd> Silgraphite provides a helper class to do range selection, cursor hitting and support text editing within a segment. These facilities were not being used in applications. Graphite2 does not preclude the addition of such a helper class if it would be of help to different applications, since it would be layered on top of graphite2. </dd><dt><span class="term"> Hinted Attachment Points </span></dt><dd> No use has been made of hinted attachment points, and so until a real use case requirement is proven, these are not in the font api. They can be added should a need be proven. </dd></dl></div></div><div class="section" title="5.4. Hunting Speed"><div class="titlepage"><div><div><h3 class="title"><a id="_hunting_speed"></a>5.4. Hunting Speed</h3></div></div></div><p>Graphite2 is written based on experience of using SilGraphite. SilGraphite was written primarily to be feature complete in terms of all features that may be needed. Graphite2 takes the experience of using SilGraphite and starts from a use case requirement before a feature is added to the engine. Thus a number of features that have not been used in SilGraphite have been removed, although the design is such that they can be replaced in future.</p><p>In addition, a number of techniques were used to speed up the engine. Some of these are discussed here.</p><div class="variablelist"><dl><dt><span class="term"> Slot Stream </span></dt><dd> Rather than copying slots from one stream to another, the slot stream is allocated in blocks of slots and the processing is done in place. This means that each pass is executed to completion in sequence rather than using a pull model that SilGraphite uses. In addition, the slot stream is held as a linked list to keep the cost of insertion and deletion down for large segments. </dd><dt><span class="term"> Virtual Machine </span></dt><dd> The virtual machine that executes action and condition code is optimised for speed with different versions of the core engine code being used dependent upon compiler. The interpretted code is also pre-analysed for checking purposes and even some commands are added necessary for the inplace editing of the slot stream. </dd><dt><span class="term"> Design Space Positioning </span></dt><dd> The nature of the new processing model is that all concrete positioning is done in a final finalisation process. This means that all passes can be run in design space and then only at finalisation positioned in pixel space. </dd></dl></div></div></div><div class="section" title="6. Android"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="_android"></a>6. Android</h2></div></div></div><p>Included in the contribs section of the Graphite2 source code is a way of integrating the Graphite2 library into an android application. It is known to work for Android 2.2 - Android 2.3.1 (API levels 8-10).</p><p>The sample application shows how it might be used.</p><pre class="programlisting">/* GRAPHITE2 LICENSING Copyright 2010, SIL International All rights reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should also have received a copy of the GNU Lesser General Public License along with this library in the file named "LICENSE". If not, write to the Free Software Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA or visit their web page on the internet at http://www.fsf.org/licenses/lgpl.html. Alternatively, you may use this library under the terms of the Mozilla Public License (http://mozilla.org/MPL) or under the GNU General Public License, as published by the Free Sofware Foundation; either version 2 of the license or (at your option) any later version. */ package org.sil.palaso.helloworld; import android.app.Activity; import android.graphics.Typeface; import android.os.Bundle; import android.webkit.WebView; import android.widget.TextView; import org.sil.palaso.Graphite; public class HelloWorld extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { Graphite.loadGraphite(); // <a id="CO5-1"></a><img src="./images/icons/callouts/1.png" alt="1" border="0" /> Typeface tfp = (Typeface)Graphite.addFontResource(getAssets(), "Padauk.ttf", "padauk", 0); // <a id="CO5-2"></a><img src="./images/icons/callouts/2.png" alt="2" border="0" /> Typeface tfa = (Typeface)Graphite.addFontResource(getAssets(), "Scheherazadegr.ttf", "Scheh", 1); TextView tv; WebView wv; // String s = "မဂင်္ဂလာ|မဘ္ဘာ၊ ဤကဲ့|သို့|ရာ|ဇ|ဝင်|တင်|မည့် ကြေ|ညာ|ချက်|ကို ပြု|လုပ်|ပြီး|နောက် ဤညီ|လာ|ခံ|အ|စည်း|အ|ဝေး|ကြီး|က ကမ္ဘာ့|ကု|လ|သ|မဂ္ဂ|အ|ဖွဲ့|ဝင် နိုင်|ငံ အား|လုံး|အား ထို|ကြေ|ညာ|စာ|တမ်း|ကြီး၏ စာ|သား|ကို|အ|များ|ပြည်|သူ|တို့ ကြား|သိ|စေ|ရန် ကြေ|ညာ|ပါ|မည့် အ|ကြောင်း|ကို|လည်း|ကောင်း၊ ထို့|ပြင်|နိုင်|ငံ|များ၊ သို့|တည်း|မ|ဟုတ် နယ်|မြေ|များ၏ နိုင်|ငံ|ရေး အ|ဆင့်|အ|တ|န်း|ကို လိုက်၍ ခွဲ|ခြား|ခြင်း မ|ပြု|ဘဲ|အ|ဓိ|က|အား|ဖြင့် စာ|သင်|ကျောင်း|များ|နှင့် အ|ခြား|ပ|ညာ|ရေး အ|ဖွဲ့|အ|စည်း|များ|တွင် ထို|ကြေ|ညာ|စာ|တမ်း|ကြီး|ကို ဖြန့်|ချိ ဝေ|ငှ စေ|ရန်၊ မြင်|သာ|အောင် ပြ|သ|ထား|စေ|ရန်၊|ဖတ်|ကြား|စေ|ရန်|နှင့် အ|ဓိပ္ပါယ်|ရှင်း|လင်း ဖော်|ပြ|စေ|ရန် ဆောင်|ရွက်|ပါ|မည့် အ|ကြောင်း|ဖြင့် လည်း|ကောင်း ဆင့်|ဆို လိုက်|သည်။".replace("|", "\u200B"); String s = "لمّا كان الاعتراف بالكرامة المتأصلة في جميع أعضاء الأسرة (البشرية) وبحقوقهم المتساوية الثابتة هو أساس الحرية والعدل \u06F1\u06F2\u06F3 والسلام في العالم."; String w = "\uFEFF<html><body style=\"font-family: Scheh\">Test: " + s + "</body></html>"; // <a id="CO5-3"></a><img src="./images/icons/callouts/3.png" alt="3" border="0" /> super.onCreate(savedInstanceState); setContentView(R.layout.main); tv = (TextView) findViewById(R.id.tv); tv.setText(s); tv.setTypeface(tfa, 0); // <a id="CO5-4"></a><img src="./images/icons/callouts/4.png" alt="4" border="0" /> tv.setTextSize((float)(tv.getTextSize() * 1.2)); wv = (WebView) findViewById(R.id.wv); wv.loadData(w, "text/html", "UTF-8"); } }</pre><div class="calloutlist"><table border="0" summary="Callout list"><tr><td width="5%" valign="top" align="left"><p><a href="#CO5-1"><img src="./images/icons/callouts/1.png" alt="1" border="0" /></a> </p></td><td valign="top" align="left"> This sets up the graphite redirection for the core graphics layer. </td></tr><tr><td width="5%" valign="top" align="left"><p><a href="#CO5-2"><img src="./images/icons/callouts/2.png" alt="2" border="0" /></a> </p></td><td valign="top" align="left"> The graphite integration needs to be informed of the fonts we intend to use The fonts are included in the assets/ directory and we give the filename, then an identifier to use for the font within web styling, followed by whether the font is presumed to be rendering right to left or left to right text. </td></tr><tr><td width="5%" valign="top" align="left"><p><a href="#CO5-3"><img src="./images/icons/callouts/3.png" alt="3" border="0" /></a> </p></td><td valign="top" align="left"> Here we package the simple text as HTML and set the font. Notice how the font-family: parameter corresponds to the font identifier in <2>. </td></tr><tr><td width="5%" valign="top" align="left"><p><a href="#CO5-4"><img src="./images/icons/callouts/4.png" alt="4" border="0" /></a> </p></td><td valign="top" align="left"> Registering a font also returns a Typeface for the font and this can be used to set the typeface for a widget. </td></tr></table></div></div></div></body></html>