2 * syriac-ot.h: Determine what OpenType features to apply to characters based
3 * on the rules for Syriac from the OpenType standard.
5 * Copyright (C) 2004 Emil Soleyman-Zomalan
6 * Author: Emil Soleyman-Zomalan <emil@soleyman.com>
8 * This file is based on the Arabic shaping code from FreeType 1 tree; original
11 * The FreeType project -- a free and portable quality TrueType renderer.
13 * Copyright 1996-2000 by
14 * D. Turner, R.Wilhelm, and W. Lemberg
16 * The code, like the FreeType code it is derived from is dual-licensed
17 * under the GNU General Public License and the FreeType license. See
18 * pango/opentype/COPYING for full details of this licensing scheme.
21 #include "syriac-ot.h"
23 /* Here a table of the joining classes for characters in the range
26 * The following character also has a joining class:
28 * U+200C ZERO WIDTH NON-JOINER -> causing
30 * All other characters are given the joining class `none'.
32 static const JoiningClass syriac[] =
35 none, none, none, none,
36 none, none, none, none,
37 none, none, none, none,
38 none, none, none, transparent,
41 right, none, dual, dual,
42 dual, right, right, right,
43 right, right, dual, dual,
44 dual, dual, right, dual,
47 dual, dual, dual, dual,
48 dual, dual, dual, dual,
49 right, dual, right, dual,
50 right, none, none, none,
53 transparent, transparent, transparent, transparent,
54 transparent, transparent, transparent, transparent,
55 transparent, transparent, transparent, transparent,
56 transparent, transparent, transparent, transparent,
59 transparent, transparent, transparent, transparent,
60 transparent, transparent, transparent, transparent,
61 transparent, transparent, transparent, none,
62 none, right, dual, dual
65 /* `direction' can be -1, 0, or 1 to indicate the last non-transparent
66 * glyph, the current glyph, and the next non-transparent glyph,
70 Get_Joining_Class (gunichar* string,
79 if (pos == 0 && direction < 0)
87 if (string[pos] < 0x0700 ||
88 string[pos] >= 0x074F)
90 if (string[pos] == 0x200C)
96 j = syriac[string[pos] - 0x0700];
98 if (!direction || j != transparent)
104 /* The rules here are roughly based on the Arabic rules from the Unicode
105 * 2.0 standard (which differ from the Unicode-4.0 rules), augmented
106 * with the Syriac rules from the Unicode-4.0 standard. The numbers
107 * R1...R11 below do not correspond to either the Arabic or the Syriac
108 * rule numbering from the Unicode standard.
110 * Characters are here specified as appearing in the byte stream, i.e.
111 * *not* in visual order. Joining classes are given in angle brackets,
112 * glyph forms in square brackets. Glyphs affected by a specific rule are
113 * enclosed with vertical bars.
116 * Glyphs: 0x0715 (Dalath), 0x0716 (Dalath Rish), 0x072A (Rish),
117 * 0x0722 (Nun), 0x071F (Kaph)
120 * R1: <anything1> <transparent> <anything2>
122 * apply joining rules for
123 * <anything1> <anything2> -> [shape1] [shape2]
124 * -> [shape1] [isolated] [shape2]
127 * R2: <causing|right> <0x0722|0x071F> <!(causing|right|dual)>
130 * The Nun and Kaph characters each have 3 different glyphs
131 * with two of those glyphs coming at the final position.
132 * However, one of those final glyphs should really be of the
133 * isolated glyph form where the preceding character cannot be
134 * joined to and there is no next character.
136 * This rule exists to combine similar exception for both
137 * characters without increasing the complexity in the other
141 * R3: <causing|right|dual> && <!(0x0715|0x0716|0x072A)> |<alaph>|
145 * If the preceding glyph cannot be joined to the current
146 * glyph and the preceding character is not a Dalath, Rish,
147 * or Dotless Dalath Rish, then the Alaph takes this contextual
150 * The [final2] joining rule is placed ahead of the [final] to
151 * give it greater precedence when choosing the correct glyph.
152 * If it comes after the [final] rule, the incorrect glyph is
153 * inserted into position.
156 * R4: <0x0715|0x0715|0x072A> |<alaph>|
160 * If the previous glyph is a Dalath, Rish, or Dotless Dalath
161 * Rish, then the Alaph takes this contextual position.
163 * The [final3] joining rule is placed ahead of the [final] to
164 * give it greater precedence when choosing the correct glyph.
165 * If it comes after the [final] rule, the incorrect glyph is
166 * inserted into position.
169 * R5: <causing|right|dual> |<right>|
174 * R6: <causing|right|dual> |<dual>| <!(causing|right|dual)>
179 * R7: <causing|left|dual> |<dual>| <causing|right|dual>
184 * R8: <causing|right> |<alaph>| <causing|right|dual>
188 * If the Alaph glyph falls in the middle of a Syriac word and
189 * the preceding character cannot be joined to, then the Alaph
190 * takes this contextual position.
193 * R9: |<left>| <causing|right|dual>
198 * R10: <!(causing|left|dual)> |<dual>| <causing|right|dual>
203 * R11: <anything> -> [isolated]
205 * This joining rule is placed at the end of these features
206 * because when it is placed at the beginning of all of them
207 * it tends to break the cursive nature of Syriac writing --
208 * it inserts the isolated glyph of each character into that
209 * position with no joining occurring all throughout a text
214 syriac_assign_properties (gunichar *string,
218 JoiningClass previous, current, next;
221 if (!string || !properties || length == 0)
222 return FT_Err_Invalid_Argument;
224 for (i = 0; i < length; i++)
226 previous = Get_Joining_Class (string, i, length, -1);
227 current = Get_Joining_Class (string, i, length, 0);
228 next = Get_Joining_Class (string, i, length, 1);
232 if (current == transparent)
234 properties[i] |= isolated_p;
240 if (string[i] == 0x0722 ||
242 if (previous == causing ||
244 if (!(next == causing ||
248 properties[i] |= isolated_p;
254 if (string[i] == 0x0710)
255 if (previous == causing ||
257 if (!(string[i - 1] == 0x0715 ||
258 string[i - 1] == 0x0716 ||
259 string[i - 1] == 0x072A))
261 properties[i] |= final2_p;
267 if (string[i] == 0x0710)
268 if (previous == causing ||
270 if (string[i - 1] == 0x0715 ||
271 string[i - 1] == 0x0716 ||
272 string[i - 1] == 0x072A)
274 properties[i] |= final3_p;
280 if (previous == causing ||
283 if (current == right)
285 properties[i] |= final_p;
291 if (previous == causing ||
295 if (!(next == causing ||
299 properties[i] |= final_p;
305 if (previous == causing ||
309 if (next == causing ||
313 properties[i] |= medial_p;
319 if (string[i] == 0x0710)
320 if (previous == causing ||
322 if (next == causing ||
326 properties[i] |= medial2_p;
333 if (next == causing ||
337 properties[i] |= initial_p;
343 if (!(previous == causing ||
347 if (next == causing ||
351 properties[i] |= initial_p;
357 properties[i] |= isolated_p;