1 /*
2 * Copyright (C) 2000, 2007 Red Hat, Inc.
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 * Red Hat Author(s): Owen Taylor, Behdad Esfahbod
25 */
26
27 #include "harfbuzz-impl.h"
28 #include "harfbuzz-dump.h"
29 #include "harfbuzz-gdef-private.h"
30 #include "harfbuzz-gsub-private.h"
31 #include "harfbuzz-gpos-private.h"
32 #include "harfbuzz-open-private.h"
33 #include <stdarg.h>
34
35 #define DUMP(format) dump (stream, indent, format)
36 #define DUMP1(format, arg1) dump (stream, indent, format, arg1)
37 #define DUMP2(format, arg1, arg2) dump (stream, indent, format, arg1, arg2)
38 #define DUMP3(format, arg1, arg2, arg3) dump (stream, indent, format, arg1, arg2, arg3)
39
40 #define DUMP_FINT(strct,fld) dump (stream, indent, "<" #fld ">%d</" #fld ">\n", (strct)->fld)
41 #define DUMP_FUINT(strct,fld) dump (stream, indent, "<" #fld ">%u</" #fld ">\n", (strct)->fld)
42 #define DUMP_FGLYPH(strct,fld) dump (stream, indent, "<" #fld ">%#06x</" #fld ">\n", (strct)->fld)
43 #define DUMP_FGLYPH(strct,fld) dump (stream, indent, "<" #fld ">%#06x</" #fld ">\n", (strct)->fld)
44 #define DUMP_USHORT_ARRAY(strct,fld,cnt) Dump_UShort_Array ((strct)->fld, cnt, #fld, stream, indent);
45
46 #define DEF_DUMP(type) static void Dump_ ## type (HB_ ## type *type, FILE *stream, int indent, HB_Type hb_type)
47 #define RECURSE(name, type, val) do { DUMP ("<" #name ">\n"); Dump_ ## type (val, stream, indent + 1, hb_type); DUMP ("</" #name ">\n"); } while (0)
48 #define RECURSE_NUM(name, i, type, val) do { DUMP1 ("<" #name "> <!-- %d -->\n", i); Dump_ ## type (val, stream, indent + 1, hb_type); DUMP ("</" #name ">\n"); } while (0)
49 #define DUMP_VALUE_RECORD(val, frmt) do { DUMP ("<ValueRecord>\n"); Dump_ValueRecord (val, stream, indent + 1, hb_type, frmt); DUMP ("</ValueRecord>\n"); } while (0)
50
51 static void
do_indent(FILE * stream,int indent)52 do_indent (FILE *stream, int indent)
53 {
54 fprintf (stream, "%*s", indent * 3, "");
55 }
56
57 static void
dump(FILE * stream,int indent,const char * format,...)58 dump (FILE *stream, int indent, const char *format, ...)
59 {
60 va_list list;
61
62 do_indent (stream, indent);
63
64 va_start (list, format);
65 vfprintf (stream, format, list);
66 va_end (list);
67 }
68
69 static void
Dump_UShort_Array(HB_UShort * array,int count,const char * name,FILE * stream,int indent)70 Dump_UShort_Array (HB_UShort *array, int count, const char *name, FILE *stream, int indent)
71 {
72 int i;
73
74 do_indent (stream, indent);
75
76 fprintf (stream, "<%s>", name);
77 for (i = 0; i < count; i++)
78 fprintf (stream, "%d%s", array[i], i == 0 ? "" : " ");
79 fprintf (stream, "</%s>\n", name);
80 }
81
82 static void
Print_Tag(HB_UInt tag,FILE * stream)83 Print_Tag (HB_UInt tag, FILE *stream)
84 {
85 fprintf (stream, "%c%c%c%c",
86 (unsigned char)(tag >> 24),
87 (unsigned char)((tag >> 16) & 0xff),
88 (unsigned char)((tag >> 8) & 0xff),
89 (unsigned char)(tag & 0xff));
90 }
91
DEF_DUMP(LangSys)92 DEF_DUMP (LangSys)
93 {
94 int i;
95
96 HB_UNUSED(hb_type);
97
98 DUMP_FUINT (LangSys, LookupOrderOffset);
99 DUMP_FUINT (LangSys, ReqFeatureIndex);
100 DUMP_FUINT (LangSys, FeatureCount);
101
102 for (i=0; i < LangSys->FeatureCount; i++)
103 DUMP1("<FeatureIndex>%d</FeatureIndex>\n", LangSys->FeatureIndex[i]);
104 }
105
DEF_DUMP(ScriptTable)106 DEF_DUMP (ScriptTable)
107 {
108 int i;
109
110 RECURSE (DefaultLangSys, LangSys, &ScriptTable->DefaultLangSys);
111
112 DUMP_FUINT (ScriptTable, LangSysCount);
113
114 for (i=0; i < ScriptTable->LangSysCount; i++)
115 {
116 do_indent (stream, indent);
117 fprintf (stream, "<LangSysTag>");
118 Print_Tag (ScriptTable->LangSysRecord[i].LangSysTag, stream);
119 fprintf (stream, "</LangSysTag>\n");
120 RECURSE_NUM (LangSys, i, LangSys, &ScriptTable->LangSysRecord[i].LangSys);
121 }
122 }
123
DEF_DUMP(ScriptList)124 DEF_DUMP (ScriptList)
125 {
126 int i;
127
128 DUMP_FUINT (ScriptList, ScriptCount);
129
130 for (i=0; i < ScriptList->ScriptCount; i++)
131 {
132 do_indent (stream, indent);
133 fprintf (stream, "<ScriptTag>");
134 Print_Tag (ScriptList->ScriptRecord[i].ScriptTag, stream);
135 fprintf (stream, "</ScriptTag>\n");
136 RECURSE_NUM (Script, i, ScriptTable, &ScriptList->ScriptRecord[i].Script);
137 }
138 }
139
DEF_DUMP(Feature)140 DEF_DUMP (Feature)
141 {
142 int i;
143
144 HB_UNUSED(hb_type);
145
146 DUMP_FUINT (Feature, FeatureParams);
147 DUMP_FUINT (Feature, LookupListCount);
148
149 for (i=0; i < Feature->LookupListCount; i++)
150 DUMP1("<LookupIndex>%d</LookupIndex>\n", Feature->LookupListIndex[i]);
151 }
152
DEF_DUMP(MarkRecord)153 DEF_DUMP (MarkRecord)
154 {
155 HB_UNUSED(hb_type);
156
157 DUMP_FUINT (MarkRecord, Class);
158 DUMP1("<Anchor>%d</Anchor>\n", MarkRecord->MarkAnchor.PosFormat );
159 }
160
DEF_DUMP(MarkArray)161 DEF_DUMP (MarkArray)
162 {
163 int i;
164
165 DUMP_FUINT (MarkArray, MarkCount);
166
167 for (i=0; i < MarkArray->MarkCount; i++)
168 RECURSE_NUM (MarkRecord, i, MarkRecord, &MarkArray->MarkRecord[i]);
169 }
170
DEF_DUMP(FeatureList)171 DEF_DUMP (FeatureList)
172 {
173 int i;
174
175 DUMP_FUINT (FeatureList, FeatureCount);
176
177 for (i=0; i < FeatureList->FeatureCount; i++)
178 {
179 do_indent (stream, indent);
180 fprintf (stream, "<FeatureTag>");
181 Print_Tag (FeatureList->FeatureRecord[i].FeatureTag, stream);
182 fprintf (stream, "</FeatureTag> <!-- %d -->\n", i);
183 RECURSE_NUM (Feature, i, Feature, &FeatureList->FeatureRecord[i].Feature);
184 }
185 }
186
DEF_DUMP(Coverage)187 DEF_DUMP (Coverage)
188 {
189 HB_UNUSED(hb_type);
190
191 DUMP_FUINT (Coverage, CoverageFormat);
192
193 if (Coverage->CoverageFormat == 1)
194 {
195 int i;
196 DUMP_FUINT (&Coverage->cf.cf1, GlyphCount);
197
198 for (i = 0; i < Coverage->cf.cf1.GlyphCount; i++)
199 DUMP2("<Glyph>%#06x</Glyph> <!-- %d -->\n",
200 Coverage->cf.cf1.GlyphArray[i], i);
201 }
202 else
203 {
204 int i;
205 DUMP_FUINT (&Coverage->cf.cf2, RangeCount);
206
207 for ( i = 0; i < Coverage->cf.cf2.RangeCount; i++ )
208 DUMP3("<Glyph>%#06x - %#06x</Glyph> <!-- %d -->\n",
209 Coverage->cf.cf2.RangeRecord[i].Start,
210 Coverage->cf.cf2.RangeRecord[i].End, i);
211 }
212 }
213
DEF_DUMP(ClassRangeRecord)214 DEF_DUMP (ClassRangeRecord)
215 {
216 HB_UNUSED(hb_type);
217
218 DUMP_FGLYPH (ClassRangeRecord, Start);
219 DUMP_FGLYPH (ClassRangeRecord, End);
220 DUMP_FUINT (ClassRangeRecord, Class);
221 }
222
DEF_DUMP(ClassDefinition)223 DEF_DUMP (ClassDefinition)
224 {
225 HB_UNUSED(hb_type);
226
227 DUMP_FUINT( ClassDefinition, ClassFormat);
228 DUMP_FUINT( ClassDefinition, loaded);
229
230 if (ClassDefinition->ClassFormat == 1)
231 {
232 int i;
233 HB_ClassDefFormat1 *ClassDefFormat1 = &ClassDefinition->cd.cd1;
234 DUMP("<ClassDefinition>\n");
235 DUMP_FUINT (ClassDefFormat1, StartGlyph );
236 DUMP_FUINT (ClassDefFormat1, GlyphCount );
237 for (i = 0; i < ClassDefFormat1->GlyphCount; i++)
238 DUMP2(" <Class>%d</Class> <!-- %#06x -->", ClassDefFormat1->ClassValueArray[i],
239 ClassDefFormat1->StartGlyph+i );
240 }
241 else if (ClassDefinition->ClassFormat == 2)
242 {
243 int i;
244 HB_ClassDefFormat2 *ClassDefFormat2 = &ClassDefinition->cd.cd2;
245 DUMP_FUINT (ClassDefFormat2, ClassRangeCount);
246
247 for (i = 0; i < ClassDefFormat2->ClassRangeCount; i++)
248 RECURSE_NUM (ClassRangeRecord, i, ClassRangeRecord, &ClassDefFormat2->ClassRangeRecord[i]);
249 }
250 else
251 fprintf(stderr, "invalid class def table!!!\n");
252 }
253
DEF_DUMP(SubstLookupRecord)254 DEF_DUMP (SubstLookupRecord)
255 {
256 HB_UNUSED(hb_type);
257
258 DUMP_FUINT (SubstLookupRecord, SequenceIndex);
259 DUMP_FUINT (SubstLookupRecord, LookupListIndex);
260 }
261
DEF_DUMP(ChainSubClassRule)262 DEF_DUMP (ChainSubClassRule)
263 {
264 int i;
265
266 DUMP_USHORT_ARRAY (ChainSubClassRule, Backtrack, ChainSubClassRule->BacktrackGlyphCount);
267 DUMP_USHORT_ARRAY (ChainSubClassRule, Input, ChainSubClassRule->InputGlyphCount - 1);
268 DUMP_USHORT_ARRAY (ChainSubClassRule, Lookahead, ChainSubClassRule->LookaheadGlyphCount);
269
270 for (i = 0; i < ChainSubClassRule->SubstCount; i++)
271 RECURSE_NUM (SubstLookupRecord, i, SubstLookupRecord, &ChainSubClassRule->SubstLookupRecord[i]);
272
273 indent--;
274 }
275
DEF_DUMP(ChainSubClassSet)276 DEF_DUMP (ChainSubClassSet)
277 {
278 int i;
279
280 DUMP_FUINT( ChainSubClassSet, ChainSubClassRuleCount );
281 for (i = 0; i < ChainSubClassSet->ChainSubClassRuleCount; i++)
282 RECURSE_NUM (ChainSubClassRule, i, ChainSubClassRule, &ChainSubClassSet->ChainSubClassRule[i]);
283 }
284
285 static void
Dump_GSUB_Lookup_Single(HB_SubTable * subtable,FILE * stream,int indent,HB_Type hb_type)286 Dump_GSUB_Lookup_Single (HB_SubTable *subtable, FILE *stream, int indent, HB_Type hb_type)
287 {
288 HB_SingleSubst *SingleSubst = &subtable->st.gsub.single;
289
290 DUMP_FUINT (SingleSubst, SubstFormat);
291 RECURSE (Coverage, Coverage, &SingleSubst->Coverage);
292
293 if (SingleSubst->SubstFormat == 1)
294 {
295 DUMP_FINT (&SingleSubst->ssf.ssf1, DeltaGlyphID);
296 }
297 else
298 {
299 int i;
300
301 DUMP_FINT (&SingleSubst->ssf.ssf2, GlyphCount);
302 for (i=0; i < SingleSubst->ssf.ssf2.GlyphCount; i++)
303 DUMP2("<Substitute>%#06x</Substitute> <!-- %d -->\n", SingleSubst->ssf.ssf2.Substitute[i], i);
304 }
305 }
306
DEF_DUMP(Ligature)307 DEF_DUMP (Ligature)
308 {
309 int i;
310
311 HB_UNUSED(hb_type);
312
313 DUMP_FGLYPH (Ligature, LigGlyph);
314 DUMP_FUINT (Ligature, ComponentCount);
315
316 for (i=0; i < Ligature->ComponentCount - 1; i++)
317 DUMP1("<Component>%#06x</Component>\n", Ligature->Component[i]);
318 }
319
DEF_DUMP(LigatureSet)320 DEF_DUMP (LigatureSet)
321 {
322 int i;
323
324 DUMP_FUINT (LigatureSet, LigatureCount);
325
326 for (i=0; i < LigatureSet->LigatureCount; i++)
327 RECURSE_NUM (Ligature, i, Ligature, &LigatureSet->Ligature[i]);
328 }
329
330 static void
Dump_GSUB_Lookup_Ligature(HB_SubTable * subtable,FILE * stream,int indent,HB_Type hb_type)331 Dump_GSUB_Lookup_Ligature (HB_SubTable *subtable, FILE *stream, int indent, HB_Type hb_type)
332 {
333 int i;
334 HB_LigatureSubst *LigatureSubst = &subtable->st.gsub.ligature;
335
336 DUMP_FUINT (LigatureSubst, SubstFormat);
337 RECURSE (Coverage, Coverage, &LigatureSubst->Coverage);
338
339 DUMP_FUINT (LigatureSubst, LigatureSetCount);
340
341 for (i=0; i < LigatureSubst->LigatureSetCount; i++)
342 RECURSE_NUM (LigatureSet, i, LigatureSet, &LigatureSubst->LigatureSet[i]);
343 }
344
DEF_DUMP(ContextSubstFormat1)345 DEF_DUMP (ContextSubstFormat1)
346 {
347 HB_UNUSED(hb_type);
348 HB_UNUSED(ContextSubstFormat1);
349
350
351 DUMP("<!-- Not implemented!!! -->\n");
352 }
353
DEF_DUMP(ContextSubstFormat2)354 DEF_DUMP (ContextSubstFormat2)
355 {
356 DUMP_FUINT (ContextSubstFormat2, MaxContextLength);
357 RECURSE (Coverage, Coverage, &ContextSubstFormat2->Coverage);
358 RECURSE (ClassDefinition, ClassDefinition, &ContextSubstFormat2->ClassDef);
359 }
360
DEF_DUMP(ContextSubstFormat3)361 DEF_DUMP (ContextSubstFormat3)
362 {
363 HB_UNUSED(hb_type);
364 HB_UNUSED(ContextSubstFormat3);
365
366 DUMP("<!-- Not implemented!!! -->\n");
367 }
368
369 static void
Dump_GSUB_Lookup_Context(HB_SubTable * subtable,FILE * stream,int indent,HB_Type hb_type)370 Dump_GSUB_Lookup_Context (HB_SubTable *subtable, FILE *stream, int indent, HB_Type hb_type)
371 {
372 HB_ContextSubst *ContextSubst = &subtable->st.gsub.context;
373
374 DUMP_FUINT (ContextSubst, SubstFormat);
375 switch( ContextSubst->SubstFormat )
376 {
377 case 1:
378 Dump_ContextSubstFormat1 (&ContextSubst->csf.csf1, stream, indent+2, hb_type);
379 break;
380 case 2:
381 Dump_ContextSubstFormat2 (&ContextSubst->csf.csf2, stream, indent+2, hb_type);
382 break;
383 case 3:
384 Dump_ContextSubstFormat3 (&ContextSubst->csf.csf3, stream, indent+2, hb_type);
385 break;
386 default:
387 fprintf(stderr, "invalid subformat!!!!!\n");
388 }
389 }
390
DEF_DUMP(ChainContextSubstFormat1)391 DEF_DUMP (ChainContextSubstFormat1)
392 {
393 HB_UNUSED(hb_type);
394 HB_UNUSED(ChainContextSubstFormat1);
395
396 DUMP("<!-- Not implemented!!! -->\n");
397 }
398
DEF_DUMP(ChainContextSubstFormat2)399 DEF_DUMP (ChainContextSubstFormat2)
400 {
401 int i;
402
403 RECURSE (Coverage, Coverage, &ChainContextSubstFormat2->Coverage);
404 DUMP_FUINT (ChainContextSubstFormat2, MaxBacktrackLength);
405 RECURSE (ClassDefinition, ClassDefinition, &ChainContextSubstFormat2->BacktrackClassDef);
406 DUMP_FUINT (ChainContextSubstFormat2, MaxInputLength);
407 RECURSE (ClassDefinition, ClassDefinition, &ChainContextSubstFormat2->InputClassDef);
408 DUMP_FUINT (ChainContextSubstFormat2, MaxLookaheadLength);
409 RECURSE (ClassDefinition, ClassDefinition, &ChainContextSubstFormat2->LookaheadClassDef);
410
411 DUMP_FUINT (ChainContextSubstFormat2, ChainSubClassSetCount);
412 for (i = 0; i < ChainContextSubstFormat2->ChainSubClassSetCount; i++)
413 RECURSE (ChainSubClassSet, ChainSubClassSet, &ChainContextSubstFormat2->ChainSubClassSet[i]);
414 }
415
DEF_DUMP(ChainContextSubstFormat3)416 DEF_DUMP (ChainContextSubstFormat3)
417 {
418 int i;
419
420 DUMP_FUINT (ChainContextSubstFormat3, BacktrackGlyphCount);
421 for (i = 0; i < ChainContextSubstFormat3->BacktrackGlyphCount; i++)
422 RECURSE (BacktrackCoverage, Coverage, &ChainContextSubstFormat3->BacktrackCoverage[i]);
423 DUMP_FUINT (ChainContextSubstFormat3, InputGlyphCount);
424 for (i = 0; i < ChainContextSubstFormat3->InputGlyphCount; i++)
425 RECURSE (InputCoverage, Coverage, &ChainContextSubstFormat3->InputCoverage[i]);
426 DUMP_FUINT (ChainContextSubstFormat3, LookaheadGlyphCount);
427 for (i = 0; i < ChainContextSubstFormat3->LookaheadGlyphCount; i++)
428 RECURSE (LookaheadCoverage, Coverage, &ChainContextSubstFormat3->LookaheadCoverage[i]);
429
430 for (i = 0; i < ChainContextSubstFormat3->SubstCount; i++)
431 RECURSE_NUM (SubstLookupRecord, i, SubstLookupRecord, &ChainContextSubstFormat3->SubstLookupRecord[i]);
432
433 }
434
435 static void
Dump_GSUB_Lookup_Chain(HB_SubTable * subtable,FILE * stream,int indent,HB_Type hb_type)436 Dump_GSUB_Lookup_Chain (HB_SubTable *subtable, FILE *stream, int indent, HB_Type hb_type)
437 {
438 HB_ChainContextSubst *chain = &subtable->st.gsub.chain;
439
440 DUMP_FUINT (chain, SubstFormat);
441 switch (chain->SubstFormat)
442 {
443 case 1:
444 Dump_ChainContextSubstFormat1 (&chain->ccsf.ccsf1, stream, indent+2, hb_type);
445 break;
446 case 2:
447 Dump_ChainContextSubstFormat2 (&chain->ccsf.ccsf2, stream, indent+2, hb_type);
448 break;
449 case 3:
450 Dump_ChainContextSubstFormat3 (&chain->ccsf.ccsf3, stream, indent+2, hb_type);
451 break;
452 default:
453 fprintf(stderr, "invalid subformat!!!!!\n");
454 }
455 }
456
457 static void
Dump_Device(HB_Device * Device,FILE * stream,int indent,HB_Type hb_type)458 Dump_Device (HB_Device *Device, FILE *stream, int indent, HB_Type hb_type)
459 {
460 int i;
461 int bits;
462 int n_per;
463 unsigned int mask;
464
465 HB_UNUSED(hb_type);
466
467 DUMP_FUINT (Device, StartSize);
468 DUMP_FUINT (Device, EndSize);
469 DUMP_FUINT (Device, DeltaFormat);
470 switch (Device->DeltaFormat)
471 {
472 case 1:
473 bits = 2;
474 break;
475 case 2:
476 bits = 4;
477 break;
478 case 3:
479 bits = 8;
480 break;
481 default:
482 bits = 0;
483 break;
484 }
485
486 DUMP ("<DeltaValue>");
487 if (!bits)
488 {
489
490 fprintf(stderr, "invalid DeltaFormat!!!!!\n");
491 }
492 else
493 {
494 n_per = 16 / bits;
495 mask = (1 << bits) - 1;
496 mask = mask << (16 - bits);
497
498 for (i = Device->StartSize; i <= Device->EndSize ; i++)
499 {
500 HB_UShort val = Device->DeltaValue[i / n_per];
501 HB_Short signed_val = ((val << ((i % n_per) * bits)) & mask);
502 dump (stream, indent, "%d", signed_val >> (16 - bits));
503 if (i != Device->EndSize)
504 DUMP (", ");
505 }
506 }
507 DUMP ("</DeltaValue>\n");
508 }
509
510 static void
Dump_ValueRecord(HB_ValueRecord * ValueRecord,FILE * stream,int indent,HB_Type hb_type,HB_UShort value_format)511 Dump_ValueRecord (HB_ValueRecord *ValueRecord, FILE *stream, int indent, HB_Type hb_type, HB_UShort value_format)
512 {
513 if (value_format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT)
514 DUMP_FINT (ValueRecord, XPlacement);
515 if (value_format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT)
516 DUMP_FINT (ValueRecord, YPlacement);
517 if (value_format & HB_GPOS_FORMAT_HAVE_X_ADVANCE)
518 DUMP_FINT (ValueRecord, XAdvance);
519 if (value_format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE)
520 DUMP_FINT (ValueRecord, XAdvance);
521 if (value_format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT_DEVICE)
522 RECURSE (Device, Device, &*ValueRecord->DeviceTables[VR_X_PLACEMENT_DEVICE]);
523 if (value_format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT_DEVICE)
524 RECURSE (Device, Device, &*ValueRecord->DeviceTables[VR_Y_PLACEMENT_DEVICE]);
525 if (value_format & HB_GPOS_FORMAT_HAVE_X_ADVANCE_DEVICE)
526 RECURSE (Device, Device, &*ValueRecord->DeviceTables[VR_X_ADVANCE_DEVICE]);
527 if (value_format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE_DEVICE)
528 RECURSE (Device, Device, &*ValueRecord->DeviceTables[VR_Y_ADVANCE_DEVICE]);
529 #ifdef HB_SUPPORT_MULTIPLE_MASTER
530 if (value_format & HB_GPOS_FORMAT_HAVE_X_ID_PLACEMENT)
531 DUMP_FUINT (ValueRecord, XIdPlacement);
532 if (value_format & HB_GPOS_FORMAT_HAVE_Y_ID_PLACEMENT)
533 DUMP_FUINT (ValueRecord, YIdPlacement);
534 if (value_format & HB_GPOS_FORMAT_HAVE_X_ID_ADVANCE)
535 DUMP_FUINT (ValueRecord, XIdAdvance);
536 if (value_format & HB_GPOS_FORMAT_HAVE_Y_ID_ADVANCE)
537 DUMP_FUINT (ValueRecord, XIdAdvance);
538 #endif
539 }
540
541 static void
Dump_GPOS_Lookup_Single(HB_SubTable * subtable,FILE * stream,int indent,HB_Type hb_type)542 Dump_GPOS_Lookup_Single (HB_SubTable *subtable, FILE *stream, int indent, HB_Type hb_type)
543 {
544 HB_SinglePos *SinglePos = &subtable->st.gpos.single;
545
546 DUMP_FUINT (SinglePos, PosFormat);
547 RECURSE (Coverage, Coverage, &SinglePos->Coverage);
548
549 DUMP_FUINT (SinglePos, ValueFormat);
550
551 if (SinglePos->PosFormat == 1)
552 {
553 DUMP_VALUE_RECORD (&SinglePos->spf.spf1.Value, SinglePos->ValueFormat);
554 }
555 else
556 {
557 int i;
558
559 DUMP_FUINT (&SinglePos->spf.spf2, ValueCount);
560 for (i = 0; i < SinglePos->spf.spf2.ValueCount; i++)
561 DUMP_VALUE_RECORD (&SinglePos->spf.spf2.Value[i], SinglePos->ValueFormat);
562 }
563 }
564
565 static void
Dump_PairValueRecord(HB_PairValueRecord * PairValueRecord,FILE * stream,int indent,HB_Type hb_type,HB_UShort ValueFormat1,HB_UShort ValueFormat2)566 Dump_PairValueRecord (HB_PairValueRecord *PairValueRecord, FILE *stream, int indent, HB_Type hb_type, HB_UShort ValueFormat1, HB_UShort ValueFormat2)
567 {
568 DUMP_FUINT (PairValueRecord, SecondGlyph);
569 DUMP_VALUE_RECORD (&PairValueRecord->Value1, ValueFormat1);
570 DUMP_VALUE_RECORD (&PairValueRecord->Value2, ValueFormat2);
571 }
572
573 static void
Dump_PairSet(HB_PairSet * PairSet,FILE * stream,int indent,HB_Type hb_type,HB_UShort ValueFormat1,HB_UShort ValueFormat2)574 Dump_PairSet (HB_PairSet *PairSet, FILE *stream, int indent, HB_Type hb_type, HB_UShort ValueFormat1, HB_UShort ValueFormat2)
575 {
576 int i;
577 DUMP_FUINT (PairSet, PairValueCount);
578
579 for (i = 0; i < PairSet->PairValueCount; i++)
580 {
581 DUMP ("<PairValueRecord>\n");
582 Dump_PairValueRecord (&PairSet->PairValueRecord[i], stream, indent + 1, hb_type, ValueFormat1, ValueFormat2);
583 DUMP ("</PairValueRecord>\n");
584 }
585 }
586
587 static void
Dump_GPOS_Lookup_Pair(HB_SubTable * subtable,FILE * stream,int indent,HB_Type hb_type)588 Dump_GPOS_Lookup_Pair (HB_SubTable *subtable, FILE *stream, int indent, HB_Type hb_type)
589 {
590 HB_PairPos *PairPos = &subtable->st.gpos.pair;
591
592 DUMP_FUINT (PairPos, PosFormat);
593 RECURSE (Coverage, Coverage, &PairPos->Coverage);
594
595 DUMP_FUINT (PairPos, ValueFormat1);
596 DUMP_FUINT (PairPos, ValueFormat2);
597
598 if (PairPos->PosFormat == 1)
599 {
600 int i;
601
602 DUMP_FUINT (&PairPos->ppf.ppf1, PairSetCount);
603 for (i = 0; i < PairPos->ppf.ppf1.PairSetCount; i++)
604 {
605 DUMP ("<PairSet>\n");
606 Dump_PairSet (&PairPos->ppf.ppf1.PairSet[i], stream, indent + 1, hb_type, PairPos->ValueFormat1, PairPos->ValueFormat2);
607 DUMP ("</PairSet>\n");
608 }
609 }
610 else
611 {
612 }
613 }
614
615 static void
Dump_GPOS_Lookup_Markbase(HB_SubTable * subtable,FILE * stream,int indent,HB_Type hb_type)616 Dump_GPOS_Lookup_Markbase (HB_SubTable *subtable, FILE *stream, int indent, HB_Type hb_type)
617 {
618 int i;
619 HB_MarkBasePos *markbase = &subtable->st.gpos.markbase;
620
621 DUMP_FUINT (markbase, PosFormat);
622 RECURSE (Coverage, Coverage, &markbase->MarkCoverage);
623 RECURSE (Coverage, Coverage, &markbase->BaseCoverage);
624 DUMP_FUINT (markbase, ClassCount);
625 RECURSE (MarkArray, MarkArray, &markbase->MarkArray);
626
627 DUMP ("<BaseArray>\n");
628 indent++;
629
630 DUMP_FUINT (&markbase->BaseArray, BaseCount);
631 for (i = 0; i < markbase->BaseArray.BaseCount; i++)
632 {
633 int j;
634 HB_BaseRecord *r = &markbase->BaseArray.BaseRecord[i];
635 DUMP1 ("<BaseRecord> <!-- %d -->\n", i);
636 for (j = 0; j < markbase->ClassCount; j++)
637 DUMP1 (" <Anchor>%d</Anchor>\n", r->BaseAnchor->PosFormat);
638 DUMP ("<BaseRecord>\n");
639 }
640
641 indent--;
642 DUMP ("</BaseArray>\n");
643 }
644
DEF_DUMP(Lookup)645 DEF_DUMP (Lookup)
646 {
647 int i;
648 const char *lookup_name;
649 void (*lookup_func) (HB_SubTable *subtable, FILE *stream, int indent, HB_Type hb_type) = NULL;
650
651 if (hb_type == HB_Type_GSUB)
652 {
653 switch (Lookup->LookupType)
654 {
655 case HB_GSUB_LOOKUP_SINGLE:
656 lookup_name = "SINGLE";
657 lookup_func = Dump_GSUB_Lookup_Single;
658 break;
659 case HB_GSUB_LOOKUP_MULTIPLE:
660 lookup_name = "MULTIPLE";
661 break;
662 case HB_GSUB_LOOKUP_ALTERNATE:
663 lookup_name = "ALTERNATE";
664 break;
665 case HB_GSUB_LOOKUP_LIGATURE:
666 lookup_name = "LIGATURE";
667 lookup_func = Dump_GSUB_Lookup_Ligature;
668 break;
669 case HB_GSUB_LOOKUP_CONTEXT:
670 lookup_name = "CONTEXT";
671 lookup_func = Dump_GSUB_Lookup_Context;
672 break;
673 case HB_GSUB_LOOKUP_CHAIN:
674 lookup_name = "CHAIN";
675 lookup_func = Dump_GSUB_Lookup_Chain;
676 break;
677 default:
678 lookup_name = "(unknown)";
679 lookup_func = NULL;
680 break;
681 }
682 }
683 else
684 {
685 switch (Lookup->LookupType)
686 {
687 case HB_GPOS_LOOKUP_SINGLE:
688 lookup_name = "SINGLE";
689 lookup_func = Dump_GPOS_Lookup_Single;
690 break;
691 case HB_GPOS_LOOKUP_PAIR:
692 lookup_name = "PAIR";
693 lookup_func = Dump_GPOS_Lookup_Pair;
694 break;
695 case HB_GPOS_LOOKUP_CURSIVE:
696 lookup_name = "CURSIVE";
697 break;
698 case HB_GPOS_LOOKUP_MARKBASE:
699 lookup_name = "MARKBASE";
700 lookup_func = Dump_GPOS_Lookup_Markbase;
701 break;
702 case HB_GPOS_LOOKUP_MARKLIG:
703 lookup_name = "MARKLIG";
704 break;
705 case HB_GPOS_LOOKUP_MARKMARK:
706 lookup_name = "MARKMARK";
707 break;
708 case HB_GPOS_LOOKUP_CONTEXT:
709 lookup_name = "CONTEXT";
710 break;
711 case HB_GPOS_LOOKUP_CHAIN:
712 lookup_name = "CHAIN";
713 break;
714 default:
715 lookup_name = "(unknown)";
716 lookup_func = NULL;
717 break;
718 }
719 }
720
721 DUMP2("<LookupType>%s</LookupType> <!-- %d -->\n", lookup_name, Lookup->LookupType);
722 DUMP1("<LookupFlag>%#06x</LookupFlag>\n", Lookup->LookupFlag);
723
724 for (i=0; i < Lookup->SubTableCount; i++)
725 {
726 DUMP ("<Subtable>\n");
727 if (lookup_func)
728 (*lookup_func) (&Lookup->SubTable[i], stream, indent + 1, hb_type);
729 DUMP ("</Subtable>\n");
730 }
731 }
732
DEF_DUMP(LookupList)733 DEF_DUMP (LookupList)
734 {
735 int i;
736
737 DUMP_FUINT (LookupList, LookupCount);
738
739 for (i=0; i < LookupList->LookupCount; i++)
740 RECURSE_NUM (Lookup, i, Lookup, &LookupList->Lookup[i]);
741 }
742
743 void
HB_Dump_GSUB_Table(HB_GSUB gsub,FILE * stream)744 HB_Dump_GSUB_Table (HB_GSUB gsub, FILE *stream)
745 {
746 int indent = 1;
747 HB_Type hb_type = HB_Type_GSUB;
748
749 do_indent (stream, indent);
750 fprintf(stream, "<!-- GSUB -->\n");
751 RECURSE (ScriptList, ScriptList, &gsub->ScriptList);
752 RECURSE (FeatureList, FeatureList, &gsub->FeatureList);
753 RECURSE (LookupList, LookupList, &gsub->LookupList);
754 }
755
756 void
HB_Dump_GPOS_Table(HB_GPOS gpos,FILE * stream)757 HB_Dump_GPOS_Table (HB_GPOS gpos, FILE *stream)
758 {
759 int indent = 1;
760 HB_Type hb_type = HB_Type_GPOS;
761
762 do_indent (stream, indent);
763 fprintf(stream, "<!-- GPOS -->\n");
764 RECURSE (ScriptList, ScriptList, &gpos->ScriptList);
765 RECURSE (FeatureList, FeatureList, &gpos->FeatureList);
766 RECURSE (LookupList, LookupList, &gpos->LookupList);
767 }
768