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 52 do_indent (FILE *stream, int indent) 53 { 54 fprintf (stream, "%*s", indent * 3, ""); 55 } 56 57 static void 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 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 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 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 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 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 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 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 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 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 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 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 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 254 DEF_DUMP (SubstLookupRecord) 255 { 256 HB_UNUSED(hb_type); 257 258 DUMP_FUINT (SubstLookupRecord, SequenceIndex); 259 DUMP_FUINT (SubstLookupRecord, LookupListIndex); 260 } 261 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 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 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 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 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 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 345 DEF_DUMP (ContextSubstFormat1) 346 { 347 HB_UNUSED(hb_type); 348 HB_UNUSED(ContextSubstFormat1); 349 350 351 DUMP("<!-- Not implemented!!! -->\n"); 352 } 353 354 DEF_DUMP (ContextSubstFormat2) 355 { 356 DUMP_FUINT (ContextSubstFormat2, MaxContextLength); 357 RECURSE (Coverage, Coverage, &ContextSubstFormat2->Coverage); 358 RECURSE (ClassDefinition, ClassDefinition, &ContextSubstFormat2->ClassDef); 359 } 360 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 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 391 DEF_DUMP (ChainContextSubstFormat1) 392 { 393 HB_UNUSED(hb_type); 394 HB_UNUSED(ChainContextSubstFormat1); 395 396 DUMP("<!-- Not implemented!!! -->\n"); 397 } 398 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 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 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 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 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 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 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 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 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 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 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 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 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 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