Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(424)

Side by Side Diff: third_party/harfbuzz/src/harfbuzz-shaper.cpp

Issue 12413010: Remove unused harfbuzz. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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.htm l
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, P B, 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, D B, 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, I B, 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, I B, 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, D B, 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, D B, 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, D B, 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, D B, 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, D B, 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, D B, 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, D B, 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, D B, 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, D B, 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, D B, 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, D B, 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, D B, 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, I B, 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, P B, 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, D B, 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, D B, 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, I B, 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, D B, 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, D B, 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, D B, 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, D B, 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, D B, 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_CharAttribute s *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_LineBrea k_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_ForcedBr eak;
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 ana lysis), the unicode
189 // standard recommends to treat them as AL. thai_attributes and othe r 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_NoBrea k;
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, baseI nfo.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 bool rightToLeft = item->item.bidiLevel % 2;
269
270 int i;
271 unsigned char lastCmb = 0;
272 HB_GlyphMetrics attachmentRect;
273 memset(&attachmentRect, 0, sizeof(attachmentRect));
274
275 for(i = 1; i <= nmarks; i++) {
276 HB_Glyph mark = glyphs[gfrom+i];
277 HB_GlyphMetrics markMetrics;
278 item->font->klass->getGlyphMetrics(item->font, mark, &markMetrics);
279 HB_FixedPoint p;
280 p.x = p.y = 0;
281 // qDebug("markInfo: %f/%f (%f/%f) off=%f/%f", markInfo.x, markInfo.y, markInfo.width, markInfo.height, markInfo.xoff, markInfo.yoff);
282
283 HB_Fixed offset = offsetBase;
284 unsigned char cmb = attributes[gfrom+i].combiningClass;
285
286 // ### maybe the whole position determination should move down to heuris ticSetGlyphAttributes. Would save some
287 // bits in the glyphAttributes structure.
288 if (cmb < 200) {
289 // fixed position classes. We approximate by mapping to one of the o thers.
290 // currently I added only the ones for arabic, hebrew, lao and thai.
291
292 // for Lao and Thai marks with class 0, see below (heuristicSetGlyph Attributes)
293
294 // add a bit more offset to arabic, a bit hacky
295 if (cmb >= 27 && cmb <= 36 && offset < 3)
296 offset +=1;
297 // below
298 if ((cmb >= 10 && cmb <= 18) ||
299 cmb == 20 || cmb == 22 ||
300 cmb == 29 || cmb == 32)
301 cmb = HB_Combining_Below;
302 // above
303 else if (cmb == 23 || cmb == 27 || cmb == 28 ||
304 cmb == 30 || cmb == 31 || (cmb >= 33 && cmb <= 36))
305 cmb = HB_Combining_Above;
306 //below-right
307 else if (cmb == 9 || cmb == 103 || cmb == 118)
308 cmb = HB_Combining_BelowRight;
309 // above-right
310 else if (cmb == 24 || cmb == 107 || cmb == 122)
311 cmb = HB_Combining_AboveRight;
312 else if (cmb == 25)
313 cmb = HB_Combining_AboveLeft;
314 // fixed:
315 // 19 21
316
317 }
318
319 // combining marks of different class don't interact. Reset the rectangl e.
320 if (cmb != lastCmb) {
321 //qDebug("resetting rect");
322 attachmentRect = baseMetrics;
323 }
324
325 switch(cmb) {
326 case HB_Combining_DoubleBelow:
327 // ### wrong in rtl context!
328 case HB_Combining_BelowLeft:
329 p.y += offset;
330 case HB_Combining_BelowLeftAttached:
331 p.x += attachmentRect.x - markMetrics.x;
332 p.y += (attachmentRect.y + attachmentRect.height) - markMetrics.y;
333 break;
334 case HB_Combining_Below:
335 p.y += offset;
336 case HB_Combining_BelowAttached:
337 p.x += attachmentRect.x - markMetrics.x;
338 p.y += (attachmentRect.y + attachmentRect.height) - markMetrics.y;
339
340 p.x += (attachmentRect.width - markMetrics.width) / 2;
341 break;
342 case HB_Combining_BelowRight:
343 p.y += offset;
344 case HB_Combining_BelowRightAttached:
345 p.x += attachmentRect.x + attachmentRect.width - markMetrics.width - markMetrics.x;
346 p.y += attachmentRect.y + attachmentRect.height - markMetrics.y;
347 break;
348 case HB_Combining_Left:
349 p.x -= offset;
350 case HB_Combining_LeftAttached:
351 break;
352 case HB_Combining_Right:
353 p.x += offset;
354 case HB_Combining_RightAttached:
355 break;
356 case HB_Combining_DoubleAbove:
357 // ### wrong in RTL context!
358 case HB_Combining_AboveLeft:
359 p.y -= offset;
360 case HB_Combining_AboveLeftAttached:
361 p.x += attachmentRect.x - markMetrics.x;
362 p.y += attachmentRect.y - markMetrics.y - markMetrics.height;
363 break;
364 case HB_Combining_Above:
365 p.y -= offset;
366 case HB_Combining_AboveAttached:
367 p.x += attachmentRect.x - markMetrics.x;
368 p.y += attachmentRect.y - markMetrics.y - markMetrics.height;
369
370 p.x += (attachmentRect.width - markMetrics.width) / 2;
371 break;
372 case HB_Combining_AboveRight:
373 p.y -= offset;
374 case HB_Combining_AboveRightAttached:
375 p.x += attachmentRect.x + attachmentRect.width - markMetrics.x - mar kMetrics.width;
376 p.y += attachmentRect.y - markMetrics.y - markMetrics.height;
377 break;
378
379 case HB_Combining_IotaSubscript:
380 default:
381 break;
382 }
383 // qDebug("char=%x combiningClass = %d offset=%f/%f", mark, cmb, p.x(), p.y());
384 markMetrics.x += p.x;
385 markMetrics.y += p.y;
386
387 HB_GlyphMetrics unitedAttachmentRect = attachmentRect;
388 unitedAttachmentRect.x = HB_MIN(attachmentRect.x, markMetrics.x);
389 unitedAttachmentRect.y = HB_MIN(attachmentRect.y, markMetrics.y);
390 unitedAttachmentRect.width = HB_MAX(attachmentRect.x + attachmentRect.wi dth, markMetrics.x + markMetrics.width) - unitedAttachmentRect.x;
391 unitedAttachmentRect.height = HB_MAX(attachmentRect.y + attachmentRect.h eight, markMetrics.y + markMetrics.height) - unitedAttachmentRect.y;
392 attachmentRect = unitedAttachmentRect;
393
394 lastCmb = cmb;
395 if (rightToLeft) {
396 item->offsets[gfrom+i].x = p.x;
397 item->offsets[gfrom+i].y = p.y;
398 } else {
399 item->offsets[gfrom+i].x = p.x - baseMetrics.xOffset;
400 item->offsets[gfrom+i].y = p.y - baseMetrics.yOffset;
401 }
402 item->advances[gfrom+i] = 0;
403 }
404 }
405
406 void HB_HeuristicPosition(HB_ShaperItem *item)
407 {
408 HB_GetGlyphAdvances(item);
409 HB_GlyphAttributes *attributes = item->attributes;
410
411 int cEnd = -1;
412 int i = item->num_glyphs;
413 while (i--) {
414 if (cEnd == -1 && attributes[i].mark) {
415 cEnd = i;
416 } else if (cEnd != -1 && !attributes[i].mark) {
417 positionCluster(item, i, cEnd);
418 cEnd = -1;
419 }
420 }
421 }
422
423 // set the glyph attributes heuristically. Assumes a 1 to 1 relationship between chars and glyphs
424 // and no reordering.
425 // also computes logClusters heuristically
426 void HB_HeuristicSetGlyphAttributes(HB_ShaperItem *item)
427 {
428 const HB_UChar16 *uc = item->string + item->item.pos;
429 hb_uint32 length = item->item.length;
430
431 // ### zeroWidth and justification are missing here!!!!!
432
433 // qDebug("QScriptEngine::heuristicSetGlyphAttributes, num_glyphs=%d", item- >num_glyphs);
434 HB_GlyphAttributes *attributes = item->attributes;
435 unsigned short *logClusters = item->log_clusters;
436
437 hb_uint32 glyph_pos = 0;
438 hb_uint32 i;
439 for (i = 0; i < length; i++) {
440 if (HB_IsHighSurrogate(uc[i]) && i < length - 1
441 && HB_IsLowSurrogate(uc[i + 1])) {
442 logClusters[i] = glyph_pos;
443 logClusters[++i] = glyph_pos;
444 } else {
445 logClusters[i] = glyph_pos;
446 }
447 ++glyph_pos;
448 }
449
450 // first char in a run is never (treated as) a mark
451 int cStart = 0;
452 const bool symbolFont = item->face->isSymbolFont;
453 attributes[0].mark = false;
454 attributes[0].clusterStart = true;
455 attributes[0].dontPrint = (!symbolFont && uc[0] == 0x00ad) || HB_IsControlCh ar(uc[0]);
456
457 int pos = 0;
458 HB_CharCategory lastCat;
459 int dummy;
460 HB_GetUnicodeCharProperties(uc[0], &lastCat, &dummy);
461 for (i = 1; i < length; ++i) {
462 if (logClusters[i] == pos)
463 // same glyph
464 continue;
465 ++pos;
466 while (pos < logClusters[i]) {
467 attributes[pos] = attributes[pos-1];
468 ++pos;
469 }
470 // hide soft-hyphens by default
471 if ((!symbolFont && uc[i] == 0x00ad) || HB_IsControlChar(uc[i]))
472 attributes[pos].dontPrint = true;
473 HB_CharCategory cat;
474 int cmb;
475 HB_GetUnicodeCharProperties(uc[i], &cat, &cmb);
476 if (cat != HB_Mark_NonSpacing) {
477 attributes[pos].mark = false;
478 attributes[pos].clusterStart = true;
479 attributes[pos].combiningClass = 0;
480 cStart = logClusters[i];
481 } else {
482 if (cmb == 0) {
483 // Fix 0 combining classes
484 if ((uc[pos] & 0xff00) == 0x0e00) {
485 // thai or lao
486 if (uc[pos] == 0xe31 ||
487 uc[pos] == 0xe34 ||
488 uc[pos] == 0xe35 ||
489 uc[pos] == 0xe36 ||
490 uc[pos] == 0xe37 ||
491 uc[pos] == 0xe47 ||
492 uc[pos] == 0xe4c ||
493 uc[pos] == 0xe4d ||
494 uc[pos] == 0xe4e) {
495 cmb = HB_Combining_AboveRight;
496 } else if (uc[pos] == 0xeb1 ||
497 uc[pos] == 0xeb4 ||
498 uc[pos] == 0xeb5 ||
499 uc[pos] == 0xeb6 ||
500 uc[pos] == 0xeb7 ||
501 uc[pos] == 0xebb ||
502 uc[pos] == 0xecc ||
503 uc[pos] == 0xecd) {
504 cmb = HB_Combining_Above;
505 } else if (uc[pos] == 0xebc) {
506 cmb = HB_Combining_Below;
507 }
508 }
509 }
510
511 attributes[pos].mark = true;
512 attributes[pos].clusterStart = false;
513 attributes[pos].combiningClass = cmb;
514 logClusters[i] = cStart;
515 }
516 // one gets an inter character justification point if the current char i s not a non spacing mark.
517 // as then the current char belongs to the last one and one gets a space justification point
518 // after the space char.
519 if (lastCat == HB_Separator_Space)
520 attributes[pos-1].justification = HB_Space;
521 else if (cat != HB_Mark_NonSpacing)
522 attributes[pos-1].justification = HB_Character;
523 else
524 attributes[pos-1].justification = HB_NoJustification;
525
526 lastCat = cat;
527 }
528 pos = logClusters[length-1];
529 if (lastCat == HB_Separator_Space)
530 attributes[pos].justification = HB_Space;
531 else
532 attributes[pos].justification = HB_Character;
533 }
534
535 #ifndef NO_OPENTYPE
536 static const HB_OpenTypeFeature basic_features[] = {
537 { HB_MAKE_TAG('c', 'c', 'm', 'p'), CcmpProperty },
538 { HB_MAKE_TAG('l', 'i', 'g', 'a'), CcmpProperty },
539 { HB_MAKE_TAG('c', 'l', 'i', 'g'), CcmpProperty },
540 {0, 0}
541 };
542 #endif
543
544 HB_Bool HB_ConvertStringToGlyphIndices(HB_ShaperItem *shaper_item)
545 {
546 if (shaper_item->glyphIndicesPresent) {
547 shaper_item->num_glyphs = shaper_item->initialGlyphCount;
548 shaper_item->glyphIndicesPresent = false;
549 return true;
550 }
551 return shaper_item->font->klass
552 ->convertStringToGlyphIndices(shaper_item->font,
553 shaper_item->string + shaper_item->item .pos, shaper_item->item.length,
554 shaper_item->glyphs, &shaper_item->num_ glyphs,
555 shaper_item->item.bidiLevel % 2);
556 }
557
558 HB_Bool HB_BasicShape(HB_ShaperItem *shaper_item)
559 {
560 #ifndef NO_OPENTYPE
561 const int availableGlyphs = shaper_item->num_glyphs;
562 #endif
563
564 if (!HB_ConvertStringToGlyphIndices(shaper_item))
565 return false;
566
567 HB_HeuristicSetGlyphAttributes(shaper_item);
568
569 #ifndef NO_OPENTYPE
570 if (HB_SelectScript(shaper_item, basic_features)) {
571 HB_OpenTypeShape(shaper_item, /*properties*/0);
572 return HB_OpenTypePosition(shaper_item, availableGlyphs, /*doLogClusters */true);
573 }
574 #endif
575
576 HB_HeuristicPosition(shaper_item);
577 return true;
578 }
579
580 const HB_ScriptEngine HB_ScriptEngines[] = {
581 // Common
582 { HB_BasicShape, 0},
583 // Greek
584 { HB_GreekShape, 0},
585 // Cyrillic
586 { HB_BasicShape, 0},
587 // Armenian
588 { HB_BasicShape, 0},
589 // Hebrew
590 { HB_HebrewShape, 0 },
591 // Arabic
592 { HB_ArabicShape, 0},
593 // Syriac
594 { HB_ArabicShape, 0},
595 // Thaana
596 { HB_BasicShape, 0 },
597 // Devanagari
598 { HB_IndicShape, HB_IndicAttributes },
599 // Bengali
600 { HB_IndicShape, HB_IndicAttributes },
601 // Gurmukhi
602 { HB_IndicShape, HB_IndicAttributes },
603 // Gujarati
604 { HB_IndicShape, HB_IndicAttributes },
605 // Oriya
606 { HB_IndicShape, HB_IndicAttributes },
607 // Tamil
608 { HB_IndicShape, HB_IndicAttributes },
609 // Telugu
610 { HB_IndicShape, HB_IndicAttributes },
611 // Kannada
612 { HB_IndicShape, HB_IndicAttributes },
613 // Malayalam
614 { HB_IndicShape, HB_IndicAttributes },
615 // Sinhala
616 { HB_IndicShape, HB_IndicAttributes },
617 // Thai
618 { HB_BasicShape, HB_ThaiAttributes },
619 // Lao
620 { HB_BasicShape, 0 },
621 // Tibetan
622 { HB_TibetanShape, HB_TibetanAttributes },
623 // Myanmar
624 { HB_MyanmarShape, HB_MyanmarAttributes },
625 // Georgian
626 { HB_BasicShape, 0 },
627 // Hangul
628 { HB_HangulShape, 0 },
629 // Ogham
630 { HB_BasicShape, 0 },
631 // Runic
632 { HB_BasicShape, 0 },
633 // Khmer
634 { HB_KhmerShape, HB_KhmerAttributes },
635 // N'Ko
636 { HB_ArabicShape, 0}
637 };
638
639 void HB_GetCharAttributes(const HB_UChar16 *string, hb_uint32 stringLength,
640 const HB_ScriptItem *items, hb_uint32 numItems,
641 HB_CharAttributes *attributes)
642 {
643 calcLineBreaks(string, stringLength, attributes);
644
645 for (hb_uint32 i = 0; i < numItems; ++i) {
646 HB_Script script = items[i].script;
647 if (script == HB_Script_Inherited)
648 script = HB_Script_Common;
649 HB_AttributeFunction attributeFunction = HB_ScriptEngines[script].charAt tributes;
650 if (!attributeFunction)
651 continue;
652 attributeFunction(script, string, items[i].pos, items[i].length, attribu tes);
653 }
654 }
655
656
657 enum BreakRule { NoBreak = 0, Break = 1, Middle = 2 };
658
659 static const hb_uint8 wordbreakTable[HB_Word_ExtendNumLet + 1][HB_Word_ExtendNum Let + 1] = {
660 // Other Format Katakana ALetter MidLetter MidNum Numeric ExtendN umLet
661 { Break, Break, Break, Break, Break, Break, Break, Break }, // Other
662 { Break, Break, Break, Break, Break, Break, Break, Break }, // Format
663 { Break, Break, NoBreak, Break, Break, Break, Break, NoBreak }, // Katakana
664 { Break, Break, Break, NoBreak, Middle, Break, NoBreak, NoBreak }, // ALetter
665 { Break, Break, Break, Break, Break, Break, Break, Break }, // MidLetter
666 { Break, Break, Break, Break, Break, Break, Break, Break }, // MidNum
667 { Break, Break, Break, NoBreak, Break, Middle, NoBreak, NoBreak }, // Numeric
668 { Break, Break, NoBreak, NoBreak, Break, Break, NoBreak, NoBreak }, // ExtendNumLet
669 };
670
671 void HB_GetWordBoundaries(const HB_UChar16 *string, hb_uint32 stringLength,
672 const HB_ScriptItem * /*items*/, hb_uint32 /*numItems* /,
673 HB_CharAttributes *attributes)
674 {
675 if (stringLength == 0)
676 return;
677 unsigned int brk = HB_GetWordClass(string[0]);
678 attributes[0].wordBoundary = true;
679 for (hb_uint32 i = 1; i < stringLength; ++i) {
680 if (!attributes[i].charStop) {
681 attributes[i].wordBoundary = false;
682 continue;
683 }
684 hb_uint32 nbrk = HB_GetWordClass(string[i]);
685 if (nbrk == HB_Word_Format) {
686 attributes[i].wordBoundary = (HB_GetSentenceClass(string[i-1]) == HB _Sentence_Sep);
687 continue;
688 }
689 BreakRule rule = (BreakRule)wordbreakTable[brk][nbrk];
690 if (rule == Middle) {
691 rule = Break;
692 hb_uint32 lookahead = i + 1;
693 while (lookahead < stringLength) {
694 hb_uint32 testbrk = HB_GetWordClass(string[lookahead]);
695 if (testbrk == HB_Word_Format && HB_GetSentenceClass(string[look ahead]) != HB_Sentence_Sep) {
696 ++lookahead;
697 continue;
698 }
699 if (testbrk == brk) {
700 rule = NoBreak;
701 while (i < lookahead)
702 attributes[i++].wordBoundary = false;
703 nbrk = testbrk;
704 }
705 break;
706 }
707 }
708 attributes[i].wordBoundary = (rule == Break);
709 brk = nbrk;
710 }
711 }
712
713
714 enum SentenceBreakStates {
715 SB_Initial,
716 SB_Upper,
717 SB_UpATerm,
718 SB_ATerm,
719 SB_ATermC,
720 SB_ACS,
721 SB_STerm,
722 SB_STermC,
723 SB_SCS,
724 SB_BAfter,
725 SB_Break,
726 SB_Look
727 };
728
729 static const hb_uint8 sentenceBreakTable[HB_Sentence_Close + 1][HB_Sentence_Clos e + 1] = {
730 // Other Sep Format Sp Lower Upper OLetter Numeric ATerm STerm Close
731 { SB_Initial, SB_BAfter , SB_Initial, SB_Initial, SB_Initial, SB_Upper , SB_Initial, SB_Initial, SB_ATerm , SB_STerm , SB_Initial }, // SB_Initial,
732 { SB_Initial, SB_BAfter , SB_Upper , SB_Initial, SB_Initial, SB_Upper , SB_Initial, SB_Initial, SB_UpATerm, SB_STerm , SB_Initial }, // SB_Upper
733
734 { SB_Look , SB_BAfter , SB_UpATerm, SB_ACS , SB_Initial, SB_Upper , SB_Break , SB_Initial, SB_ATerm , SB_STerm , SB_ATermC }, // SB_UpATerm
735 { SB_Look , SB_BAfter , SB_ATerm , SB_ACS , SB_Initial, SB_Break , SB_Break , SB_Initial, SB_ATerm , SB_STerm , SB_ATermC }, // SB_ATerm
736 { SB_Look , SB_BAfter , SB_ATermC , SB_ACS , SB_Initial, SB_Break , SB_Break , SB_Look , SB_ATerm , SB_STerm , SB_ATermC }, // SB_ATermC,
737 { SB_Look , SB_BAfter , SB_ACS , SB_ACS , SB_Initial, SB_Break , SB_Break , SB_Look , SB_ATerm , SB_STerm , SB_Look }, // SB_ACS,
738
739 { SB_Break , SB_BAfter , SB_STerm , SB_SCS , SB_Break , SB_Break , SB_Break , SB_Break , SB_ATerm , SB_STerm , SB_STermC }, // SB_STerm,
740 { SB_Break , SB_BAfter , SB_STermC , SB_SCS , SB_Break , SB_Break , SB_Break , SB_Break , SB_ATerm , SB_STerm , SB_STermC }, // SB_STermC,
741 { SB_Break , SB_BAfter , SB_SCS , SB_SCS , SB_Break , SB_Break , SB_Break , SB_Break , SB_ATerm , SB_STerm , SB_Break }, // SB_SCS,
742 { SB_Break , SB_Break , SB_Break , SB_Break , SB_Break , SB_Break , SB_Break , SB_Break , SB_Break , SB_Break , SB_Break }, // SB_BAfter,
743 };
744
745 void HB_GetSentenceBoundaries(const HB_UChar16 *string, hb_uint32 stringLength,
746 const HB_ScriptItem * /*items*/, hb_uint32 /*numIt ems*/,
747 HB_CharAttributes *attributes)
748 {
749 if (stringLength == 0)
750 return;
751 hb_uint32 brk = sentenceBreakTable[SB_Initial][HB_GetSentenceClass(string[0] )];
752 attributes[0].sentenceBoundary = true;
753 for (hb_uint32 i = 1; i < stringLength; ++i) {
754 if (!attributes[i].charStop) {
755 attributes[i].sentenceBoundary = false;
756 continue;
757 }
758 brk = sentenceBreakTable[brk][HB_GetSentenceClass(string[i])];
759 if (brk == SB_Look) {
760 brk = SB_Break;
761 hb_uint32 lookahead = i + 1;
762 while (lookahead < stringLength) {
763 hb_uint32 sbrk = HB_GetSentenceClass(string[lookahead]);
764 if (sbrk != HB_Sentence_Other && sbrk != HB_Sentence_Numeric && sbrk != HB_Sentence_Close) {
765 break;
766 } else if (sbrk == HB_Sentence_Lower) {
767 brk = SB_Initial;
768 break;
769 }
770 ++lookahead;
771 }
772 if (brk == SB_Initial) {
773 while (i < lookahead)
774 attributes[i++].sentenceBoundary = false;
775 }
776 }
777 if (brk == SB_Break) {
778 attributes[i].sentenceBoundary = true;
779 brk = sentenceBreakTable[SB_Initial][HB_GetSentenceClass(string[i])] ;
780 } else {
781 attributes[i].sentenceBoundary = false;
782 }
783 }
784 }
785
786
787 static inline char *tag_to_string(HB_UInt tag)
788 {
789 static char string[5];
790 string[0] = (tag >> 24)&0xff;
791 string[1] = (tag >> 16)&0xff;
792 string[2] = (tag >> 8)&0xff;
793 string[3] = tag&0xff;
794 string[4] = 0;
795 return string;
796 }
797
798 #ifdef OT_DEBUG
799 static void dump_string(HB_Buffer buffer)
800 {
801 for (uint i = 0; i < buffer->in_length; ++i) {
802 qDebug(" %x: cluster=%d", buffer->in_string[i].gindex, buffer->in_str ing[i].cluster);
803 }
804 }
805 #define DEBUG printf
806 #else
807 #define DEBUG if (1) ; else printf
808 #endif
809
810 #define DefaultLangSys 0xffff
811 #define DefaultScript HB_MAKE_TAG('D', 'F', 'L', 'T')
812
813 enum {
814 RequiresGsub = 1,
815 RequiresGpos = 2
816 };
817
818 struct OTScripts {
819 unsigned int tag;
820 int flags;
821 };
822 static const OTScripts ot_scripts [] = {
823 // Common
824 { HB_MAKE_TAG('l', 'a', 't', 'n'), 0 },
825 // Greek
826 { HB_MAKE_TAG('g', 'r', 'e', 'k'), 0 },
827 // Cyrillic
828 { HB_MAKE_TAG('c', 'y', 'r', 'l'), 0 },
829 // Armenian
830 { HB_MAKE_TAG('a', 'r', 'm', 'n'), 0 },
831 // Hebrew
832 { HB_MAKE_TAG('h', 'e', 'b', 'r'), 1 },
833 // Arabic
834 { HB_MAKE_TAG('a', 'r', 'a', 'b'), 1 },
835 // Syriac
836 { HB_MAKE_TAG('s', 'y', 'r', 'c'), 1 },
837 // Thaana
838 { HB_MAKE_TAG('t', 'h', 'a', 'a'), 1 },
839 // Devanagari
840 { HB_MAKE_TAG('d', 'e', 'v', 'a'), 1 },
841 // Bengali
842 { HB_MAKE_TAG('b', 'e', 'n', 'g'), 1 },
843 // Gurmukhi
844 { HB_MAKE_TAG('g', 'u', 'r', 'u'), 1 },
845 // Gujarati
846 { HB_MAKE_TAG('g', 'u', 'j', 'r'), 1 },
847 // Oriya
848 { HB_MAKE_TAG('o', 'r', 'y', 'a'), 1 },
849 // Tamil
850 { HB_MAKE_TAG('t', 'a', 'm', 'l'), 1 },
851 // Telugu
852 { HB_MAKE_TAG('t', 'e', 'l', 'u'), 1 },
853 // Kannada
854 { HB_MAKE_TAG('k', 'n', 'd', 'a'), 1 },
855 // Malayalam
856 { HB_MAKE_TAG('m', 'l', 'y', 'm'), 1 },
857 // Sinhala
858 { HB_MAKE_TAG('s', 'i', 'n', 'h'), 1 },
859 // Thai
860 { HB_MAKE_TAG('t', 'h', 'a', 'i'), 1 },
861 // Lao
862 { HB_MAKE_TAG('l', 'a', 'o', ' '), 1 },
863 // Tibetan
864 { HB_MAKE_TAG('t', 'i', 'b', 't'), 1 },
865 // Myanmar
866 { HB_MAKE_TAG('m', 'y', 'm', 'r'), 1 },
867 // Georgian
868 { HB_MAKE_TAG('g', 'e', 'o', 'r'), 0 },
869 // Hangul
870 { HB_MAKE_TAG('h', 'a', 'n', 'g'), 1 },
871 // Ogham
872 { HB_MAKE_TAG('o', 'g', 'a', 'm'), 0 },
873 // Runic
874 { HB_MAKE_TAG('r', 'u', 'n', 'r'), 0 },
875 // Khmer
876 { HB_MAKE_TAG('k', 'h', 'm', 'r'), 1 },
877 // N'Ko
878 { HB_MAKE_TAG('n', 'k', 'o', ' '), 1 }
879 };
880 enum { NumOTScripts = sizeof(ot_scripts)/sizeof(OTScripts) };
881
882 static HB_Bool checkScript(HB_Face face, int script)
883 {
884 assert(script < HB_ScriptCount);
885
886 if (!face->gsub && !face->gpos)
887 return false;
888
889 unsigned int tag = ot_scripts[script].tag;
890 int requirements = ot_scripts[script].flags;
891
892 if (requirements & RequiresGsub) {
893 if (!face->gsub)
894 return false;
895
896 HB_UShort script_index;
897 HB_Error error = HB_GSUB_Select_Script(face->gsub, tag, &script_index);
898 if (error) {
899 DEBUG("could not select script %d in GSub table: %d", (int)script, e rror);
900 error = HB_GSUB_Select_Script(face->gsub, HB_MAKE_TAG('D', 'F', 'L', 'T'), &script_index);
901 if (error)
902 return false;
903 }
904 }
905
906 if (requirements & RequiresGpos) {
907 if (!face->gpos)
908 return false;
909
910 HB_UShort script_index;
911 HB_Error error = HB_GPOS_Select_Script(face->gpos, script, &script_index );
912 if (error) {
913 DEBUG("could not select script in gpos table: %d", error);
914 error = HB_GPOS_Select_Script(face->gpos, HB_MAKE_TAG('D', 'F', 'L', 'T'), &script_index);
915 if (error)
916 return false;
917 }
918
919 }
920 return true;
921 }
922
923 static HB_Stream getTableStream(void *font, HB_GetFontTableFunc tableFunc, HB_Ta g tag)
924 {
925 HB_Error error;
926 HB_UInt length = 0;
927 HB_Stream stream = 0;
928
929 if (!font)
930 return 0;
931
932 error = tableFunc(font, tag, 0, &length);
933 if (error)
934 return 0;
935 stream = (HB_Stream)malloc(sizeof(HB_StreamRec));
936 if (!stream)
937 return 0;
938 stream->base = (HB_Byte*)malloc(length);
939 if (!stream->base) {
940 free(stream);
941 return 0;
942 }
943 error = tableFunc(font, tag, stream->base, &length);
944 if (error) {
945 _hb_close_stream(stream);
946 return 0;
947 }
948 stream->size = length;
949 stream->pos = 0;
950 stream->cursor = NULL;
951 return stream;
952 }
953
954 HB_Face HB_NewFace(void *font, HB_GetFontTableFunc tableFunc)
955 {
956 HB_Face face = (HB_Face )malloc(sizeof(HB_FaceRec));
957 if (!face)
958 return 0;
959
960 face->isSymbolFont = false;
961 face->gdef = 0;
962 face->gpos = 0;
963 face->gsub = 0;
964 face->current_script = HB_ScriptCount;
965 face->current_flags = HB_ShaperFlag_Default;
966 face->has_opentype_kerning = false;
967 face->tmpAttributes = 0;
968 face->tmpLogClusters = 0;
969 face->glyphs_substituted = false;
970 face->buffer = 0;
971
972 HB_Error error = HB_Err_Ok;
973 HB_Stream stream;
974 HB_Stream gdefStream;
975
976 gdefStream = getTableStream(font, tableFunc, TTAG_GDEF);
977 error = HB_Err_Not_Covered;
978 if (!gdefStream || (error = HB_Load_GDEF_Table(gdefStream, &face->gdef))) {
979 //DEBUG("error loading gdef table: %d", error);
980 face->gdef = 0;
981 }
982
983 //DEBUG() << "trying to load gsub table";
984 stream = getTableStream(font, tableFunc, TTAG_GSUB);
985 error = HB_Err_Not_Covered;
986 if (!stream || (error = HB_Load_GSUB_Table(stream, &face->gsub, face->gdef, gdefStream))) {
987 face->gsub = 0;
988 if (error != HB_Err_Not_Covered) {
989 //DEBUG("error loading gsub table: %d", error);
990 } else {
991 //DEBUG("face doesn't have a gsub table");
992 }
993 }
994 _hb_close_stream(stream);
995
996 stream = getTableStream(font, tableFunc, TTAG_GPOS);
997 error = HB_Err_Not_Covered;
998 if (!stream || (error = HB_Load_GPOS_Table(stream, &face->gpos, face->gdef, gdefStream))) {
999 face->gpos = 0;
1000 DEBUG("error loading gpos table: %d", error);
1001 }
1002 _hb_close_stream(stream);
1003
1004 _hb_close_stream(gdefStream);
1005
1006 for (unsigned int i = 0; i < HB_ScriptCount; ++i)
1007 face->supported_scripts[i] = checkScript(face, i);
1008
1009 if (hb_buffer_new(&face->buffer) != HB_Err_Ok) {
1010 HB_FreeFace(face);
1011 return 0;
1012 }
1013
1014 return face;
1015 }
1016
1017 void HB_FreeFace(HB_Face face)
1018 {
1019 if (!face)
1020 return;
1021 if (face->gpos)
1022 HB_Done_GPOS_Table(face->gpos);
1023 if (face->gsub)
1024 HB_Done_GSUB_Table(face->gsub);
1025 if (face->gdef)
1026 HB_Done_GDEF_Table(face->gdef);
1027 if (face->buffer)
1028 hb_buffer_free(face->buffer);
1029 if (face->tmpAttributes)
1030 free(face->tmpAttributes);
1031 if (face->tmpLogClusters)
1032 free(face->tmpLogClusters);
1033 free(face);
1034 }
1035
1036 HB_Bool HB_SelectScript(HB_ShaperItem *shaper_item, const HB_OpenTypeFeature *fe atures)
1037 {
1038 HB_Script script = shaper_item->item.script;
1039
1040 if (!shaper_item->face->supported_scripts[script])
1041 return false;
1042
1043 HB_Face face = shaper_item->face;
1044 if (face->current_script == script && face->current_flags == shaper_item->sh aperFlags)
1045 return true;
1046
1047 face->current_script = script;
1048 face->current_flags = shaper_item->shaperFlags;
1049
1050 assert(script < HB_ScriptCount);
1051 // find script in our list of supported scripts.
1052 unsigned int tag = ot_scripts[script].tag;
1053
1054 if (face->gsub && features) {
1055 #ifdef OT_DEBUG
1056 {
1057 HB_FeatureList featurelist = face->gsub->FeatureList;
1058 int numfeatures = featurelist.FeatureCount;
1059 DEBUG("gsub table has %d features", numfeatures);
1060 for (int i = 0; i < numfeatures; i++) {
1061 HB_FeatureRecord *r = featurelist.FeatureRecord + i;
1062 DEBUG(" feature '%s'", tag_to_string(r->FeatureTag));
1063 }
1064 }
1065 #endif
1066 HB_GSUB_Clear_Features(face->gsub);
1067 HB_UShort script_index;
1068 HB_Error error = HB_GSUB_Select_Script(face->gsub, tag, &script_index);
1069 if (!error) {
1070 DEBUG("script %s has script index %d", tag_to_string(script), script _index);
1071 while (features->tag) {
1072 HB_UShort feature_index;
1073 error = HB_GSUB_Select_Feature(face->gsub, features->tag, script _index, 0xffff, &feature_index);
1074 if (!error) {
1075 DEBUG(" adding feature %s", tag_to_string(features->tag));
1076 HB_GSUB_Add_Feature(face->gsub, feature_index, features->pro perty);
1077 }
1078 ++features;
1079 }
1080 }
1081 }
1082
1083 // reset
1084 face->has_opentype_kerning = false;
1085
1086 if (face->gpos) {
1087 HB_GPOS_Clear_Features(face->gpos);
1088 HB_UShort script_index;
1089 HB_Error error = HB_GPOS_Select_Script(face->gpos, tag, &script_index);
1090 if (!error) {
1091 #ifdef OT_DEBUG
1092 {
1093 HB_FeatureList featurelist = face->gpos->FeatureList;
1094 int numfeatures = featurelist.FeatureCount;
1095 DEBUG("gpos table has %d features", numfeatures);
1096 for(int i = 0; i < numfeatures; i++) {
1097 HB_FeatureRecord *r = featurelist.FeatureRecord + i;
1098 HB_UShort feature_index;
1099 HB_GPOS_Select_Feature(face->gpos, r->FeatureTag, script_ind ex, 0xffff, &feature_index);
1100 DEBUG(" feature '%s'", tag_to_string(r->FeatureTag));
1101 }
1102 }
1103 #endif
1104 HB_UInt *feature_tag_list_buffer;
1105 error = HB_GPOS_Query_Features(face->gpos, script_index, 0xffff, &fe ature_tag_list_buffer);
1106 if (!error) {
1107 HB_UInt *feature_tag_list = feature_tag_list_buffer;
1108 while (*feature_tag_list) {
1109 HB_UShort feature_index;
1110 if (*feature_tag_list == HB_MAKE_TAG('k', 'e', 'r', 'n')) {
1111 if (face->current_flags & HB_ShaperFlag_NoKerning) {
1112 ++feature_tag_list;
1113 continue;
1114 }
1115 face->has_opentype_kerning = true;
1116 }
1117 error = HB_GPOS_Select_Feature(face->gpos, *feature_tag_list , script_index, 0xffff, &feature_index);
1118 if (!error)
1119 HB_GPOS_Add_Feature(face->gpos, feature_index, Positioni ngProperties);
1120 ++feature_tag_list;
1121 }
1122 FREE(feature_tag_list_buffer);
1123 }
1124 }
1125 }
1126
1127 return true;
1128 }
1129
1130 HB_Bool HB_OpenTypeShape(HB_ShaperItem *item, const hb_uint32 *properties)
1131 {
1132 HB_GlyphAttributes *tmpAttributes;
1133 unsigned int *tmpLogClusters;
1134
1135 HB_Face face = item->face;
1136
1137 face->length = item->num_glyphs;
1138
1139 hb_buffer_clear(face->buffer);
1140
1141 tmpAttributes = (HB_GlyphAttributes *) realloc(face->tmpAttributes, face->le ngth*sizeof(HB_GlyphAttributes));
1142 if (!tmpAttributes)
1143 return false;
1144 face->tmpAttributes = tmpAttributes;
1145
1146 tmpLogClusters = (unsigned int *) realloc(face->tmpLogClusters, face->length *sizeof(unsigned int));
1147 if (!tmpLogClusters)
1148 return false;
1149 face->tmpLogClusters = tmpLogClusters;
1150
1151 const int itemLength = item->item.length;
1152 assert(itemLength > 0);
1153 for (int i = 0; i < face->length; ++i) {
1154 hb_buffer_add_glyph(face->buffer, item->glyphs[i], properties ? properti es[i] : 0, i);
1155 face->tmpAttributes[i] = item->attributes[i];
1156 face->tmpLogClusters[i] = i < itemLength ? item->log_clusters[i] : item- >log_clusters[itemLength - 1];
1157 }
1158
1159 #ifdef OT_DEBUG
1160 DEBUG("-----------------------------------------");
1161 // DEBUG("log clusters before shaping:");
1162 // for (int j = 0; j < length; j++)
1163 // DEBUG(" log[%d] = %d", j, item->log_clusters[j]);
1164 DEBUG("original glyphs: %p", item->glyphs);
1165 for (int i = 0; i < length; ++i)
1166 DEBUG(" glyph=%4x", hb_buffer->in_string[i].gindex);
1167 // dump_string(hb_buffer);
1168 #endif
1169
1170 face->glyphs_substituted = false;
1171 if (face->gsub) {
1172 unsigned int error = HB_GSUB_Apply_String(face->gsub, face->buffer);
1173 if (error && error != HB_Err_Not_Covered)
1174 return false;
1175 face->glyphs_substituted = (error != HB_Err_Not_Covered);
1176 }
1177
1178 #ifdef OT_DEBUG
1179 // DEBUG("log clusters before shaping:");
1180 // for (int j = 0; j < length; j++)
1181 // DEBUG(" log[%d] = %d", j, item->log_clusters[j]);
1182 DEBUG("shaped glyphs:");
1183 for (int i = 0; i < length; ++i)
1184 DEBUG(" glyph=%4x", hb_buffer->in_string[i].gindex);
1185 DEBUG("-----------------------------------------");
1186 // dump_string(hb_buffer);
1187 #endif
1188
1189 return true;
1190 }
1191
1192 /* See comments near the definition of HB_ShaperFlag_ForceMarksToZeroWidth for a description
1193 of why this function exists. */
1194 void HB_FixupZeroWidth(HB_ShaperItem *item)
1195 {
1196 HB_UShort property;
1197
1198 if (!item->face->gdef)
1199 return;
1200
1201 for (unsigned int i = 0; i < item->num_glyphs; ++i) {
1202 /* If the glyph is a mark, force its advance to zero. */
1203 if (HB_GDEF_Get_Glyph_Property (item->face->gdef, item->glyphs[i], &prop erty) == HB_Err_Ok &&
1204 property == HB_GDEF_MARK) {
1205 item->advances[i] = 0;
1206 }
1207 }
1208 }
1209
1210 HB_Bool HB_OpenTypePosition(HB_ShaperItem *item, int availableGlyphs, HB_Bool do LogClusters)
1211 {
1212 HB_Face face = item->face;
1213
1214 bool glyphs_positioned = false;
1215 if (face->gpos) {
1216 if (face->buffer->positions)
1217 memset(face->buffer->positions, 0, face->buffer->in_length*sizeof(HB _PositionRec));
1218 // #### check that passing "false,false" is correct
1219 glyphs_positioned = HB_GPOS_Apply_String(item->font, face->gpos, face->c urrent_flags, face->buffer, false, false) != HB_Err_Not_Covered;
1220 }
1221
1222 if (!face->glyphs_substituted && !glyphs_positioned) {
1223 HB_GetGlyphAdvances(item);
1224 if (item->face->current_flags & HB_ShaperFlag_ForceMarksToZeroWidth)
1225 HB_FixupZeroWidth(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_a dvance >> 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 == 0)
1291 advances[i] += adjustment;
1292
1293 int back = 0;
1294 HB_FixedPoint *offsets = item->offsets;
1295 offsets[i].x = positions[i].x_pos;
1296 offsets[i].y = positions[i].y_pos;
1297 while (positions[i - back].back) {
1298 back += positions[i - back].back;
1299 offsets[i].x += positions[i - back].x_pos;
1300 offsets[i].y += positions[i - back].y_pos;
1301 }
1302 offsets[i].y = -offsets[i].y;
1303
1304 if (item->item.bidiLevel % 2) {
1305 // ### may need to go back multiple glyphs like in ltr
1306 back = positions[i].back;
1307 while (back--)
1308 offsets[i].x -= advances[i-back];
1309 } else {
1310 back = 0;
1311 while (positions[i - back].back) {
1312 back += positions[i - back].back;
1313 offsets[i].x -= advances[i-back];
1314 }
1315 }
1316 // DEBUG(" ->\tadv=%d\tpos=(%d/%d)",
1317 // glyphs[i].advance.x.toInt(), glyphs[i].offset.x.toInt(), g lyphs[i].offset.y.toInt());
1318 }
1319 item->kerning_applied = face->has_opentype_kerning;
1320 } else {
1321 HB_HeuristicPosition(item);
1322 }
1323
1324 #ifdef OT_DEBUG
1325 if (doLogClusters) {
1326 DEBUG("log clusters after shaping:");
1327 for (int j = 0; j < length; j++)
1328 DEBUG(" log[%d] = %d", j, item->log_clusters[j]);
1329 }
1330 DEBUG("final glyphs:");
1331 for (int i = 0; i < (int)hb_buffer->in_length; ++i)
1332 DEBUG(" glyph=%4x char_index=%d mark: %d cmp: %d, clusterStart: %d adv ance=%d/%d offset=%d/%d",
1333 glyphs[i].glyph, hb_buffer->in_string[i].cluster, glyphs[i].attri butes.mark,
1334 glyphs[i].attributes.combiningClass, glyphs[i].attributes.cluster Start,
1335 glyphs[i].advance.x.toInt(), glyphs[i].advance.y.toInt(),
1336 glyphs[i].offset.x.toInt(), glyphs[i].offset.y.toInt());
1337 DEBUG("-----------------------------------------");
1338 #endif
1339 return true;
1340 }
1341
1342 HB_Bool HB_ShapeItem(HB_ShaperItem *shaper_item)
1343 {
1344 HB_Bool result = false;
1345 if (shaper_item->num_glyphs < shaper_item->item.length) {
1346 shaper_item->num_glyphs = shaper_item->item.length;
1347 return false;
1348 }
1349 assert(shaper_item->item.script < HB_ScriptCount);
1350 result = HB_ScriptEngines[shaper_item->item.script].shape(shaper_item);
1351 shaper_item->glyphIndicesPresent = false;
1352 return result;
1353 }
OLDNEW
« no previous file with comments | « third_party/harfbuzz/src/harfbuzz-shaper.h ('k') | third_party/harfbuzz/src/harfbuzz-shaper-all.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698