Make cache of opentype tables in Harfbuzz face lazy
[profile/ivi/qtbase.git] / src / 3rdparty / harfbuzz / src / harfbuzz-shaper.cpp
1 /*
2  * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
3  *
4  * This is part of HarfBuzz, an OpenType Layout engine library.
5  *
6  * Permission is hereby granted, without written agreement and without
7  * license or royalty fees, to use, copy, modify, and distribute this
8  * software and its documentation for any purpose, provided that the
9  * above copyright notice and the following two paragraphs appear in
10  * all copies of this software.
11  *
12  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16  * DAMAGE.
17  *
18  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
21  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23  */
24
25 #include "harfbuzz-shaper.h"
26 #include "harfbuzz-shaper-private.h"
27
28 #include "harfbuzz-stream-private.h"
29 #include <assert.h>
30 #include <stdio.h>
31
32 #define HB_MIN(a, b) ((a) < (b) ? (a) : (b))
33 #define HB_MAX(a, b) ((a) > (b) ? (a) : (b))
34
35 // -----------------------------------------------------------------------------------------------------
36 //
37 // The line break algorithm. See http://www.unicode.org/reports/tr14/tr14-13.html
38 //
39 // -----------------------------------------------------------------------------------------------------
40
41 /* The Unicode algorithm does in our opinion allow line breaks at some
42    places they shouldn't be allowed. The following changes were thus
43    made in comparison to the Unicode reference:
44
45    EX->AL from DB to IB
46    SY->AL from DB to IB
47    SY->PO from DB to IB
48    SY->PR from DB to IB
49    SY->OP from DB to IB
50    AL->PR from DB to IB
51    AL->PO from DB to IB
52    PR->PR from DB to IB
53    PO->PO from DB to IB
54    PR->PO from DB to IB
55    PO->PR from DB to IB
56    HY->PO from DB to IB
57    HY->PR from DB to IB
58    HY->OP from DB to IB
59    NU->EX from PB to IB
60    EX->PO from DB to IB
61 */
62
63 // The following line break classes are not treated by the table:
64 //  AI, BK, CB, CR, LF, NL, SA, SG, SP, XX
65
66 enum break_class {
67     // the first 4 values have to agree with the enum in QCharAttributes
68     ProhibitedBreak,            // PB in table
69     DirectBreak,                // DB in table
70     IndirectBreak,              // IB in table
71     CombiningIndirectBreak,     // CI in table
72     CombiningProhibitedBreak    // CP in table
73 };
74 #define DB DirectBreak
75 #define IB IndirectBreak
76 #define CI CombiningIndirectBreak
77 #define CP CombiningProhibitedBreak
78 #define PB ProhibitedBreak
79
80 static const hb_uint8 breakTable[HB_LineBreak_JT+1][HB_LineBreak_JT+1] =
81 {
82 /*          OP  CL  QU  GL  NS  EX  SY  IS  PR  PO  NU  AL  ID  IN  HY  BA  BB  B2  ZW  CM  WJ  H2  H3  JL  JV  JT */
83 /* OP */ { PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, CP, PB, PB, PB, PB, PB, PB },
84 /* CL */ { DB, PB, IB, IB, PB, PB, PB, PB, IB, IB, IB, IB, DB, DB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
85 /* QU */ { PB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, IB, IB, IB, IB, IB, IB, IB, PB, CI, PB, IB, IB, IB, IB, IB },
86 /* GL */ { IB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, IB, IB, IB, IB, IB, IB, IB, PB, CI, PB, IB, IB, IB, IB, IB },
87 /* NS */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, DB, DB, DB, DB, DB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
88 /* EX */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, IB, DB, IB, DB, DB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
89 /* SY */ { IB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, IB, DB, DB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
90 /* IS */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, DB, IB, IB, DB, DB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
91 /* PR */ { IB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, IB, IB, DB, IB, IB, DB, DB, PB, CI, PB, IB, IB, IB, IB, IB },
92 /* PO */ { IB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, IB, DB, DB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
93 /* NU */ { IB, PB, IB, IB, IB, IB, PB, PB, IB, IB, IB, IB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
94 /* AL */ { IB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, IB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
95 /* ID */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, IB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
96 /* IN */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, DB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
97 /* HY */ { IB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, DB, DB, DB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
98 /* BA */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, DB, DB, DB, DB, DB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
99 /* BB */ { IB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, IB, IB, IB, IB, IB, IB, IB, PB, CI, PB, IB, IB, IB, IB, IB },
100 /* B2 */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, DB, DB, DB, DB, DB, IB, IB, DB, PB, PB, CI, PB, DB, DB, DB, DB, DB },
101 /* ZW */ { DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, PB, DB, DB, DB, DB, DB, DB, DB },
102 /* CM */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, DB, IB, IB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
103 /* WJ */ { IB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, IB, IB, IB, IB, IB, IB, IB, PB, CI, PB, IB, IB, IB, IB, IB },
104 /* H2 */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, IB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, IB, IB },
105 /* H3 */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, IB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, IB },
106 /* JL */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, IB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, IB, IB, IB, IB, DB },
107 /* JV */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, IB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, IB, IB },
108 /* JT */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, IB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, IB }
109 };
110 #undef DB
111 #undef IB
112 #undef CI
113 #undef CP
114 #undef PB
115
116 static const hb_uint8 graphemeTable[HB_Grapheme_LVT + 1][HB_Grapheme_LVT + 1] =
117 {
118 //      Other, CR,    LF,    Control,Extend,L,    V,     T,     LV,    LVT
119     { true , true , true , true , true , true , true , true , true , true  }, // Other, 
120     { true , true , true , true , true , true , true , true , true , true  }, // CR,
121     { true , false, true , true , true , true , true , true , true , true  }, // LF,
122     { true , true , true , true , true , true , true , true , true , true  }, // Control,
123     { false, true , true , true , false, false, false, false, false, false }, // Extend,
124     { true , true , true , true , true , false, true , true , true , true  }, // L, 
125     { true , true , true , true , true , false, false, true , false, true  }, // V, 
126     { true , true , true , true , true , true , false, false, false, false }, // T, 
127     { true , true , true , true , true , false, true , true , true , true  }, // LV, 
128     { true , true , true , true , true , false, true , true , true , true  }, // LVT
129 };
130     
131 static void calcLineBreaks(const HB_UChar16 *uc, hb_uint32 len, HB_CharAttributes *charAttributes)
132 {
133     if (!len)
134         return;
135
136     // ##### can this fail if the first char is a surrogate?
137     HB_LineBreakClass cls;
138     HB_GraphemeClass grapheme;
139     HB_GetGraphemeAndLineBreakClass(*uc, &grapheme, &cls);
140     // handle case where input starts with an LF
141     if (cls == HB_LineBreak_LF)
142         cls = HB_LineBreak_BK;
143
144     charAttributes[0].whiteSpace = (cls == HB_LineBreak_SP || cls == HB_LineBreak_BK);
145     charAttributes[0].charStop = true;
146
147     int lcls = cls;
148     for (hb_uint32 i = 1; i < len; ++i) {
149         charAttributes[i].whiteSpace = false;
150         charAttributes[i].charStop = true;
151
152         HB_UChar32 code = uc[i];
153         HB_GraphemeClass ngrapheme;
154         HB_LineBreakClass ncls;
155         HB_GetGraphemeAndLineBreakClass(code, &ngrapheme, &ncls);
156         charAttributes[i].charStop = graphemeTable[ngrapheme][grapheme];
157         // handle surrogates
158         if (ncls == HB_LineBreak_SG) {
159             if (HB_IsHighSurrogate(uc[i]) && i < len - 1 && HB_IsLowSurrogate(uc[i+1])) {
160                 continue;
161             } else if (HB_IsLowSurrogate(uc[i]) && HB_IsHighSurrogate(uc[i-1])) {
162                 code = HB_SurrogateToUcs4(uc[i-1], uc[i]);
163                 HB_GetGraphemeAndLineBreakClass(code, &ngrapheme, &ncls);
164                 charAttributes[i].charStop = false;
165             } else {
166                 ncls = HB_LineBreak_AL;
167             }
168         }
169
170         // set white space and char stop flag
171         if (ncls >= HB_LineBreak_SP)
172             charAttributes[i].whiteSpace = true;
173
174         HB_LineBreakType lineBreakType = HB_NoBreak;
175         if (cls >= HB_LineBreak_LF) {
176             lineBreakType = HB_ForcedBreak;
177         } else if(cls == HB_LineBreak_CR) {
178             lineBreakType = (ncls == HB_LineBreak_LF) ? HB_NoBreak : HB_ForcedBreak;
179         }
180
181         if (ncls == HB_LineBreak_SP)
182             goto next_no_cls_update;
183         if (ncls >= HB_LineBreak_CR)
184             goto next;
185
186         {
187             int tcls = ncls;
188             // for south east asian chars that require a complex (dictionary analysis), the unicode
189             // standard recommends to treat them as AL. thai_attributes and other attribute methods that
190             // do dictionary analysis can override
191             if (tcls >= HB_LineBreak_SA)
192                 tcls = HB_LineBreak_AL;
193             if (cls >= HB_LineBreak_SA)
194                 cls = HB_LineBreak_AL;
195
196             int brk = breakTable[cls][tcls];
197             switch (brk) {
198             case DirectBreak:
199                 lineBreakType = HB_Break;
200                 if (uc[i-1] == 0xad) // soft hyphen
201                     lineBreakType = HB_SoftHyphen;
202                 break;
203             case IndirectBreak:
204                 lineBreakType = (lcls == HB_LineBreak_SP) ? HB_Break : HB_NoBreak;
205                 break;
206             case CombiningIndirectBreak:
207                 lineBreakType = HB_NoBreak;
208                 if (lcls == HB_LineBreak_SP){
209                     if (i > 1)
210                         charAttributes[i-2].lineBreakType = HB_Break;
211                 } else {
212                     goto next_no_cls_update;
213                 }
214                 break;
215             case CombiningProhibitedBreak:
216                 lineBreakType = HB_NoBreak;
217                 if (lcls != HB_LineBreak_SP)
218                     goto next_no_cls_update;
219             case ProhibitedBreak:
220             default:
221                 break;
222             }
223         }
224     next:
225         cls = ncls;
226     next_no_cls_update:
227         lcls = ncls;
228         grapheme = ngrapheme;
229         charAttributes[i-1].lineBreakType = lineBreakType;
230     }
231     charAttributes[len-1].lineBreakType = HB_ForcedBreak;
232 }
233
234 // --------------------------------------------------------------------------------------------------------------------------------------------
235 //
236 // Basic processing
237 //
238 // --------------------------------------------------------------------------------------------------------------------------------------------
239
240 static inline void positionCluster(HB_ShaperItem *item, int gfrom,  int glast)
241 {
242     int nmarks = glast - gfrom;
243     assert(nmarks > 0);
244
245     HB_Glyph *glyphs = item->glyphs;
246     HB_GlyphAttributes *attributes = item->attributes;
247
248     HB_GlyphMetrics baseMetrics;
249     item->font->klass->getGlyphMetrics(item->font, glyphs[gfrom], &baseMetrics);
250
251     if (item->item.script == HB_Script_Hebrew
252         && (-baseMetrics.y) > baseMetrics.height)
253         // we need to attach below the baseline, because of the hebrew iud.
254         baseMetrics.height = -baseMetrics.y;
255
256 //     qDebug("---> positionCluster: cluster from %d to %d", gfrom, glast);
257 //     qDebug("baseInfo: %f/%f (%f/%f) off=%f/%f", baseInfo.x, baseInfo.y, baseInfo.width, baseInfo.height, baseInfo.xoff, baseInfo.yoff);
258
259     HB_Fixed size = item->font->klass->getFontMetric(item->font, HB_FontAscent) / 10;
260     HB_Fixed offsetBase = HB_FIXED_CONSTANT(1) + (size - HB_FIXED_CONSTANT(4)) / 4;
261     if (size > HB_FIXED_CONSTANT(4))
262         offsetBase += HB_FIXED_CONSTANT(4);
263     else
264         offsetBase += size;
265     //qreal offsetBase = (size - 4) / 4 + qMin<qreal>(size, 4) + 1;
266 //     qDebug("offset = %f", offsetBase);
267
268     // To fix some Thai character heights check for two above glyphs
269     if (nmarks == 2 && (attributes[gfrom+1].combiningClass == HB_Combining_AboveRight ||
270             attributes[gfrom+1].combiningClass  == HB_Combining_AboveLeft ||
271             attributes[gfrom+1].combiningClass == HB_Combining_Above))
272         if (attributes[gfrom+2].combiningClass == 23 ||
273             attributes[gfrom+2].combiningClass == 24 ||
274             attributes[gfrom+2].combiningClass == 25 ||
275             attributes[gfrom+2].combiningClass == 27 ||
276             attributes[gfrom+2].combiningClass == 28 ||
277             attributes[gfrom+2].combiningClass == 30 ||
278             attributes[gfrom+2].combiningClass == 31 ||
279             attributes[gfrom+2].combiningClass == 33 ||
280             attributes[gfrom+2].combiningClass == 34 ||
281             attributes[gfrom+2].combiningClass == 35 ||
282             attributes[gfrom+2].combiningClass == 36 ||
283             attributes[gfrom+2].combiningClass == 107 ||
284             attributes[gfrom+2].combiningClass == 122) {
285             // Two above glyphs, check total height
286             int markTotalHeight = baseMetrics.height;
287             HB_GlyphMetrics markMetrics;
288             item->font->klass->getGlyphMetrics(item->font, glyphs[gfrom+1], &markMetrics);
289             markTotalHeight += markMetrics.height;
290             item->font->klass->getGlyphMetrics(item->font, glyphs[gfrom+2], &markMetrics);
291             markTotalHeight += markMetrics.height;
292             if ((markTotalHeight + 2 * offsetBase) > (size * 10))
293                 offsetBase = ((size * 10) - markTotalHeight) / 2; // Use offset that just fits
294         }
295
296     bool rightToLeft = item->item.bidiLevel % 2;
297
298     int i;
299     unsigned char lastCmb = 0;
300     HB_GlyphMetrics attachmentRect;
301     memset(&attachmentRect, 0, sizeof(attachmentRect));
302
303     for(i = 1; i <= nmarks; i++) {
304         HB_Glyph mark = glyphs[gfrom+i];
305         HB_GlyphMetrics markMetrics;
306         item->font->klass->getGlyphMetrics(item->font, mark, &markMetrics);
307         HB_FixedPoint p;
308         p.x = p.y = 0;
309 //          qDebug("markInfo: %f/%f (%f/%f) off=%f/%f", markInfo.x, markInfo.y, markInfo.width, markInfo.height, markInfo.xoff, markInfo.yoff);
310
311         HB_Fixed offset = offsetBase;
312         unsigned char cmb = attributes[gfrom+i].combiningClass;
313
314         // ### maybe the whole position determination should move down to heuristicSetGlyphAttributes. Would save some
315         // bits  in the glyphAttributes structure.
316         if (cmb < 200) {
317             // fixed position classes. We approximate by mapping to one of the others.
318             // currently I added only the ones for arabic, hebrew, lao and thai.
319
320             // for Lao and Thai marks with class 0, see below (heuristicSetGlyphAttributes)
321
322             // add a bit more offset to arabic, a bit hacky
323             if (cmb >= 27 && cmb <= 36 && offset < 3)
324                 offset +=1;
325             // below
326             if ((cmb >= 10 && cmb <= 18) ||
327                  cmb == 20 || cmb == 22 ||
328                  cmb == 29 || cmb == 32)
329                 cmb = HB_Combining_Below;
330             // above
331             else if (cmb == 23 || cmb == 27 || cmb == 28 ||
332                       cmb == 30 || cmb == 31 || (cmb >= 33 && cmb <= 36))
333                 cmb = HB_Combining_Above;
334             //below-right
335             else if (cmb == 9 || cmb == 103 || cmb == 118)
336                 cmb = HB_Combining_BelowRight;
337             // above-right
338             else if (cmb == 24 || cmb == 107 || cmb == 122)
339                 cmb = HB_Combining_AboveRight;
340             else if (cmb == 25)
341                 cmb = HB_Combining_AboveLeft;
342             // fixed:
343             //  19 21
344
345         }
346
347         // combining marks of different class don't interact. Reset the rectangle.
348         if (cmb != lastCmb) {
349             //qDebug("resetting rect");
350             attachmentRect = baseMetrics;
351         }
352
353         switch(cmb) {
354         case HB_Combining_DoubleBelow:
355                 // ### wrong in rtl context!
356         case HB_Combining_BelowLeft:
357             p.y += offset;
358         case HB_Combining_BelowLeftAttached:
359             p.x += attachmentRect.x - markMetrics.x;
360             p.y += (attachmentRect.y + attachmentRect.height) - markMetrics.y;
361             break;
362         case HB_Combining_Below:
363             p.y += offset;
364         case HB_Combining_BelowAttached:
365             p.x += attachmentRect.x - markMetrics.x;
366             p.y += (attachmentRect.y + attachmentRect.height) - markMetrics.y;
367
368             p.x += (attachmentRect.width - markMetrics.width) / 2;
369             break;
370         case HB_Combining_BelowRight:
371             p.y += offset;
372         case HB_Combining_BelowRightAttached:
373             p.x += attachmentRect.x + attachmentRect.width - markMetrics.width - markMetrics.x;
374             p.y += attachmentRect.y + attachmentRect.height - markMetrics.y;
375             break;
376         case HB_Combining_Left:
377             p.x -= offset;
378         case HB_Combining_LeftAttached:
379             break;
380         case HB_Combining_Right:
381             p.x += offset;
382         case HB_Combining_RightAttached:
383             break;
384         case HB_Combining_DoubleAbove:
385             // ### wrong in RTL context!
386         case HB_Combining_AboveLeft:
387             p.y -= offset;
388         case HB_Combining_AboveLeftAttached:
389             p.x += attachmentRect.x - markMetrics.x;
390             p.y += attachmentRect.y - markMetrics.y - markMetrics.height;
391             break;
392         case HB_Combining_Above:
393             p.y -= offset;
394         case HB_Combining_AboveAttached:
395             p.x += attachmentRect.x - markMetrics.x;
396             p.y += attachmentRect.y - markMetrics.y - markMetrics.height;
397
398             p.x += (attachmentRect.width - markMetrics.width) / 2;
399             break;
400         case HB_Combining_AboveRight:
401             p.y -= offset;
402         case HB_Combining_AboveRightAttached:
403             p.x += attachmentRect.x + attachmentRect.width - markMetrics.x - markMetrics.width;
404             p.y += attachmentRect.y - markMetrics.y - markMetrics.height;
405             break;
406
407         case HB_Combining_IotaSubscript:
408             default:
409                 break;
410         }
411 //          qDebug("char=%x combiningClass = %d offset=%f/%f", mark, cmb, p.x(), p.y());
412         markMetrics.x += p.x;
413         markMetrics.y += p.y;
414
415         HB_GlyphMetrics unitedAttachmentRect = attachmentRect;
416         unitedAttachmentRect.x = HB_MIN(attachmentRect.x, markMetrics.x);
417         unitedAttachmentRect.y = HB_MIN(attachmentRect.y, markMetrics.y);
418         unitedAttachmentRect.width = HB_MAX(attachmentRect.x + attachmentRect.width, markMetrics.x + markMetrics.width) - unitedAttachmentRect.x;
419         unitedAttachmentRect.height = HB_MAX(attachmentRect.y + attachmentRect.height, markMetrics.y + markMetrics.height) - unitedAttachmentRect.y;
420         attachmentRect = unitedAttachmentRect;
421
422         lastCmb = cmb;
423         if (rightToLeft) {
424             item->offsets[gfrom+i].x = p.x;
425             item->offsets[gfrom+i].y = p.y;
426         } else {
427             item->offsets[gfrom+i].x = p.x - baseMetrics.xOffset;
428             item->offsets[gfrom+i].y = p.y - baseMetrics.yOffset;
429         }
430         item->advances[gfrom+i] = 0;
431     }
432 }
433
434 void HB_HeuristicPosition(HB_ShaperItem *item)
435 {
436     HB_GetGlyphAdvances(item);
437     HB_GlyphAttributes *attributes = item->attributes;
438
439     int cEnd = -1;
440     int i = item->num_glyphs;
441     while (i--) {
442         if (cEnd == -1 && attributes[i].mark) {
443             cEnd = i;
444         } else if (cEnd != -1 && !attributes[i].mark) {
445             positionCluster(item, i, cEnd);
446             cEnd = -1;
447         }
448     }
449 }
450
451 // set the glyph attributes heuristically. Assumes a 1 to 1 relationship between chars and glyphs
452 // and no reordering.
453 // also computes logClusters heuristically
454 void HB_HeuristicSetGlyphAttributes(HB_ShaperItem *item)
455 {
456     const HB_UChar16 *uc = item->string + item->item.pos;
457     hb_uint32 length = item->item.length;
458
459     // ### zeroWidth and justification are missing here!!!!!
460
461     assert(item->num_glyphs <= length);
462
463 //     qDebug("QScriptEngine::heuristicSetGlyphAttributes, num_glyphs=%d", item->num_glyphs);
464     HB_GlyphAttributes *attributes = item->attributes;
465     unsigned short *logClusters = item->log_clusters;
466
467     hb_uint32 glyph_pos = 0;
468     hb_uint32 i;
469     for (i = 0; i < length; i++) {
470         if (HB_IsHighSurrogate(uc[i]) && i < length - 1
471             && HB_IsLowSurrogate(uc[i + 1])) {
472             logClusters[i] = glyph_pos;
473             logClusters[++i] = glyph_pos;
474         } else {
475             logClusters[i] = glyph_pos;
476         }
477         ++glyph_pos;
478     }
479     assert(glyph_pos == item->num_glyphs);
480
481     // first char in a run is never (treated as) a mark
482     int cStart = 0;
483     const bool symbolFont = item->face->isSymbolFont;
484     attributes[0].mark = false;
485     attributes[0].clusterStart = true;
486     attributes[0].dontPrint = (!symbolFont && uc[0] == 0x00ad) || HB_IsControlChar(uc[0]);
487
488     int pos = 0;
489     HB_CharCategory lastCat;
490     int dummy;
491     HB_GetUnicodeCharProperties(uc[0], &lastCat, &dummy);
492     for (i = 1; i < length; ++i) {
493         if (logClusters[i] == pos)
494             // same glyph
495             continue;
496         ++pos;
497         while (pos < logClusters[i]) {
498             attributes[pos] = attributes[pos-1];
499             ++pos;
500         }
501         // hide soft-hyphens by default
502         if ((!symbolFont && uc[i] == 0x00ad) || HB_IsControlChar(uc[i]))
503             attributes[pos].dontPrint = true;
504         HB_CharCategory cat;
505         int cmb;
506         HB_GetUnicodeCharProperties(uc[i], &cat, &cmb);
507         if (cat != HB_Mark_NonSpacing) {
508             attributes[pos].mark = false;
509             attributes[pos].clusterStart = true;
510             attributes[pos].combiningClass = 0;
511             cStart = logClusters[i];
512         } else {
513             if (cmb == 0) {
514                 // Fix 0 combining classes
515                 if ((uc[pos] & 0xff00) == 0x0e00) {
516                     // thai or lao
517                     if (uc[pos] == 0xe31 ||
518                          uc[pos] == 0xe34 ||
519                          uc[pos] == 0xe35 ||
520                          uc[pos] == 0xe36 ||
521                          uc[pos] == 0xe37 ||
522                          uc[pos] == 0xe47 ||
523                          uc[pos] == 0xe4c ||
524                          uc[pos] == 0xe4d ||
525                          uc[pos] == 0xe4e) {
526                         cmb = HB_Combining_AboveRight;
527                     } else if (uc[pos] == 0xeb1 ||
528                                 uc[pos] == 0xeb4 ||
529                                 uc[pos] == 0xeb5 ||
530                                 uc[pos] == 0xeb6 ||
531                                 uc[pos] == 0xeb7 ||
532                                 uc[pos] == 0xebb ||
533                                 uc[pos] == 0xecc ||
534                                 uc[pos] == 0xecd) {
535                         cmb = HB_Combining_Above;
536                     } else if (uc[pos] == 0xebc) {
537                         cmb = HB_Combining_Below;
538                     }
539                 }
540             }
541
542             attributes[pos].mark = true;
543             attributes[pos].clusterStart = false;
544             attributes[pos].combiningClass = cmb;
545             logClusters[i] = cStart;
546         }
547         // one gets an inter character justification point if the current char is not a non spacing mark.
548         // as then the current char belongs to the last one and one gets a space justification point
549         // after the space char.
550         if (lastCat == HB_Separator_Space)
551             attributes[pos-1].justification = HB_Space;
552         else if (cat != HB_Mark_NonSpacing)
553             attributes[pos-1].justification = HB_Character;
554         else
555             attributes[pos-1].justification = HB_NoJustification;
556
557         lastCat = cat;
558     }
559     pos = logClusters[length-1];
560     if (lastCat == HB_Separator_Space)
561         attributes[pos].justification = HB_Space;
562     else
563         attributes[pos].justification = HB_Character;
564 }
565
566 #ifndef NO_OPENTYPE
567 static const HB_OpenTypeFeature basic_features[] = {
568     { HB_MAKE_TAG('c', 'c', 'm', 'p'), CcmpProperty },
569     { HB_MAKE_TAG('l', 'i', 'g', 'a'), LigaProperty },
570     { HB_MAKE_TAG('c', 'l', 'i', 'g'), CligProperty },
571     {0, 0}
572 };
573
574 static const HB_OpenTypeFeature disabled_features[] = {
575     { HB_MAKE_TAG('c', 'p', 'c', 't'), PositioningProperties },
576     { HB_MAKE_TAG('h', 'a', 'l', 't'), PositioningProperties },
577     // TODO: we need to add certain HB_ShaperFlag for vertical
578     // writing mode to enable these vertical writing features:
579     { HB_MAKE_TAG('v', 'a', 'l', 't'), PositioningProperties },
580     { HB_MAKE_TAG('v', 'h', 'a', 'l'), PositioningProperties },
581     { HB_MAKE_TAG('v', 'k', 'r', 'n'), PositioningProperties },
582     { HB_MAKE_TAG('v', 'p', 'a', 'l'), PositioningProperties },
583     {0, 0}
584 };
585 #endif
586
587 HB_Bool HB_ConvertStringToGlyphIndices(HB_ShaperItem *shaper_item)
588 {
589     if (shaper_item->glyphIndicesPresent) {
590         shaper_item->num_glyphs = shaper_item->initialGlyphCount;
591         shaper_item->glyphIndicesPresent = false;
592         return true;
593     }
594     return shaper_item->font->klass
595            ->convertStringToGlyphIndices(shaper_item->font,
596                                          shaper_item->string + shaper_item->item.pos, shaper_item->item.length,
597                                          shaper_item->glyphs, &shaper_item->num_glyphs,
598                                          shaper_item->item.bidiLevel % 2);
599 }
600
601 HB_Bool HB_BasicShape(HB_ShaperItem *shaper_item)
602 {
603 #ifndef NO_OPENTYPE
604     const int availableGlyphs = shaper_item->num_glyphs;
605 #endif
606
607     if (!HB_ConvertStringToGlyphIndices(shaper_item))
608         return false;
609
610     HB_HeuristicSetGlyphAttributes(shaper_item);
611
612 #ifndef NO_OPENTYPE
613     if (HB_SelectScript(shaper_item, basic_features)) {
614         HB_OpenTypeShape(shaper_item, /*properties*/0);
615         return HB_OpenTypePosition(shaper_item, availableGlyphs, /*doLogClusters*/true);
616     }
617 #endif
618
619     HB_HeuristicPosition(shaper_item);
620     return true;
621 }
622
623 const HB_ScriptEngine HB_ScriptEngines[] = {
624     // Common
625     { HB_BasicShape, 0},
626     // Greek
627     { HB_GreekShape, 0},
628     // Cyrillic
629     { HB_BasicShape, 0},
630     // Armenian
631     { HB_BasicShape, 0},
632     // Hebrew
633     { HB_HebrewShape, 0 },
634     // Arabic
635     { HB_ArabicShape, 0},
636     // Syriac
637     { HB_ArabicShape, 0},
638     // Thaana
639     { HB_BasicShape, 0 },
640     // Devanagari
641     { HB_IndicShape, HB_IndicAttributes },
642     // Bengali
643     { HB_IndicShape, HB_IndicAttributes },
644     // Gurmukhi
645     { HB_IndicShape, HB_IndicAttributes },
646     // Gujarati
647     { HB_IndicShape, HB_IndicAttributes },
648     // Oriya
649     { HB_IndicShape, HB_IndicAttributes },
650     // Tamil
651     { HB_IndicShape, HB_IndicAttributes },
652     // Telugu
653     { HB_IndicShape, HB_IndicAttributes },
654     // Kannada
655     { HB_IndicShape, HB_IndicAttributes },
656     // Malayalam
657     { HB_IndicShape, HB_IndicAttributes },
658     // Sinhala
659     { HB_IndicShape, HB_IndicAttributes },
660     // Thai
661     { HB_ThaiShape, HB_ThaiAttributes },
662     // Lao
663     { HB_BasicShape, 0 },
664     // Tibetan
665     { HB_TibetanShape, HB_TibetanAttributes },
666     // Myanmar
667     { HB_MyanmarShape, HB_MyanmarAttributes },
668     // Georgian
669     { HB_BasicShape, 0 },
670     // Hangul
671     { HB_HangulShape, 0 },
672     // Ogham
673     { HB_BasicShape, 0 },
674     // Runic
675     { HB_BasicShape, 0 },
676     // Khmer
677     { HB_KhmerShape, HB_KhmerAttributes },
678     // N'Ko
679     { HB_ArabicShape, 0}
680 };
681
682 void HB_GetCharAttributes(const HB_UChar16 *string, hb_uint32 stringLength,
683                           const HB_ScriptItem *items, hb_uint32 numItems,
684                           HB_CharAttributes *attributes)
685 {
686     memset(attributes, 0, stringLength * sizeof(HB_CharAttributes));
687     calcLineBreaks(string, stringLength, attributes);
688
689     for (hb_uint32 i = 0; i < numItems; ++i) {
690         HB_Script script = items[i].script;
691         if (script == HB_Script_Inherited)
692             script = HB_Script_Common;
693         HB_AttributeFunction attributeFunction = HB_ScriptEngines[script].charAttributes;
694         if (!attributeFunction)
695             continue;
696         attributeFunction(script, string, items[i].pos, items[i].length, attributes);
697     }
698 }
699
700
701 enum BreakRule { NoBreak = 0, Break = 1, Middle = 2 };
702
703 static const hb_uint8 wordbreakTable[HB_Word_ExtendNumLet + 1][HB_Word_ExtendNumLet + 1] = {
704 //        Other    Format   Katakana ALetter  MidLetter MidNum  Numeric  ExtendNumLet
705     {   Break,   Break,   Break,   Break,   Break,   Break,   Break,   Break }, // Other
706     {   Break,   Break,   Break,   Break,   Break,   Break,   Break,   Break }, // Format 
707     {   Break,   Break, NoBreak,   Break,   Break,   Break,   Break, NoBreak }, // Katakana
708     {   Break,   Break,   Break, NoBreak,  Middle,   Break, NoBreak, NoBreak }, // ALetter
709     {   Break,   Break,   Break,   Break,   Break,   Break,   Break,   Break }, // MidLetter
710     {   Break,   Break,   Break,   Break,   Break,   Break,   Break,   Break }, // MidNum
711     {   Break,   Break,   Break, NoBreak,   Break,  Middle, NoBreak, NoBreak }, // Numeric
712     {   Break,   Break, NoBreak, NoBreak,   Break,   Break, NoBreak, NoBreak }, // ExtendNumLet
713 };
714
715 void HB_GetWordBoundaries(const HB_UChar16 *string, hb_uint32 stringLength,
716                           const HB_ScriptItem * /*items*/, hb_uint32 /*numItems*/,
717                           HB_CharAttributes *attributes)
718 {
719     if (stringLength == 0)
720         return;
721     unsigned int brk = HB_GetWordClass(string[0]);
722     attributes[0].wordBoundary = true;
723     for (hb_uint32 i = 1; i < stringLength; ++i) {
724         if (!attributes[i].charStop) {
725             attributes[i].wordBoundary = false;
726             continue;
727         }
728         hb_uint32 nbrk = HB_GetWordClass(string[i]);
729         if (nbrk == HB_Word_Format) {
730             attributes[i].wordBoundary = (HB_GetSentenceClass(string[i-1]) == HB_Sentence_Sep);
731             continue;
732         }
733         BreakRule rule = (BreakRule)wordbreakTable[brk][nbrk];
734         if (rule == Middle) {
735             rule = Break;
736             hb_uint32 lookahead = i + 1;
737             while (lookahead < stringLength) {
738                 hb_uint32 testbrk = HB_GetWordClass(string[lookahead]);
739                 if (testbrk == HB_Word_Format && HB_GetSentenceClass(string[lookahead]) != HB_Sentence_Sep) {
740                     ++lookahead;
741                     continue;
742                 }
743                 if (testbrk == brk) {
744                     rule = NoBreak;
745                     while (i < lookahead)
746                         attributes[i++].wordBoundary = false;
747                     nbrk = testbrk;
748                 }
749                 break;
750             }
751         }
752         attributes[i].wordBoundary = (rule == Break);
753         brk = nbrk;
754     }
755 }
756
757
758 enum SentenceBreakStates {
759     SB_Initial,
760     SB_Upper,
761     SB_UpATerm, 
762     SB_ATerm,
763     SB_ATermC, 
764     SB_ACS, 
765     SB_STerm, 
766     SB_STermC, 
767     SB_SCS,
768     SB_BAfter, 
769     SB_Break,
770     SB_Look
771 };
772
773 static const hb_uint8 sentenceBreakTable[HB_Sentence_Close + 1][HB_Sentence_Close + 1] = {
774 //        Other       Sep         Format      Sp          Lower       Upper       OLetter     Numeric     ATerm       STerm       Close
775       { SB_Initial, SB_BAfter , SB_Initial, SB_Initial, SB_Initial, SB_Upper  , SB_Initial, SB_Initial, SB_ATerm  , SB_STerm  , SB_Initial }, // SB_Initial,
776       { SB_Initial, SB_BAfter , SB_Upper  , SB_Initial, SB_Initial, SB_Upper  , SB_Initial, SB_Initial, SB_UpATerm, SB_STerm  , SB_Initial }, // SB_Upper
777       
778       { SB_Look   , SB_BAfter , SB_UpATerm, SB_ACS    , SB_Initial, SB_Upper  , SB_Break  , SB_Initial, SB_ATerm  , SB_STerm  , SB_ATermC  }, // SB_UpATerm
779       { SB_Look   , SB_BAfter , SB_ATerm  , SB_ACS    , SB_Initial, SB_Break  , SB_Break  , SB_Initial, SB_ATerm  , SB_STerm  , SB_ATermC  }, // SB_ATerm
780       { SB_Look   , SB_BAfter , SB_ATermC , SB_ACS    , SB_Initial, SB_Break  , SB_Break  , SB_Look   , SB_ATerm  , SB_STerm  , SB_ATermC  }, // SB_ATermC,
781       { SB_Look   , SB_BAfter , SB_ACS    , SB_ACS    , SB_Initial, SB_Break  , SB_Break  , SB_Look   , SB_ATerm  , SB_STerm  , SB_Look    }, // SB_ACS,
782       
783       { SB_Break  , SB_BAfter , SB_STerm  , SB_SCS    , SB_Break  , SB_Break  , SB_Break  , SB_Break  , SB_ATerm  , SB_STerm  , SB_STermC  }, // SB_STerm,
784       { SB_Break  , SB_BAfter , SB_STermC , SB_SCS    , SB_Break  , SB_Break  , SB_Break  , SB_Break  , SB_ATerm  , SB_STerm  , SB_STermC  }, // SB_STermC,
785       { SB_Break  , SB_BAfter , SB_SCS    , SB_SCS    , SB_Break  , SB_Break  , SB_Break  , SB_Break  , SB_ATerm  , SB_STerm  , SB_Break   }, // SB_SCS,
786       { SB_Break  , SB_Break  , SB_Break  , SB_Break  , SB_Break  , SB_Break  , SB_Break  , SB_Break  , SB_Break  , SB_Break  , SB_Break   }, // SB_BAfter,
787 };
788
789 void HB_GetSentenceBoundaries(const HB_UChar16 *string, hb_uint32 stringLength,
790                               const HB_ScriptItem * /*items*/, hb_uint32 /*numItems*/,
791                               HB_CharAttributes *attributes)
792 {
793     if (stringLength == 0)
794         return;
795     hb_uint32 brk = sentenceBreakTable[SB_Initial][HB_GetSentenceClass(string[0])];
796     attributes[0].sentenceBoundary = true;
797     for (hb_uint32 i = 1; i < stringLength; ++i) {
798         if (!attributes[i].charStop) {
799             attributes[i].sentenceBoundary = false;
800             continue;
801         }
802         brk = sentenceBreakTable[brk][HB_GetSentenceClass(string[i])];
803         if (brk == SB_Look) {
804             brk = SB_Break;
805             hb_uint32 lookahead = i + 1;
806             while (lookahead < stringLength) {
807                 hb_uint32 sbrk = HB_GetSentenceClass(string[lookahead]);
808                 if (sbrk != HB_Sentence_Other && sbrk != HB_Sentence_Numeric && sbrk != HB_Sentence_Close) {
809                     break;
810                 } else if (sbrk == HB_Sentence_Lower) {
811                     brk = SB_Initial;
812                     break;
813                 }
814                 ++lookahead;
815             }
816             if (brk == SB_Initial) {
817                 while (i < lookahead)
818                     attributes[i++].sentenceBoundary = false;
819             }
820         }
821         if (brk == SB_Break) {
822             attributes[i].sentenceBoundary = true;
823             brk = sentenceBreakTable[SB_Initial][HB_GetSentenceClass(string[i])];
824         } else {
825             attributes[i].sentenceBoundary = false;
826         }
827     }
828 }
829
830
831 static inline char *tag_to_string(HB_UInt tag)
832 {
833     static char string[5];
834     string[0] = (tag >> 24)&0xff;
835     string[1] = (tag >> 16)&0xff;
836     string[2] = (tag >> 8)&0xff;
837     string[3] = tag&0xff;
838     string[4] = 0;
839     return string;
840 }
841
842 #ifdef OT_DEBUG
843 static void dump_string(HB_Buffer buffer)
844 {
845     for (uint i = 0; i < buffer->in_length; ++i) {
846         qDebug("    %x: cluster=%d", buffer->in_string[i].gindex, buffer->in_string[i].cluster);
847     }
848 }
849 #define DEBUG printf
850 #else
851 #define DEBUG if (1) ; else printf
852 #endif
853
854 #define DefaultLangSys 0xffff
855 #define DefaultScript HB_MAKE_TAG('D', 'F', 'L', 'T')
856
857 enum {
858     RequiresGsub = 1,
859     RequiresGpos = 2
860 };
861
862 struct OTScripts {
863     unsigned int tag;
864     int flags;
865 };
866 static const OTScripts ot_scripts [] = {
867     // Common
868     { HB_MAKE_TAG('l', 'a', 't', 'n'), 0 },
869     // Greek
870     { HB_MAKE_TAG('g', 'r', 'e', 'k'), 0 },
871     // Cyrillic
872     { HB_MAKE_TAG('c', 'y', 'r', 'l'), 0 },
873     // Armenian
874     { HB_MAKE_TAG('a', 'r', 'm', 'n'), 0 },
875     // Hebrew
876     { HB_MAKE_TAG('h', 'e', 'b', 'r'), 1 },
877     // Arabic
878     { HB_MAKE_TAG('a', 'r', 'a', 'b'), 1 },
879     // Syriac
880     { HB_MAKE_TAG('s', 'y', 'r', 'c'), 1 },
881     // Thaana
882     { HB_MAKE_TAG('t', 'h', 'a', 'a'), 1 },
883     // Devanagari
884     { HB_MAKE_TAG('d', 'e', 'v', 'a'), 1 },
885     // Bengali
886     { HB_MAKE_TAG('b', 'e', 'n', 'g'), 1 },
887     // Gurmukhi
888     { HB_MAKE_TAG('g', 'u', 'r', 'u'), 1 },
889     // Gujarati
890     { HB_MAKE_TAG('g', 'u', 'j', 'r'), 1 },
891     // Oriya
892     { HB_MAKE_TAG('o', 'r', 'y', 'a'), 1 },
893     // Tamil
894     { HB_MAKE_TAG('t', 'a', 'm', 'l'), 1 },
895     // Telugu
896     { HB_MAKE_TAG('t', 'e', 'l', 'u'), 1 },
897     // Kannada
898     { HB_MAKE_TAG('k', 'n', 'd', 'a'), 1 },
899     // Malayalam
900     { HB_MAKE_TAG('m', 'l', 'y', 'm'), 1 },
901     // Sinhala
902     { HB_MAKE_TAG('s', 'i', 'n', 'h'), 1 },
903     // Thai
904     { HB_MAKE_TAG('t', 'h', 'a', 'i'), 1 },
905     // Lao
906     { HB_MAKE_TAG('l', 'a', 'o', ' '), 1 },
907     // Tibetan
908     { HB_MAKE_TAG('t', 'i', 'b', 't'), 1 },
909     // Myanmar
910     { HB_MAKE_TAG('m', 'y', 'm', 'r'), 1 },
911     // Georgian
912     { HB_MAKE_TAG('g', 'e', 'o', 'r'), 0 },
913     // Hangul
914     { HB_MAKE_TAG('h', 'a', 'n', 'g'), 1 },
915     // Ogham
916     { HB_MAKE_TAG('o', 'g', 'a', 'm'), 0 },
917     // Runic
918     { HB_MAKE_TAG('r', 'u', 'n', 'r'), 0 },
919     // Khmer
920     { HB_MAKE_TAG('k', 'h', 'm', 'r'), 1 },
921     // N'Ko
922     { HB_MAKE_TAG('n', 'k', 'o', ' '), 1 }
923 };
924 enum { NumOTScripts = sizeof(ot_scripts)/sizeof(OTScripts) };
925
926 static HB_Bool checkScript(HB_Face face, int script)
927 {
928     assert(script < HB_ScriptCount);
929
930     if (!face->gsub && !face->gpos)
931         return false;
932
933     unsigned int tag = ot_scripts[script].tag;
934     int requirements = ot_scripts[script].flags;
935
936     if (requirements & RequiresGsub) {
937         if (!face->gsub)
938             return false;
939
940         HB_UShort script_index;
941         HB_Error error = HB_GSUB_Select_Script(face->gsub, tag, &script_index);
942         if (error) {
943             DEBUG("could not select script %d in GSub table: %d", (int)script, error);
944             error = HB_GSUB_Select_Script(face->gsub, HB_MAKE_TAG('D', 'F', 'L', 'T'), &script_index);
945             if (error)
946                 return false;
947         }
948     }
949
950     if (requirements & RequiresGpos) {
951         if (!face->gpos)
952             return false;
953
954         HB_UShort script_index;
955         HB_Error error = HB_GPOS_Select_Script(face->gpos, script, &script_index);
956         if (error) {
957             DEBUG("could not select script in gpos table: %d", error);
958             error = HB_GPOS_Select_Script(face->gpos, HB_MAKE_TAG('D', 'F', 'L', 'T'), &script_index);
959             if (error)
960                 return false;
961         }
962
963     }
964     return true;
965 }
966
967 static HB_Stream getTableStream(void *font, HB_GetFontTableFunc tableFunc, HB_Tag tag)
968 {
969     HB_Error error;
970     HB_UInt length = 0;
971     HB_Stream stream = 0;
972
973     if (!font)
974         return 0;
975
976     error = tableFunc(font, tag, 0, &length);
977     if (error)
978         return 0;
979     stream = (HB_Stream)malloc(sizeof(HB_StreamRec));
980     if (!stream)
981         return 0;
982     stream->base = (HB_Byte*)malloc(length);
983     if (!stream->base) {
984         free(stream);
985         return 0;
986     }
987     error = tableFunc(font, tag, stream->base, &length);
988     if (error) {
989         _hb_close_stream(stream);
990         return 0;
991     }
992     stream->size = length;
993     stream->pos = 0;
994     stream->cursor = NULL;
995     return stream;
996 }
997
998 HB_Face HB_AllocFace(void *font, HB_GetFontTableFunc tableFunc)
999 {
1000     HB_Face face = (HB_Face )malloc(sizeof(HB_FaceRec));
1001     if (!face)
1002         return 0;
1003
1004     face->isSymbolFont = false;
1005     face->gdef = 0;
1006     face->gpos = 0;
1007     face->gsub = 0;
1008     face->current_script = HB_ScriptCount;
1009     face->current_flags = HB_ShaperFlag_Default;
1010     face->has_opentype_kerning = false;
1011     face->tmpAttributes = 0;
1012     face->tmpLogClusters = 0;
1013     face->glyphs_substituted = false;
1014     face->buffer = 0;
1015     face->font_for_init = font;
1016     face->get_font_table_func = tableFunc;
1017
1018     return face;
1019 }
1020
1021 HB_Face HB_NewFace(void *font, HB_GetFontTableFunc tableFunc)
1022 {
1023     HB_Face face = HB_AllocFace(font, tableFunc);
1024     if (face)
1025         face = HB_LoadFace(face);
1026     return face;
1027 }
1028
1029 HB_Face HB_LoadFace(HB_Face face)
1030 {
1031     void *font = face->font_for_init;
1032     if (!font)
1033         return face;
1034
1035     HB_GetFontTableFunc tableFunc = face->get_font_table_func;
1036
1037     face->get_font_table_func = 0;
1038     face->font_for_init = 0;
1039
1040     HB_Error error = HB_Err_Ok;
1041     HB_Stream stream;
1042     HB_Stream gdefStream;
1043
1044     gdefStream = getTableStream(font, tableFunc, TTAG_GDEF);
1045     error = HB_Err_Not_Covered;
1046     if (!gdefStream || (error = HB_Load_GDEF_Table(gdefStream, &face->gdef))) {
1047         //DEBUG("error loading gdef table: %d", error);
1048         face->gdef = 0;
1049     }
1050
1051     //DEBUG() << "trying to load gsub table";
1052     stream = getTableStream(font, tableFunc, TTAG_GSUB);
1053     error = HB_Err_Not_Covered;
1054     if (!stream || (error = HB_Load_GSUB_Table(stream, &face->gsub, face->gdef, gdefStream))) {
1055         face->gsub = 0;
1056         if (error != HB_Err_Not_Covered) {
1057             //DEBUG("error loading gsub table: %d", error);
1058         } else {
1059             //DEBUG("face doesn't have a gsub table");
1060         }
1061     }
1062     _hb_close_stream(stream);
1063
1064     stream = getTableStream(font, tableFunc, TTAG_GPOS);
1065     error = HB_Err_Not_Covered;
1066     if (!stream || (error = HB_Load_GPOS_Table(stream, &face->gpos, face->gdef, gdefStream))) {
1067         face->gpos = 0;
1068         DEBUG("error loading gpos table: %d", error);
1069     }
1070     _hb_close_stream(stream);
1071
1072     _hb_close_stream(gdefStream);
1073
1074     for (unsigned int i = 0; i < HB_ScriptCount; ++i)
1075         face->supported_scripts[i] = checkScript(face, i);
1076
1077     if (hb_buffer_new(&face->buffer) != HB_Err_Ok) {
1078         HB_FreeFace(face);
1079         return 0;
1080     }
1081
1082     return face;
1083 }
1084
1085 void HB_FreeFace(HB_Face face)
1086 {
1087     if (!face)
1088         return;
1089     if (face->gpos)
1090         HB_Done_GPOS_Table(face->gpos);
1091     if (face->gsub)
1092         HB_Done_GSUB_Table(face->gsub);
1093     if (face->gdef)
1094         HB_Done_GDEF_Table(face->gdef);
1095     if (face->buffer)
1096         hb_buffer_free(face->buffer);
1097     if (face->tmpAttributes)
1098         free(face->tmpAttributes);
1099     if (face->tmpLogClusters)
1100         free(face->tmpLogClusters);
1101     free(face);
1102 }
1103
1104 HB_Bool HB_SelectScript(HB_ShaperItem *shaper_item, const HB_OpenTypeFeature *features)
1105 {
1106     HB_Script script = shaper_item->item.script;
1107
1108     HB_Face face = shaper_item->face;
1109     if (face->current_script == script && face->current_flags == shaper_item->shaperFlags)
1110         return shaper_item->face->supported_scripts[script] ? true : false;
1111
1112     face->current_script = script;
1113     face->current_flags = shaper_item->shaperFlags;
1114
1115     if (!shaper_item->face->supported_scripts[script])
1116         return false;
1117
1118     assert(script < HB_ScriptCount);
1119     // find script in our list of supported scripts.
1120     unsigned int tag = ot_scripts[script].tag;
1121
1122     if (face->gsub && features) {
1123 #ifdef OT_DEBUG
1124         {
1125             HB_FeatureList featurelist = face->gsub->FeatureList;
1126             int numfeatures = featurelist.FeatureCount;
1127             DEBUG("gsub table has %d features", numfeatures);
1128             for (int i = 0; i < numfeatures; i++) {
1129                 HB_FeatureRecord *r = featurelist.FeatureRecord + i;
1130                 DEBUG("   feature '%s'", tag_to_string(r->FeatureTag));
1131             }
1132         }
1133 #endif
1134         HB_GSUB_Clear_Features(face->gsub);
1135         HB_UShort script_index;
1136         HB_Error error = HB_GSUB_Select_Script(face->gsub, tag, &script_index);
1137         if (!error) {
1138             DEBUG("script %s has script index %d", tag_to_string(script), script_index);
1139             while (features->tag) {
1140                 HB_UShort feature_index;
1141                 error = HB_GSUB_Select_Feature(face->gsub, features->tag, script_index, 0xffff, &feature_index);
1142                 if (!error) {
1143                     DEBUG("  adding feature %s", tag_to_string(features->tag));
1144                     HB_GSUB_Add_Feature(face->gsub, feature_index, features->property);
1145                 }
1146                 ++features;
1147             }
1148         }
1149     }
1150
1151     // reset
1152     face->has_opentype_kerning = false;
1153
1154     if (face->gpos) {
1155         HB_GPOS_Clear_Features(face->gpos);
1156         HB_UShort script_index;
1157         HB_Error error = HB_GPOS_Select_Script(face->gpos, tag, &script_index);
1158         if (!error) {
1159 #ifdef OT_DEBUG
1160             {
1161                 HB_FeatureList featurelist = face->gpos->FeatureList;
1162                 int numfeatures = featurelist.FeatureCount;
1163                 DEBUG("gpos table has %d features", numfeatures);
1164                 for(int i = 0; i < numfeatures; i++) {
1165                     HB_FeatureRecord *r = featurelist.FeatureRecord + i;
1166                     HB_UShort feature_index;
1167                     HB_GPOS_Select_Feature(face->gpos, r->FeatureTag, script_index, 0xffff, &feature_index);
1168                     DEBUG("   feature '%s'", tag_to_string(r->FeatureTag));
1169                 }
1170             }
1171 #endif
1172             HB_UInt *feature_tag_list_buffer;
1173             error = HB_GPOS_Query_Features(face->gpos, script_index, 0xffff, &feature_tag_list_buffer);
1174             if (!error) {
1175                 HB_UInt *feature_tag_list = feature_tag_list_buffer;
1176                 while (*feature_tag_list) {
1177                     HB_UShort feature_index;
1178                     bool skip = false;
1179                     if (*feature_tag_list == HB_MAKE_TAG('k', 'e', 'r', 'n')) {
1180                         if (face->current_flags & HB_ShaperFlag_NoKerning)
1181                             skip = true;
1182                         else
1183                             face->has_opentype_kerning = true;
1184                     }
1185                     features = disabled_features;
1186                     while (features->tag) {
1187                         if (*feature_tag_list == features->tag) {
1188                             skip = true;
1189                             break;
1190                         }
1191                         ++features;
1192                     }
1193                     // 'palt' should be turned off by default unless 'kern' is on
1194                     if (!face->has_opentype_kerning &&
1195                         *feature_tag_list == HB_MAKE_TAG('p', 'a', 'l', 't'))
1196                         skip = true;
1197
1198                     if (skip) {
1199                         ++feature_tag_list;
1200                         continue;
1201                     }
1202                     error = HB_GPOS_Select_Feature(face->gpos, *feature_tag_list, script_index, 0xffff, &feature_index);
1203                     if (!error)
1204                         HB_GPOS_Add_Feature(face->gpos, feature_index, PositioningProperties);
1205                     ++feature_tag_list;
1206                 }
1207                 FREE(feature_tag_list_buffer);
1208             }
1209         }
1210     }
1211
1212     return true;
1213 }
1214
1215 HB_Bool HB_OpenTypeShape(HB_ShaperItem *item, const hb_uint32 *properties)
1216 {
1217     HB_GlyphAttributes *tmpAttributes;
1218     unsigned int *tmpLogClusters;
1219
1220     HB_Face face = item->face;
1221
1222     face->length = item->num_glyphs;
1223
1224     hb_buffer_clear(face->buffer);
1225
1226     tmpAttributes = (HB_GlyphAttributes *) realloc(face->tmpAttributes, face->length*sizeof(HB_GlyphAttributes));
1227     if (!tmpAttributes)
1228         return false;
1229     face->tmpAttributes = tmpAttributes;
1230
1231     tmpLogClusters = (unsigned int *) realloc(face->tmpLogClusters, face->length*sizeof(unsigned int));
1232     if (!tmpLogClusters)
1233         return false;
1234     face->tmpLogClusters = tmpLogClusters;
1235
1236     for (int i = 0; i < face->length; ++i) {
1237         hb_buffer_add_glyph(face->buffer, item->glyphs[i], properties ? properties[i] : 0, i);
1238         face->tmpAttributes[i] = item->attributes[i];
1239         face->tmpLogClusters[i] = item->log_clusters[i];
1240     }
1241
1242 #ifdef OT_DEBUG
1243     DEBUG("-----------------------------------------");
1244 //     DEBUG("log clusters before shaping:");
1245 //     for (int j = 0; j < length; j++)
1246 //         DEBUG("    log[%d] = %d", j, item->log_clusters[j]);
1247     DEBUG("original glyphs: %p", item->glyphs);
1248     for (int i = 0; i < length; ++i)
1249         DEBUG("   glyph=%4x", hb_buffer->in_string[i].gindex);
1250 //     dump_string(hb_buffer);
1251 #endif
1252
1253     face->glyphs_substituted = false;
1254     if (face->gsub) {
1255         unsigned int error = HB_GSUB_Apply_String(face->gsub, face->buffer);
1256         if (error && error != HB_Err_Not_Covered)
1257             return false;
1258         face->glyphs_substituted = (error != HB_Err_Not_Covered);
1259     }
1260
1261 #ifdef OT_DEBUG
1262 //     DEBUG("log clusters before shaping:");
1263 //     for (int j = 0; j < length; j++)
1264 //         DEBUG("    log[%d] = %d", j, item->log_clusters[j]);
1265     DEBUG("shaped glyphs:");
1266     for (int i = 0; i < length; ++i)
1267         DEBUG("   glyph=%4x", hb_buffer->in_string[i].gindex);
1268     DEBUG("-----------------------------------------");
1269 //     dump_string(hb_buffer);
1270 #endif
1271
1272     return true;
1273 }
1274
1275 HB_Bool HB_OpenTypePosition(HB_ShaperItem *item, int availableGlyphs, HB_Bool doLogClusters)
1276 {
1277     HB_Face face = item->face;
1278
1279     bool glyphs_positioned = false;
1280     if (face->gpos) {
1281         if (face->buffer->positions)
1282             memset(face->buffer->positions, 0, face->buffer->in_length*sizeof(HB_PositionRec));
1283         // #### check that passing "false,false" is correct
1284         glyphs_positioned = HB_GPOS_Apply_String(item->font, face->gpos, face->current_flags, face->buffer, false, false) != HB_Err_Not_Covered;
1285     }
1286
1287     if (!face->glyphs_substituted && !glyphs_positioned) {
1288         HB_HeuristicPosition(item);
1289         return true; // nothing to do for us
1290     }
1291
1292     // make sure we have enough space to write everything back
1293     if (availableGlyphs < (int)face->buffer->in_length) {
1294         item->num_glyphs = face->buffer->in_length;
1295         return false;
1296     }
1297
1298     HB_Glyph *glyphs = item->glyphs;
1299     HB_GlyphAttributes *attributes = item->attributes;
1300
1301     for (unsigned int i = 0; i < face->buffer->in_length; ++i) {
1302         glyphs[i] = face->buffer->in_string[i].gindex;
1303         attributes[i] = face->tmpAttributes[face->buffer->in_string[i].cluster];
1304         if (i && face->buffer->in_string[i].cluster == face->buffer->in_string[i-1].cluster)
1305             attributes[i].clusterStart = false;
1306     }
1307     item->num_glyphs = face->buffer->in_length;
1308
1309     if (doLogClusters && face->glyphs_substituted) {
1310         // we can't do this for indic, as we pass the stuf in syllables and it's easier to do it in the shaper.
1311         unsigned short *logClusters = item->log_clusters;
1312         int clusterStart = 0;
1313         int oldCi = 0;
1314         // #### the reconstruction of the logclusters currently does not work if the original string
1315         // contains surrogate pairs
1316         for (unsigned int i = 0; i < face->buffer->in_length; ++i) {
1317             int ci = face->buffer->in_string[i].cluster;
1318             //         DEBUG("   ci[%d] = %d mark=%d, cmb=%d, cs=%d",
1319             //                i, ci, glyphAttributes[i].mark, glyphAttributes[i].combiningClass, glyphAttributes[i].clusterStart);
1320             if (!attributes[i].mark && attributes[i].clusterStart && ci != oldCi) {
1321                 for (int j = oldCi; j < ci; j++)
1322                     logClusters[j] = clusterStart;
1323                 clusterStart = i;
1324                 oldCi = ci;
1325             }
1326         }
1327         for (int j = oldCi; j < face->length; j++)
1328             logClusters[j] = clusterStart;
1329     }
1330
1331     // calulate the advances for the shaped glyphs
1332 //     DEBUG("unpositioned: ");
1333
1334     // positioning code:
1335     if (glyphs_positioned) {
1336         HB_GetGlyphAdvances(item);
1337         HB_Position positions = face->buffer->positions;
1338         HB_Fixed *advances = item->advances;
1339
1340 //         DEBUG("positioned glyphs:");
1341         for (unsigned int i = 0; i < face->buffer->in_length; i++) {
1342 //             DEBUG("    %d:\t orig advance: (%d/%d)\tadv=(%d/%d)\tpos=(%d/%d)\tback=%d\tnew_advance=%d", i,
1343 //                    glyphs[i].advance.x.toInt(), glyphs[i].advance.y.toInt(),
1344 //                    (int)(positions[i].x_advance >> 6), (int)(positions[i].y_advance >> 6),
1345 //                    (int)(positions[i].x_pos >> 6), (int)(positions[i].y_pos >> 6),
1346 //                    positions[i].back, positions[i].new_advance);
1347
1348             HB_Fixed adjustment = positions[i].x_advance;
1349
1350             if (!(face->current_flags & HB_ShaperFlag_UseDesignMetrics))
1351                 adjustment = HB_FIXED_ROUND(adjustment);
1352
1353             if (positions[i].new_advance) {
1354                 advances[i] = adjustment;
1355             } else {
1356                 advances[i] += adjustment;
1357             }
1358
1359             int back = 0;
1360             HB_FixedPoint *offsets = item->offsets;
1361             offsets[i].x = positions[i].x_pos;
1362             offsets[i].y = positions[i].y_pos;
1363             while (positions[i - back].back) {
1364                 back += positions[i - back].back;
1365                 offsets[i].x += positions[i - back].x_pos;
1366                 offsets[i].y += positions[i - back].y_pos;
1367             }
1368             offsets[i].y = -offsets[i].y;
1369
1370             if (item->item.bidiLevel % 2) {
1371                 // ### may need to go back multiple glyphs like in ltr
1372                 back = positions[i].back;
1373                 while (back--)
1374                     offsets[i].x -= advances[i-back];
1375             } else {
1376                 back = 0;
1377                 while (positions[i - back].back) {
1378                     back += positions[i - back].back;
1379                     offsets[i].x -= advances[i-back];
1380                 }
1381             }
1382 //             DEBUG("   ->\tadv=%d\tpos=(%d/%d)",
1383 //                    glyphs[i].advance.x.toInt(), glyphs[i].offset.x.toInt(), glyphs[i].offset.y.toInt());
1384         }
1385         item->kerning_applied = face->has_opentype_kerning;
1386     } else {
1387         HB_HeuristicPosition(item);
1388     }
1389
1390 #ifdef OT_DEBUG
1391     if (doLogClusters) {
1392         DEBUG("log clusters after shaping:\n");
1393         for (unsigned int j = 0; j < item->item.length; j++)
1394             DEBUG("    log[%d] = %d\n", j, item->log_clusters[j]);
1395     }
1396     DEBUG("final glyphs:\n");
1397     for (unsigned int i = 0; i < item->num_glyphs; ++i)
1398         DEBUG("   glyph=%4x char_index=%d mark: %d cmp: %d, clusterStart: %d advance=%d offset=%d/%d\n",
1399                glyphs[i], face->buffer->in_string[i].cluster, attributes[i].mark,
1400                attributes[i].combiningClass, attributes[i].clusterStart,
1401                item->advances[i] >> 6,
1402                item->offsets[i].x >> 6, item->offsets[i].y >> 6);
1403     DEBUG("-----------------------------------------\n");
1404 #endif
1405     return true;
1406 }
1407
1408 HB_Bool HB_ShapeItem(HB_ShaperItem *shaper_item)
1409 {
1410     HB_Bool result = false;
1411     if (shaper_item->num_glyphs < shaper_item->item.length) {
1412         shaper_item->num_glyphs = shaper_item->item.length;
1413         return false;
1414     }
1415     assert(shaper_item->item.script < HB_ScriptCount);
1416     result = HB_ScriptEngines[shaper_item->item.script].shape(shaper_item);
1417     shaper_item->glyphIndicesPresent = false;
1418     return result;
1419 }
1420