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