diff --git a/src/Otl.php b/src/Otl.php index 0237092b0..98795c4f6 100644 --- a/src/Otl.php +++ b/src/Otl.php @@ -1642,13 +1642,13 @@ function _applyGSUBsubtableSpecial($lookupID, $subtable, $ptr, $currGlyph, $curr //////////////////////////////////////////////////////////////////////////////// $Coverage = $subtable_offset + $this->reader->readUInt16(); $NextGlyphPos = $LuCoverage[$nextGID]; - $LigSetCount = $this->reader->readInt16(); + $LigSetCount = $this->reader->readUInt16(); $this->reader->skip($NextGlyphPos * 2); - $LigSet = $subtable_offset + $this->reader->readInt16(); + $LigSet = $subtable_offset + $this->reader->readUInt16(); $this->reader->seek($LigSet); - $LigCount = $this->reader->readInt16(); + $LigCount = $this->reader->readUInt16(); // LigatureSet i.e. all starting with the same Glyph $nextGlyph [Consonant] $LigatureOffset = []; for ($g = 0; $g < $LigCount; $g++) { @@ -1824,10 +1824,10 @@ private function _applyGSUBmultipleSubst($lookupID, $subtable, $ptr, $currGlyph, $GlyphPos = $LuCoverage[$currGID]; $this->reader->skip(2); $this->reader->skip($GlyphPos * 2); - $Sequences = $subtable_offset + $this->reader->readInt16(); + $Sequences = $subtable_offset + $this->reader->readUInt16(); $this->reader->seek($Sequences); - $GlyphCount = $this->reader->readInt16(); + $GlyphCount = $this->reader->readUInt16(); $SubstituteGlyphs = []; for ($g = 0; $g < $GlyphCount; $g++) { $sgid = $this->reader->readUInt16(); @@ -1861,7 +1861,7 @@ private function _applyGSUBalternateSubst($lookupID, $subtable, $ptr, $currGlyph return 0; } $Coverage = $subtable_offset + $this->reader->readUInt16(); - $AlternateSetCount = $this->reader->readInt16(); + $AlternateSetCount = $this->reader->readUInt16(); ///////////////////////////////////////////////////////////////////////////////!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // Need to set alternate IF set by CSS3 font-feature for a tag // i.e. if this is 'salt' alternate may be set to 2 @@ -1878,10 +1878,10 @@ private function _applyGSUBalternateSubst($lookupID, $subtable, $ptr, $currGlyph $GlyphPos = $LuCoverage[$currGID]; $this->reader->skip($GlyphPos * 2); - $AlternateSets = $subtable_offset + $this->reader->readInt16(); + $AlternateSets = $subtable_offset + $this->reader->readUInt16(); $this->reader->seek($AlternateSets); - $AlternateGlyphCount = $this->reader->readInt16(); + $AlternateGlyphCount = $this->reader->readUInt16(); if ($alt > $AlternateGlyphCount) { return 0; } // If specified alternate not present, cancel [ or could default $alt = 1 ?] @@ -1919,13 +1919,13 @@ private function _applyGSUBligatureSubst($lookupID, $subtable, $ptr, $currGlyph, $Coverage = $subtable_offset + $this->reader->readUInt16(); $FirstGlyphPos = $LuCoverage[$currGID]; - $LigSetCount = $this->reader->readInt16(); + $LigSetCount = $this->reader->readUInt16(); $this->reader->skip($FirstGlyphPos * 2); - $LigSet = $subtable_offset + $this->reader->readInt16(); + $LigSet = $subtable_offset + $this->reader->readUInt16(); $this->reader->seek($LigSet); - $LigCount = $this->reader->readInt16(); + $LigCount = $this->reader->readUInt16(); // LigatureSet i.e. all starting with the same first Glyph $currGlyph $LigatureOffset = []; for ($g = 0; $g < $LigCount; $g++) { diff --git a/src/OtlDump.php b/src/OtlDump.php index 0023678e4..2c7e01c85 100644 --- a/src/OtlDump.php +++ b/src/OtlDump.php @@ -1205,14 +1205,14 @@ function _getGSUBtables() else { if ($Lookup[$i]['Type'] == 2) { $Lookup[$i]['Subtable'][$c]['CoverageTableOffset'] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->reader->readUInt16(); - $Lookup[$i]['Subtable'][$c]['SequenceCount'] = $SequenceCount = $this->reader->readInt16(); + $Lookup[$i]['Subtable'][$c]['SequenceCount'] = $SequenceCount = $this->reader->readUInt16(); for ($s = 0; $s < $SequenceCount; $s++) { - $Lookup[$i]['Subtable'][$c]['Sequences'][$s]['Offset'] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->reader->readInt16(); + $Lookup[$i]['Subtable'][$c]['Sequences'][$s]['Offset'] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->reader->readUInt16(); } for ($s = 0; $s < $SequenceCount; $s++) { // Sequence Tables $this->reader->seek($Lookup[$i]['Subtable'][$c]['Sequences'][$s]['Offset']); - $Lookup[$i]['Subtable'][$c]['Sequences'][$s]['GlyphCount'] = $this->reader->readInt16(); + $Lookup[$i]['Subtable'][$c]['Sequences'][$s]['GlyphCount'] = $this->reader->readUInt16(); for ($g = 0; $g < $Lookup[$i]['Subtable'][$c]['Sequences'][$s]['GlyphCount']; $g++) { $Lookup[$i]['Subtable'][$c]['Sequences'][$s]['SubstituteGlyphID'][] = $this->reader->readUInt16(); } @@ -1221,15 +1221,15 @@ function _getGSUBtables() else { if ($Lookup[$i]['Type'] == 3) { $Lookup[$i]['Subtable'][$c]['CoverageTableOffset'] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->reader->readUInt16(); - $Lookup[$i]['Subtable'][$c]['AlternateSetCount'] = $AlternateSetCount = $this->reader->readInt16(); + $Lookup[$i]['Subtable'][$c]['AlternateSetCount'] = $AlternateSetCount = $this->reader->readUInt16(); for ($s = 0; $s < $AlternateSetCount; $s++) { - $Lookup[$i]['Subtable'][$c]['AlternateSets'][$s]['Offset'] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->reader->readInt16(); + $Lookup[$i]['Subtable'][$c]['AlternateSets'][$s]['Offset'] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->reader->readUInt16(); } for ($s = 0; $s < $AlternateSetCount; $s++) { // AlternateSet Tables $this->reader->seek($Lookup[$i]['Subtable'][$c]['AlternateSets'][$s]['Offset']); - $Lookup[$i]['Subtable'][$c]['AlternateSets'][$s]['GlyphCount'] = $this->reader->readInt16(); + $Lookup[$i]['Subtable'][$c]['AlternateSets'][$s]['GlyphCount'] = $this->reader->readUInt16(); for ($g = 0; $g < $Lookup[$i]['Subtable'][$c]['AlternateSets'][$s]['GlyphCount']; $g++) { $Lookup[$i]['Subtable'][$c]['AlternateSets'][$s]['SubstituteGlyphID'][] = $this->reader->readUInt16(); } @@ -1238,14 +1238,14 @@ function _getGSUBtables() else { if ($Lookup[$i]['Type'] == 4) { $Lookup[$i]['Subtable'][$c]['CoverageTableOffset'] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->reader->readUInt16(); - $Lookup[$i]['Subtable'][$c]['LigSetCount'] = $LigSetCount = $this->reader->readInt16(); + $Lookup[$i]['Subtable'][$c]['LigSetCount'] = $LigSetCount = $this->reader->readUInt16(); for ($s = 0; $s < $LigSetCount; $s++) { - $Lookup[$i]['Subtable'][$c]['LigSet'][$s]['Offset'] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->reader->readInt16(); + $Lookup[$i]['Subtable'][$c]['LigSet'][$s]['Offset'] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->reader->readUInt16(); } for ($s = 0; $s < $LigSetCount; $s++) { // LigatureSet Tables $this->reader->seek($Lookup[$i]['Subtable'][$c]['LigSet'][$s]['Offset']); - $Lookup[$i]['Subtable'][$c]['LigSet'][$s]['LigCount'] = $this->reader->readInt16(); + $Lookup[$i]['Subtable'][$c]['LigSet'][$s]['LigCount'] = $this->reader->readUInt16(); for ($g = 0; $g < $Lookup[$i]['Subtable'][$c]['LigSet'][$s]['LigCount']; $g++) { $Lookup[$i]['Subtable'][$c]['LigSet'][$s]['LigatureOffset'][$g] = $Lookup[$i]['Subtable'][$c]['LigSet'][$s]['Offset'] + $this->reader->readUInt16(); } @@ -1267,14 +1267,14 @@ function _getGSUBtables() // Format 1: Context Substitution if ($SubstFormat == 1) { $Lookup[$i]['Subtable'][$c]['CoverageTableOffset'] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->reader->readUInt16(); - $Lookup[$i]['Subtable'][$c]['SubRuleSetCount'] = $SubRuleSetCount = $this->reader->readInt16(); + $Lookup[$i]['Subtable'][$c]['SubRuleSetCount'] = $SubRuleSetCount = $this->reader->readUInt16(); for ($s = 0; $s < $SubRuleSetCount; $s++) { - $Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['Offset'] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->reader->readInt16(); + $Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['Offset'] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->reader->readUInt16(); } for ($s = 0; $s < $SubRuleSetCount; $s++) { // SubRuleSet Tables $this->reader->seek($Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['Offset']); - $Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['SubRuleCount'] = $this->reader->readInt16(); + $Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['SubRuleCount'] = $this->reader->readUInt16(); for ($g = 0; $g < $Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['SubRuleCount']; $g++) { $Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['SubRuleOffset'][$g] = $Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['Offset'] + $this->reader->readUInt16(); } diff --git a/tests/Mpdf/LargeSubtableTest.php b/tests/Mpdf/LargeSubtableTest.php new file mode 100644 index 000000000..ad5c78c37 --- /dev/null +++ b/tests/Mpdf/LargeSubtableTest.php @@ -0,0 +1,126 @@ + 'utf-8', + 'fontDir' => [__DIR__ . '/../data/ttf'], + 'fontdata' => ['bigsubtable' => [ + 'R' => 'NotoSans-GSUB2-BigSubtable-Synthetic.ttf', + 'useOTL' => 0xFF, + ]], + 'default_font' => 'bigsubtable', + ]); + $mpdf->WriteHTML('

' . $html . '

'); + + return array_values(unpack('N*', mb_convert_encoding($mpdf->drawnText[0], 'UTF-32BE', 'UTF-8'))); + } + + /** + * The control: a glyph whose Sequence is well inside the first 32 KB was always read correctly. + * The markers have no codepoints of their own, so the run is read by its shape rather than by + * naming them. + */ + public function testAGlyphBeforeTheBoundaryExpandsIntoItsOwnRun() + { + $drawn = $this->drawn([self::EARLY]); + + $this->assertCount(self::SEQUENCE_LENGTH, $drawn); + $this->assertSame(self::EARLY, $drawn[self::SELF_POSITION]); + } + + /** + * The first glyph past the boundary. Read signed, its offset was negative: the shaper seeked + * before the subtable, read a glyph count of its own and replaced the character with eight glyphs + * belonging to another - the character typed was not on the page at all. + */ + public function testAGlyphPastTheBoundaryExpandsIntoItsOwnRun() + { + $drawn = $this->drawn([self::FIRST_PAST_BOUNDARY]); + + $this->assertCount(self::SEQUENCE_LENGTH, $drawn); + $this->assertSame(self::FIRST_PAST_BOUNDARY, $drawn[self::SELF_POSITION]); + } + + /** + * Every covered glyph is given the same markers, so the two runs have to agree everywhere but the + * middle. Run against the last glyph of the subtable, 3 KB further past the boundary, so that a + * glyph past it is read from its own Sequence rather than from one that happens to be as long. + */ + public function testTheRunPastTheBoundaryIsTheSameRunAsTheOneBeforeIt() + { + $early = $this->drawn([self::EARLY]); + $late = $this->drawn([self::LAST]); + + unset($early[self::SELF_POSITION], $late[self::SELF_POSITION]); + + $this->assertSame($early, $late); + } + + /** + * Four of them in one run. A font that shapes this way feeds the markers to chaining rules that + * compute on them, so a Sequence read from the wrong place is not one wrong glyph but a run those + * rules then match against and expand again: Noto Sans Duployan turned four characters into + * 102,109 glyphs and 52 seconds of shaping. + */ + public function testEachGlyphOfARunExpandsOnce() + { + $run = [self::LAST - 3, self::LAST - 2, self::LAST - 1, self::LAST]; + $drawn = $this->drawn($run); + + $this->assertCount(count($run) * self::SEQUENCE_LENGTH, $drawn); + foreach ($run as $i => $codepoint) { + $this->assertSame( + $codepoint, + $drawn[$i * self::SEQUENCE_LENGTH + self::SELF_POSITION], + sprintf('the character at position %d is not in the run it expanded into', $i) + ); + } + } + +} diff --git a/tests/Snapshots/LargeSubtableSnapshotTest.php b/tests/Snapshots/LargeSubtableSnapshotTest.php new file mode 100644 index 000000000..b5a0fe6cb --- /dev/null +++ b/tests/Snapshots/LargeSubtableSnapshotTest.php @@ -0,0 +1,142 @@ +mpdf and + * loading it with content + * + * @return void + * @internal Don't call any $this->mpdf->Output*() method + */ + public function generatePdf() + { + $this->mpdf = $this->createMpdf($this->config()); + $this->mpdf->WriteHTML($this->style() . $this->samples()); + } + + private function config() + { + return [ + 'mode' => 'utf-8', + 'fontDir' => [__DIR__ . '/../data/ttf'], + 'fontdata' => [ + 'bigsubtable' => [ + 'R' => 'NotoSans-GSUB2-BigSubtable-Synthetic.ttf', + 'useOTL' => 0xFF, + ], + ], + ]; + } + + private function style() + { + ob_start(); + ?> + + +

mPDF

+

A substitution subtable over 32 KB

+

Each of these characters is replaced by a run of fifteen markers with the + character itself in the middle. The markers draw nothing, so a row shows the shape of the + character that was typed - unless the record was read from the wrong place, in which case the + character is gone and the row is blank.

+ '; + foreach (self::SAMPLES as $sample) { + list($name, $codepoint, $where) = $sample; + $html .= '' . $name . ' U+' . sprintf('%04X', $codepoint) + . ' - ' . $where . '' + . '' . sprintf('&#x%04X;', $codepoint) . ''; + } + + return $html . ''; + } + + /** + * The font comes from the inline style rather than from the stylesheet, so the sample stands on + * its own and the run is the first thing drawn. + * + * @return int[] the codepoints the sample was drawn with + */ + private function drawn($codepoint) + { + $mpdf = new TextRecordingMpdf($this->config()); + $mpdf->WriteHTML(sprintf('

&#x%04X;

', $codepoint)); + + return array_values(unpack('N*', mb_convert_encoding($mpdf->drawnText[0], 'UTF-32BE', 'UTF-8'))); + } + + /** + * The document only shows anything if each row draws the character that was typed. The markers + * around it have no codepoints of their own, so the run is read by where the character sits in it + * rather than by naming them. + */ + public function testEveryRowDrawsTheCharacterThatWasTyped() + { + foreach (self::SAMPLES as $sample) { + list($name, $codepoint) = $sample; + $drawn = $this->drawn($codepoint); + + $this->assertCount(self::SEQUENCE_LENGTH, $drawn, $name . ' was not replaced by a run of sixteen'); + $this->assertSame($codepoint, $drawn[self::SELF_POSITION], $name . ' is not in the run it expanded into'); + } + } +} diff --git a/tests/data/fontcache/NotoSans-GSUB2-BigSubtable-Synthetic.json b/tests/data/fontcache/NotoSans-GSUB2-BigSubtable-Synthetic.json new file mode 100644 index 000000000..f84eebd60 --- /dev/null +++ b/tests/data/fontcache/NotoSans-GSUB2-BigSubtable-Synthetic.json @@ -0,0 +1,1053 @@ +{ + "_": "Generated by composer fontcache:update. See tests/Mpdf/Fonts/ParserGoldenMaster.php.", + "fullName": "NotoSans-GSUB2-BigSubtable-Synthetic", + "mtx": { + "GSUBScriptLang": { + "DFLT": "DFLT " + }, + "GSUBFeatures": { + "DFLT": { + "DFLT": { + "ccmp": [ + 0 + ] + } + } + }, + "GSUBLookups": [ + { + "Type": 2, + "Flag": 0, + "SubtableCount": 1, + "Subtables": [ + 56 + ], + "MarkFilteringSet": "" + } + ], + "GPOSScriptLang": [], + "GPOSFeatures": [], + "GPOSLookups": [], + "MarkGlyphSets": [], + "rtlPUAstr": "", + "haskernGPOS": false, + "hassmallcapsGSUB": false + }, + "cache": { + "GDEFdata.json": { + "GlyphClassBases": " 0E000| 0E001| 0E002| 0E003| 0E004| 0E005| 0E006| 0E007| 0E008| 0E009| 0E00A| 0E00B| 0E00C| 0E00D| 0E00E| 0E00F| 0E010| 0E011| 0E012| 0E013| 0E014| 0E015| 0E016| 0E017| 0E018| 0E019| 0E01A| 0E01B| 0E01C| 0E01D| 0E01E| 0E01F| 0E020| 0E021| 0E022| 0E023| 0E024| 0E025| 0E026| 0E027| 0E028| 0E029| 0E02A| 0E02B| 0E02C| 0E02D| 0E02E| 0E02F| 0E030| 0E031| 0E032| 0E033| 0E034| 0E035| 0E036| 0E037| 0E038| 0E039| 0E03A| 0E03B| 0E03C| 0E03D| 0E03E| 0E03F| 0E040| 0E041| 0E042| 0E043| 0E044| 0E045| 0E046| 0E047| 0E048| 0E049| 0E04A| 0E04B| 0E04C| 0E04D| 0E04E| 0E04F| 0E050| 0E051| 0E052| 0E053| 0E054| 0E055| 0E056| 0E057| 0E058| 0E059| 0E05A| 0E05B| 0E05C| 0E05D| 0E05E| 0E05F| 0E060| 0E061| 0E062| 0E063| 0E064| 0E065| 0E066| 0E067| 0E068| 0E069| 0E06A| 0E06B| 0E06C| 0E06D| 0E06E| 0E06F| 0E070| 0E071| 0E072| 0E073| 0E074| 0E075| 0E076| 0E077| 0E078| 0E079| 0E07A| 0E07B| 0E07C| 0E07D| 0E07E| 0E07F| 0E080| 0E081| 0E082| 0E083| 0E084| 0E085| 0E086| 0E087| 0E088| 0E089| 0E08A| 0E08B| 0E08C| 0E08D| 0E08E| 0E08F| 0E090| 0E091| 0E092| 0E093| 0E094| 0E095| 0E096| 0E097| 0E098| 0E099| 0E09A| 0E09B| 0E09C| 0E09D| 0E09E| 0E09F| 0E0A0| 0E0A1| 0E0A2| 0E0A3| 0E0A4| 0E0A5| 0E0A6| 0E0A7| 0E0A8| 0E0A9| 0E0AA| 0E0AB| 0E0AC| 0E0AD| 0E0AE| 0E0AF| 0E0B0| 0E0B1| 0E0B2| 0E0B3| 0E0B4| 0E0B5| 0E0B6| 0E0B7| 0E0B8| 0E0B9| 0E0BA| 0E0BB| 0E0BC| 0E0BD| 0E0BE| 0E0BF| 0E0C0| 0E0C1| 0E0C2| 0E0C3| 0E0C4| 0E0C5| 0E0C6| 0E0C7| 0E0C8| 0E0C9| 0E0CA| 0E0CB| 0E0CC| 0E0CD| 0E0CE| 0E0CF| 0E0D0| 0E0D1| 0E0D2| 0E0D3| 0E0D4| 0E0D5| 0E0D6| 0E0D7| 0E0D8| 0E0D9| 0E0DA| 0E0DB| 0E0DC| 0E0DD| 0E0DE| 0E0DF| 0E0E0| 0E0E1| 0E0E2| 0E0E3| 0E0E4| 0E0E5| 0E0E6| 0E0E7| 0E0E8| 0E0E9| 0E0EA| 0E0EB| 0E0EC| 0E0ED| 0E0EE| 0E0EF| 0E0F0| 0E0F1| 0E0F2| 0E0F3| 0E0F4| 0E0F5| 0E0F6| 0E0F7| 0E0F8| 0E0F9| 0E0FA| 0E0FB| 0E0FC| 0E0FD| 0E0FE| 0E0FF| 0E100| 0E101| 0E102| 0E103| 0E104| 0E105| 0E106| 0E107| 0E108| 0E109| 0E10A| 0E10B| 0E10C| 0E10D| 0E10E| 0E10F| 0E110| 0E111| 0E112| 0E113| 0E114| 0E115| 0E116| 0E117| 0E118| 0E119| 0E11A| 0E11B| 0E11C| 0E11D| 0E11E| 0E11F| 0E120| 0E121| 0E122| 0E123| 0E124| 0E125| 0E126| 0E127| 0E128| 0E129| 0E12A| 0E12B| 0E12C| 0E12D| 0E12E| 0E12F| 0E130| 0E131| 0E132| 0E133| 0E134| 0E135| 0E136| 0E137| 0E138| 0E139| 0E13A| 0E13B| 0E13C| 0E13D| 0E13E| 0E13F| 0E140| 0E141| 0E142| 0E143| 0E144| 0E145| 0E146| 0E147| 0E148| 0E149| 0E14A| 0E14B| 0E14C| 0E14D| 0E14E| 0E14F| 0E150| 0E151| 0E152| 0E153| 0E154| 0E155| 0E156| 0E157| 0E158| 0E159| 0E15A| 0E15B| 0E15C| 0E15D| 0E15E| 0E15F| 0E160| 0E161| 0E162| 0E163| 0E164| 0E165| 0E166| 0E167| 0E168| 0E169| 0E16A| 0E16B| 0E16C| 0E16D| 0E16E| 0E16F| 0E170| 0E171| 0E172| 0E173| 0E174| 0E175| 0E176| 0E177| 0E178| 0E179| 0E17A| 0E17B| 0E17C| 0E17D| 0E17E| 0E17F| 0E180| 0E181| 0E182| 0E183| 0E184| 0E185| 0E186| 0E187| 0E188| 0E189| 0E18A| 0E18B| 0E18C| 0E18D| 0E18E| 0E18F| 0E190| 0E191| 0E192| 0E193| 0E194| 0E195| 0E196| 0E197| 0E198| 0E199| 0E19A| 0E19B| 0E19C| 0E19D| 0E19E| 0E19F| 0E1A0| 0E1A1| 0E1A2| 0E1A3| 0E1A4| 0E1A5| 0E1A6| 0E1A7| 0E1A8| 0E1A9| 0E1AA| 0E1AB| 0E1AC| 0E1AD| 0E1AE| 0E1AF| 0E1B0| 0E1B1| 0E1B2| 0E1B3| 0E1B4| 0E1B5| 0E1B6| 0E1B7| 0E1B8| 0E1B9| 0E1BA| 0E1BB| 0E1BC| 0E1BD| 0E1BE| 0E1BF| 0E1C0| 0E1C1| 0E1C2| 0E1C3| 0E1C4| 0E1C5| 0E1C6| 0E1C7| 0E1C8| 0E1C9| 0E1CA| 0E1CB| 0E1CC| 0E1CD| 0E1CE| 0E1CF| 0E1D0| 0E1D1| 0E1D2| 0E1D3| 0E1D4| 0E1D5| 0E1D6| 0E1D7| 0E1D8| 0E1D9| 0E1DA| 0E1DB| 0E1DC| 0E1DD| 0E1DE| 0E1DF| 0E1E0| 0E1E1| 0E1E2| 0E1E3| 0E1E4| 0E1E5| 0E1E6| 0E1E7| 0E1E8| 0E1E9| 0E1EA| 0E1EB| 0E1EC| 0E1ED| 0E1EE| 0E1EF| 0E1F0| 0E1F1| 0E1F2| 0E1F3| 0E1F4| 0E1F5| 0E1F6| 0E1F7| 0E1F8| 0E1F9| 0E1FA| 0E1FB| 0E1FC| 0E1FD| 0E1FE| 0E1FF| 0E200| 0E201| 0E202| 0E203| 0E204| 0E205| 0E206| 0E207| 0E208| 0E209| 0E20A| 0E20B| 0E20C| 0E20D| 0E20E| 0E20F| 0E210| 0E211| 0E212| 0E213| 0E214| 0E215| 0E216| 0E217| 0E218| 0E219| 0E21A| 0E21B| 0E21C| 0E21D| 0E21E| 0E21F| 0E220| 0E221| 0E222| 0E223| 0E224| 0E225| 0E226| 0E227| 0E228| 0E229| 0E22A| 0E22B| 0E22C| 0E22D| 0E22E| 0E22F| 0E230| 0E231| 0E232| 0E233| 0E234| 0E235| 0E236| 0E237| 0E238| 0E239| 0E23A| 0E23B| 0E23C| 0E23D| 0E23E| 0E23F| 0E240| 0E241| 0E242| 0E243| 0E244| 0E245| 0E246| 0E247| 0E248| 0E249| 0E24A| 0E24B| 0E24C| 0E24D| 0E24E| 0E24F| 0E250| 0E251| 0E252| 0E253| 0E254| 0E255| 0E256| 0E257| 0E258| 0E259| 0E25A| 0E25B| 0E25C| 0E25D| 0E25E| 0E25F| 0E260| 0E261| 0E262| 0E263| 0E264| 0E265| 0E266| 0E267| 0E268| 0E269| 0E26A| 0E26B| 0E26C| 0E26D| 0E26E| 0E26F| 0E270| 0E271| 0E272| 0E273| 0E274| 0E275| 0E276| 0E277| 0E278| 0E279| 0E27A| 0E27B| 0E27C| 0E27D| 0E27E| 0E27F| 0E280| 0E281| 0E282| 0E283| 0E284| 0E285| 0E286| 0E287| 0E288| 0E289| 0E28A| 0E28B| 0E28C| 0E28D| 0E28E| 0E28F| 0E290| 0E291| 0E292| 0E293| 0E294| 0E295| 0E296| 0E297| 0E298| 0E299| 0E29A| 0E29B| 0E29C| 0E29D| 0E29E| 0E29F| 0E2A0| 0E2A1| 0E2A2| 0E2A3| 0E2A4| 0E2A5| 0E2A6| 0E2A7| 0E2A8| 0E2A9| 0E2AA| 0E2AB| 0E2AC| 0E2AD| 0E2AE| 0E2AF| 0E2B0| 0E2B1| 0E2B2| 0E2B3| 0E2B4| 0E2B5| 0E2B6| 0E2B7| 0E2B8| 0E2B9| 0E2BA| 0E2BB| 0E2BC| 0E2BD| 0E2BE| 0E2BF| 0E2C0| 0E2C1| 0E2C2| 0E2C3| 0E2C4| 0E2C5| 0E2C6| 0E2C7| 0E2C8| 0E2C9| 0E2CA| 0E2CB| 0E2CC| 0E2CD| 0E2CE| 0E2CF| 0E2D0| 0E2D1| 0E2D2| 0E2D3| 0E2D4| 0E2D5| 0E2D6| 0E2D7| 0E2D8| 0E2D9| 0E2DA| 0E2DB| 0E2DC| 0E2DD| 0E2DE| 0E2DF| 0E2E0| 0E2E1| 0E2E2| 0E2E3| 0E2E4| 0E2E5| 0E2E6| 0E2E7| 0E2E8| 0E2E9| 0E2EA| 0E2EB| 0E2EC| 0E2ED| 0E2EE| 0E2EF| 0E2F0| 0E2F1| 0E2F2| 0E2F3| 0E2F4| 0E2F5| 0E2F6| 0E2F7| 0E2F8| 0E2F9| 0E2FA| 0E2FB| 0E2FC| 0E2FD| 0E2FE| 0E2FF| 0E300| 0E301| 0E302| 0E303| 0E304| 0E305| 0E306| 0E307| 0E308| 0E309| 0E30A| 0E30B| 0E30C| 0E30D| 0E30E| 0E30F| 0E310| 0E311| 0E312| 0E313| 0E314| 0E315| 0E316| 0E317| 0E318| 0E319| 0E31A| 0E31B| 0E31C| 0E31D| 0E31E| 0E31F| 0E320| 0E321| 0E322| 0E323| 0E324| 0E325| 0E326| 0E327| 0E328| 0E329| 0E32A| 0E32B| 0E32C| 0E32D| 0E32E| 0E32F| 0E330| 0E331| 0E332| 0E333| 0E334| 0E335| 0E336| 0E337| 0E338| 0E339| 0E33A| 0E33B| 0E33C| 0E33D| 0E33E| 0E33F| 0E340| 0E341| 0E342| 0E343| 0E344| 0E345| 0E346| 0E347| 0E348| 0E349| 0E34A| 0E34B| 0E34C| 0E34D| 0E34E| 0E34F| 0E350| 0E351| 0E352| 0E353| 0E354| 0E355| 0E356| 0E357| 0E358| 0E359| 0E35A| 0E35B| 0E35C| 0E35D| 0E35E| 0E35F| 0E360| 0E361| 0E362| 0E363| 0E364| 0E365| 0E366| 0E367| 0E368| 0E369| 0E36A| 0E36B| 0E36C| 0E36D| 0E36E| 0E36F| 0E370| 0E371| 0E372| 0E373| 0E374| 0E375| 0E376| 0E377| 0E378| 0E379| 0E37A| 0E37B| 0E37C| 0E37D| 0E37E| 0E37F| 0E380| 0E381| 0E382| 0E383| 0E384| 0E385| 0E386| 0E387| 0E388| 0E389| 0E38A| 0E38B| 0E38C| 0E38D| 0E38E| 0E38F| 0E390| 0E391| 0E392| 0E393| 0E394| 0E395| 0E396| 0E397| 0E398| 0E399| 0E39A| 0E39B| 0E39C| 0E39D| 0E39E| 0E39F| 0E3A0| 0E3A1| 0E3A2| 0E3A3| 0E3A4| 0E3A5| 0E3A6| 0E3A7| 0E3A8| 0E3A9| 0E3AA| 0E3AB| 0E3AC| 0E3AD| 0E3AE| 0E3AF| 0E3B0| 0E3B1| 0E3B2| 0E3B3| 0E3B4| 0E3B5| 0E3B6| 0E3B7| 0E3B8| 0E3B9| 0E3BA| 0E3BB| 0E3BC| 0E3BD| 0E3BE| 0E3BF| 0E3C0| 0E3C1| 0E3C2| 0E3C3| 0E3C4| 0E3C5| 0E3C6| 0E3C7| 0E3C8| 0E3C9| 0E3CA| 0E3CB| 0E3CC| 0E3CD| 0E3CE| 0E3CF| 0E3D0| 0E3D1| 0E3D2| 0E3D3| 0E3D4| 0E3D5| 0E3D6| 0E3D7| 0E3D8| 0E3D9| 0E3DA| 0E3DB| 0E3DC| 0E3DD| 0E3DE| 0E3DF| 0E3E0| 0E3E1| 0E3E2| 0E3E3| 0E3E4| 0E3E5| 0E3E6| 0E3E7", + "GlyphClassMarks": " 0E3E8| 0E3E9| 0E3EA| 0E3EB| 0E3EC| 0E3ED| 0E3EE| 0E3EF| 0E3F0| 0E3F1| 0E3F2| 0E3F3| 0E3F4| 0E3F5| 0E3F6", + "GlyphClassLigatures": "", + "GlyphClassComponents": "", + "MarkGlyphSets": [], + "MarkAttachmentType": [] + }, + "GSUB.dat": "36072 bytes, sha256 6fc0558b0e4e9a4348e45908fbd9ddbb728fb0603b84b36ac717f1ec265d7e18", + "GSUBdata.json": [ + [ + { + "57344": 0, + "57345": 1, + "57346": 2, + "57347": 3, + "57348": 4, + "57349": 5, + "57350": 6, + "57351": 7, + "57352": 8, + "57353": 9, + "57354": 10, + "57355": 11, + "57356": 12, + "57357": 13, + "57358": 14, + "57359": 15, + "57360": 16, + "57361": 17, + "57362": 18, + "57363": 19, + "57364": 20, + "57365": 21, + "57366": 22, + "57367": 23, + "57368": 24, + "57369": 25, + "57370": 26, + "57371": 27, + "57372": 28, + "57373": 29, + "57374": 30, + "57375": 31, + "57376": 32, + "57377": 33, + "57378": 34, + "57379": 35, + "57380": 36, + "57381": 37, + "57382": 38, + "57383": 39, + "57384": 40, + "57385": 41, + "57386": 42, + "57387": 43, + "57388": 44, + "57389": 45, + "57390": 46, + "57391": 47, + "57392": 48, + "57393": 49, + "57394": 50, + "57395": 51, + "57396": 52, + "57397": 53, + "57398": 54, + "57399": 55, + "57400": 56, + "57401": 57, + "57402": 58, + "57403": 59, + "57404": 60, + "57405": 61, + "57406": 62, + "57407": 63, + "57408": 64, + "57409": 65, + "57410": 66, + "57411": 67, + "57412": 68, + "57413": 69, + "57414": 70, + "57415": 71, + "57416": 72, + "57417": 73, + "57418": 74, + "57419": 75, + "57420": 76, + "57421": 77, + "57422": 78, + "57423": 79, + "57424": 80, + "57425": 81, + "57426": 82, + "57427": 83, + "57428": 84, + "57429": 85, + "57430": 86, + "57431": 87, + "57432": 88, + "57433": 89, + "57434": 90, + "57435": 91, + "57436": 92, + "57437": 93, + "57438": 94, + "57439": 95, + "57440": 96, + "57441": 97, + "57442": 98, + "57443": 99, + "57444": 100, + "57445": 101, + "57446": 102, + "57447": 103, + "57448": 104, + "57449": 105, + "57450": 106, + "57451": 107, + "57452": 108, + "57453": 109, + "57454": 110, + "57455": 111, + "57456": 112, + "57457": 113, + "57458": 114, + "57459": 115, + "57460": 116, + "57461": 117, + "57462": 118, + "57463": 119, + "57464": 120, + "57465": 121, + "57466": 122, + "57467": 123, + "57468": 124, + "57469": 125, + "57470": 126, + "57471": 127, + "57472": 128, + "57473": 129, + "57474": 130, + "57475": 131, + "57476": 132, + "57477": 133, + "57478": 134, + "57479": 135, + "57480": 136, + "57481": 137, + "57482": 138, + "57483": 139, + "57484": 140, + "57485": 141, + "57486": 142, + "57487": 143, + "57488": 144, + "57489": 145, + "57490": 146, + "57491": 147, + "57492": 148, + "57493": 149, + "57494": 150, + "57495": 151, + "57496": 152, + "57497": 153, + "57498": 154, + "57499": 155, + "57500": 156, + "57501": 157, + "57502": 158, + "57503": 159, + "57504": 160, + "57505": 161, + "57506": 162, + "57507": 163, + "57508": 164, + "57509": 165, + "57510": 166, + "57511": 167, + "57512": 168, + "57513": 169, + "57514": 170, + "57515": 171, + "57516": 172, + "57517": 173, + "57518": 174, + "57519": 175, + "57520": 176, + "57521": 177, + "57522": 178, + "57523": 179, + "57524": 180, + "57525": 181, + "57526": 182, + "57527": 183, + "57528": 184, + "57529": 185, + "57530": 186, + "57531": 187, + "57532": 188, + "57533": 189, + "57534": 190, + "57535": 191, + "57536": 192, + "57537": 193, + "57538": 194, + "57539": 195, + "57540": 196, + "57541": 197, + "57542": 198, + "57543": 199, + "57544": 200, + "57545": 201, + "57546": 202, + "57547": 203, + "57548": 204, + "57549": 205, + "57550": 206, + "57551": 207, + "57552": 208, + "57553": 209, + "57554": 210, + "57555": 211, + "57556": 212, + "57557": 213, + "57558": 214, + "57559": 215, + "57560": 216, + "57561": 217, + "57562": 218, + "57563": 219, + "57564": 220, + "57565": 221, + "57566": 222, + "57567": 223, + "57568": 224, + "57569": 225, + "57570": 226, + "57571": 227, + "57572": 228, + "57573": 229, + "57574": 230, + "57575": 231, + "57576": 232, + "57577": 233, + "57578": 234, + "57579": 235, + "57580": 236, + "57581": 237, + "57582": 238, + "57583": 239, + "57584": 240, + "57585": 241, + "57586": 242, + "57587": 243, + "57588": 244, + "57589": 245, + "57590": 246, + "57591": 247, + "57592": 248, + "57593": 249, + "57594": 250, + "57595": 251, + "57596": 252, + "57597": 253, + "57598": 254, + "57599": 255, + "57600": 256, + "57601": 257, + "57602": 258, + "57603": 259, + "57604": 260, + "57605": 261, + "57606": 262, + "57607": 263, + "57608": 264, + "57609": 265, + "57610": 266, + "57611": 267, + "57612": 268, + "57613": 269, + "57614": 270, + "57615": 271, + "57616": 272, + "57617": 273, + "57618": 274, + "57619": 275, + "57620": 276, + "57621": 277, + "57622": 278, + "57623": 279, + "57624": 280, + "57625": 281, + "57626": 282, + "57627": 283, + "57628": 284, + "57629": 285, + "57630": 286, + "57631": 287, + "57632": 288, + "57633": 289, + "57634": 290, + "57635": 291, + "57636": 292, + "57637": 293, + "57638": 294, + "57639": 295, + "57640": 296, + "57641": 297, + "57642": 298, + "57643": 299, + "57644": 300, + "57645": 301, + "57646": 302, + "57647": 303, + "57648": 304, + "57649": 305, + "57650": 306, + "57651": 307, + "57652": 308, + "57653": 309, + "57654": 310, + "57655": 311, + "57656": 312, + "57657": 313, + "57658": 314, + "57659": 315, + "57660": 316, + "57661": 317, + "57662": 318, + "57663": 319, + "57664": 320, + "57665": 321, + "57666": 322, + "57667": 323, + "57668": 324, + "57669": 325, + "57670": 326, + "57671": 327, + "57672": 328, + "57673": 329, + "57674": 330, + "57675": 331, + "57676": 332, + "57677": 333, + "57678": 334, + "57679": 335, + "57680": 336, + "57681": 337, + "57682": 338, + "57683": 339, + "57684": 340, + "57685": 341, + "57686": 342, + "57687": 343, + "57688": 344, + "57689": 345, + "57690": 346, + "57691": 347, + "57692": 348, + "57693": 349, + "57694": 350, + "57695": 351, + "57696": 352, + "57697": 353, + "57698": 354, + "57699": 355, + "57700": 356, + "57701": 357, + "57702": 358, + "57703": 359, + "57704": 360, + "57705": 361, + "57706": 362, + "57707": 363, + "57708": 364, + "57709": 365, + "57710": 366, + "57711": 367, + "57712": 368, + "57713": 369, + "57714": 370, + "57715": 371, + "57716": 372, + "57717": 373, + "57718": 374, + "57719": 375, + "57720": 376, + "57721": 377, + "57722": 378, + "57723": 379, + "57724": 380, + "57725": 381, + "57726": 382, + "57727": 383, + "57728": 384, + "57729": 385, + "57730": 386, + "57731": 387, + "57732": 388, + "57733": 389, + "57734": 390, + "57735": 391, + "57736": 392, + "57737": 393, + "57738": 394, + "57739": 395, + "57740": 396, + "57741": 397, + "57742": 398, + "57743": 399, + "57744": 400, + "57745": 401, + "57746": 402, + "57747": 403, + "57748": 404, + "57749": 405, + "57750": 406, + "57751": 407, + "57752": 408, + "57753": 409, + "57754": 410, + "57755": 411, + "57756": 412, + "57757": 413, + "57758": 414, + "57759": 415, + "57760": 416, + "57761": 417, + "57762": 418, + "57763": 419, + "57764": 420, + "57765": 421, + "57766": 422, + "57767": 423, + "57768": 424, + "57769": 425, + "57770": 426, + "57771": 427, + "57772": 428, + "57773": 429, + "57774": 430, + "57775": 431, + "57776": 432, + "57777": 433, + "57778": 434, + "57779": 435, + "57780": 436, + "57781": 437, + "57782": 438, + "57783": 439, + "57784": 440, + "57785": 441, + "57786": 442, + "57787": 443, + "57788": 444, + "57789": 445, + "57790": 446, + "57791": 447, + "57792": 448, + "57793": 449, + "57794": 450, + "57795": 451, + "57796": 452, + "57797": 453, + "57798": 454, + "57799": 455, + "57800": 456, + "57801": 457, + "57802": 458, + "57803": 459, + "57804": 460, + "57805": 461, + "57806": 462, + "57807": 463, + "57808": 464, + "57809": 465, + "57810": 466, + "57811": 467, + "57812": 468, + "57813": 469, + "57814": 470, + "57815": 471, + "57816": 472, + "57817": 473, + "57818": 474, + "57819": 475, + "57820": 476, + "57821": 477, + "57822": 478, + "57823": 479, + "57824": 480, + "57825": 481, + "57826": 482, + "57827": 483, + "57828": 484, + "57829": 485, + "57830": 486, + "57831": 487, + "57832": 488, + "57833": 489, + "57834": 490, + "57835": 491, + "57836": 492, + "57837": 493, + "57838": 494, + "57839": 495, + "57840": 496, + "57841": 497, + "57842": 498, + "57843": 499, + "57844": 500, + "57845": 501, + "57846": 502, + "57847": 503, + "57848": 504, + "57849": 505, + "57850": 506, + "57851": 507, + "57852": 508, + "57853": 509, + "57854": 510, + "57855": 511, + "57856": 512, + "57857": 513, + "57858": 514, + "57859": 515, + "57860": 516, + "57861": 517, + "57862": 518, + "57863": 519, + "57864": 520, + "57865": 521, + "57866": 522, + "57867": 523, + "57868": 524, + "57869": 525, + "57870": 526, + "57871": 527, + "57872": 528, + "57873": 529, + "57874": 530, + "57875": 531, + "57876": 532, + "57877": 533, + "57878": 534, + "57879": 535, + "57880": 536, + "57881": 537, + "57882": 538, + "57883": 539, + "57884": 540, + "57885": 541, + "57886": 542, + "57887": 543, + "57888": 544, + "57889": 545, + "57890": 546, + "57891": 547, + "57892": 548, + "57893": 549, + "57894": 550, + "57895": 551, + "57896": 552, + "57897": 553, + "57898": 554, + "57899": 555, + "57900": 556, + "57901": 557, + "57902": 558, + "57903": 559, + "57904": 560, + "57905": 561, + "57906": 562, + "57907": 563, + "57908": 564, + "57909": 565, + "57910": 566, + "57911": 567, + "57912": 568, + "57913": 569, + "57914": 570, + "57915": 571, + "57916": 572, + "57917": 573, + "57918": 574, + "57919": 575, + "57920": 576, + "57921": 577, + "57922": 578, + "57923": 579, + "57924": 580, + "57925": 581, + "57926": 582, + "57927": 583, + "57928": 584, + "57929": 585, + "57930": 586, + "57931": 587, + "57932": 588, + "57933": 589, + "57934": 590, + "57935": 591, + "57936": 592, + "57937": 593, + "57938": 594, + "57939": 595, + "57940": 596, + "57941": 597, + "57942": 598, + "57943": 599, + "57944": 600, + "57945": 601, + "57946": 602, + "57947": 603, + "57948": 604, + "57949": 605, + "57950": 606, + "57951": 607, + "57952": 608, + "57953": 609, + "57954": 610, + "57955": 611, + "57956": 612, + "57957": 613, + "57958": 614, + "57959": 615, + "57960": 616, + "57961": 617, + "57962": 618, + "57963": 619, + "57964": 620, + "57965": 621, + "57966": 622, + "57967": 623, + "57968": 624, + "57969": 625, + "57970": 626, + "57971": 627, + "57972": 628, + "57973": 629, + "57974": 630, + "57975": 631, + "57976": 632, + "57977": 633, + "57978": 634, + "57979": 635, + "57980": 636, + "57981": 637, + "57982": 638, + "57983": 639, + "57984": 640, + "57985": 641, + "57986": 642, + "57987": 643, + "57988": 644, + "57989": 645, + "57990": 646, + "57991": 647, + "57992": 648, + "57993": 649, + "57994": 650, + "57995": 651, + "57996": 652, + "57997": 653, + "57998": 654, + "57999": 655, + "58000": 656, + "58001": 657, + "58002": 658, + "58003": 659, + "58004": 660, + "58005": 661, + "58006": 662, + "58007": 663, + "58008": 664, + "58009": 665, + "58010": 666, + "58011": 667, + "58012": 668, + "58013": 669, + "58014": 670, + "58015": 671, + "58016": 672, + "58017": 673, + "58018": 674, + "58019": 675, + "58020": 676, + "58021": 677, + "58022": 678, + "58023": 679, + "58024": 680, + "58025": 681, + "58026": 682, + "58027": 683, + "58028": 684, + "58029": 685, + "58030": 686, + "58031": 687, + "58032": 688, + "58033": 689, + "58034": 690, + "58035": 691, + "58036": 692, + "58037": 693, + "58038": 694, + "58039": 695, + "58040": 696, + "58041": 697, + "58042": 698, + "58043": 699, + "58044": 700, + "58045": 701, + "58046": 702, + "58047": 703, + "58048": 704, + "58049": 705, + "58050": 706, + "58051": 707, + "58052": 708, + "58053": 709, + "58054": 710, + "58055": 711, + "58056": 712, + "58057": 713, + "58058": 714, + "58059": 715, + "58060": 716, + "58061": 717, + "58062": 718, + "58063": 719, + "58064": 720, + "58065": 721, + "58066": 722, + "58067": 723, + "58068": 724, + "58069": 725, + "58070": 726, + "58071": 727, + "58072": 728, + "58073": 729, + "58074": 730, + "58075": 731, + "58076": 732, + "58077": 733, + "58078": 734, + "58079": 735, + "58080": 736, + "58081": 737, + "58082": 738, + "58083": 739, + "58084": 740, + "58085": 741, + "58086": 742, + "58087": 743, + "58088": 744, + "58089": 745, + "58090": 746, + "58091": 747, + "58092": 748, + "58093": 749, + "58094": 750, + "58095": 751, + "58096": 752, + "58097": 753, + "58098": 754, + "58099": 755, + "58100": 756, + "58101": 757, + "58102": 758, + "58103": 759, + "58104": 760, + "58105": 761, + "58106": 762, + "58107": 763, + "58108": 764, + "58109": 765, + "58110": 766, + "58111": 767, + "58112": 768, + "58113": 769, + "58114": 770, + "58115": 771, + "58116": 772, + "58117": 773, + "58118": 774, + "58119": 775, + "58120": 776, + "58121": 777, + "58122": 778, + "58123": 779, + "58124": 780, + "58125": 781, + "58126": 782, + "58127": 783, + "58128": 784, + "58129": 785, + "58130": 786, + "58131": 787, + "58132": 788, + "58133": 789, + "58134": 790, + "58135": 791, + "58136": 792, + "58137": 793, + "58138": 794, + "58139": 795, + "58140": 796, + "58141": 797, + "58142": 798, + "58143": 799, + "58144": 800, + "58145": 801, + "58146": 802, + "58147": 803, + "58148": 804, + "58149": 805, + "58150": 806, + "58151": 807, + "58152": 808, + "58153": 809, + "58154": 810, + "58155": 811, + "58156": 812, + "58157": 813, + "58158": 814, + "58159": 815, + "58160": 816, + "58161": 817, + "58162": 818, + "58163": 819, + "58164": 820, + "58165": 821, + "58166": 822, + "58167": 823, + "58168": 824, + "58169": 825, + "58170": 826, + "58171": 827, + "58172": 828, + "58173": 829, + "58174": 830, + "58175": 831, + "58176": 832, + "58177": 833, + "58178": 834, + "58179": 835, + "58180": 836, + "58181": 837, + "58182": 838, + "58183": 839, + "58184": 840, + "58185": 841, + "58186": 842, + "58187": 843, + "58188": 844, + "58189": 845, + "58190": 846, + "58191": 847, + "58192": 848, + "58193": 849, + "58194": 850, + "58195": 851, + "58196": 852, + "58197": 853, + "58198": 854, + "58199": 855, + "58200": 856, + "58201": 857, + "58202": 858, + "58203": 859, + "58204": 860, + "58205": 861, + "58206": 862, + "58207": 863, + "58208": 864, + "58209": 865, + "58210": 866, + "58211": 867, + "58212": 868, + "58213": 869, + "58214": 870, + "58215": 871, + "58216": 872, + "58217": 873, + "58218": 874, + "58219": 875, + "58220": 876, + "58221": 877, + "58222": 878, + "58223": 879, + "58224": 880, + "58225": 881, + "58226": 882, + "58227": 883, + "58228": 884, + "58229": 885, + "58230": 886, + "58231": 887, + "58232": 888, + "58233": 889, + "58234": 890, + "58235": 891, + "58236": 892, + "58237": 893, + "58238": 894, + "58239": 895, + "58240": 896, + "58241": 897, + "58242": 898, + "58243": 899, + "58244": 900, + "58245": 901, + "58246": 902, + "58247": 903, + "58248": 904, + "58249": 905, + "58250": 906, + "58251": 907, + "58252": 908, + "58253": 909, + "58254": 910, + "58255": 911, + "58256": 912, + "58257": 913, + "58258": 914, + "58259": 915, + "58260": 916, + "58261": 917, + "58262": 918, + "58263": 919, + "58264": 920, + "58265": 921, + "58266": 922, + "58267": 923, + "58268": 924, + "58269": 925, + "58270": 926, + "58271": 927, + "58272": 928, + "58273": 929, + "58274": 930, + "58275": 931, + "58276": 932, + "58277": 933, + "58278": 934, + "58279": 935, + "58280": 936, + "58281": 937, + "58282": 938, + "58283": 939, + "58284": 940, + "58285": 941, + "58286": 942, + "58287": 943, + "58288": 944, + "58289": 945, + "58290": 946, + "58291": 947, + "58292": 948, + "58293": 949, + "58294": 950, + "58295": 951, + "58296": 952, + "58297": 953, + "58298": 954, + "58299": 955, + "58300": 956, + "58301": 957, + "58302": 958, + "58303": 959, + "58304": 960, + "58305": 961, + "58306": 962, + "58307": 963, + "58308": 964, + "58309": 965, + "58310": 966, + "58311": 967, + "58312": 968, + "58313": 969, + "58314": 970, + "58315": 971, + "58316": 972, + "58317": 973, + "58318": 974, + "58319": 975, + "58320": 976, + "58321": 977, + "58322": 978, + "58323": 979, + "58324": 980, + "58325": 981, + "58326": 982, + "58327": 983, + "58328": 984, + "58329": 985, + "58330": 986, + "58331": 987, + "58332": 988, + "58333": 989, + "58334": 990, + "58335": 991, + "58336": 992, + "58337": 993, + "58338": 994, + "58339": 995, + "58340": 996, + "58341": 997, + "58342": 998, + "58343": 999 + } + ] + ] + } +} diff --git a/tests/data/otldump/NotoSans-GSUB2-BigSubtable-Synthetic.txt b/tests/data/otldump/NotoSans-GSUB2-BigSubtable-Synthetic.txt new file mode 100644 index 000000000..0b83983f0 --- /dev/null +++ b/tests/data/otldump/NotoSans-GSUB2-BigSubtable-Synthetic.txt @@ -0,0 +1,21 @@ +

GDEF table

+

Glyph classes

+

Glyph class 1

+
Base glyph (single character, spacing glyph)
+
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       
+

Glyph class 3

+
Mark glyph (non-spacing combining glyph)
+
◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌
+

GSUB Tables

+

GSUB Scripts & Languages

+
+
DFLT
DFLT: ccmp
+
+
GPOS table not defined
+ +=== detail: script DFLT language DFLT === +609403 bytes, sha256 e4a58d9c2a74c1d25ba00f10bb4440b33d7e8a52eb0fbe1ab9b170916316b4a6 +first 8192 bytes: +

GSUB Tables

+
Lookup #0 [tag: ccmp]
Subtable #0
LookupType 2: Multiple Substitution Subtable
M+E000     » »   ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌  ◌ ◌ ◌ ◌ ◌ ◌ ◌  M+E3E8, M+E3E9, M+E3EA, M+E3EB, M+E3EC, M+E3ED, M+E3EE, M+E3EF, M+E000, M+E3F0, M+E3F1, M+E3F2, M+E3F3, M+E3F4, M+E3F5, M+E3F6
M+E001     » »   ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌  ◌ ◌ ◌ ◌ ◌ ◌ ◌  M+E3E8, M+E3E9, M+E3EA, M+E3EB, M+E3EC, M+E3ED, M+E3EE, M+E3EF, M+E001, M+E3F0, M+E3F1, M+E3F2, M+E3F3, M+E3F4, M+E3F5, M+E3F6
M+E002     » »   ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌  ◌ ◌ ◌ ◌ ◌ ◌ ◌  M+E3E8, M+E3E9, M+E3EA, M+E3EB, M+E3EC, M+E3ED, M+E3EE, M+E3EF, M+E002, M+E3F0, M+E3F1, M+E3F2, M+E3F3, M+E3F4, M+E3F5, M+E3F6
M+E003     » »   ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌  ◌ ◌ ◌ ◌ ◌ ◌ ◌  M+E3E8, M+E3E9, M+E3EA, M+E3EB, M+E3EC, M+E3ED, M+E3EE, M+E3EF, M+E003, M+E3F0, M+E3F1, M+E3F2, M+E3F3, M+E3F4, M+E3F5, M+E3F6
M+E004     » »   ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌  ◌ ◌ ◌ ◌ ◌ ◌ ◌  M+E3E8, M+E3E9, M+E3EA, M+E3EB, M+E3EC, M+E3ED, M+E3EE, M+E3EF, M+E004, M+E3F0, M+E3F1, M+E3F2, M+E3F3, M+E3F4, M+E3F5, M+E3F6
M+E005     » »   ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌  ◌ ◌ ◌ ◌ ◌ ◌ ◌  M+E3E8, M+E3E9, M+E3EA, M+E3EB, M+E3EC, M+E3ED, M+E3EE, M+E3EF, M+E005, M+E3F0, M+E3F1, M+E3F2, M+E3F3, M+E3F4, M+E3F5, M+E3F6
M+E006     » »   ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌  ◌ ◌ ◌ ◌ ◌ ◌ ◌  M+E3E8, M+E3E9, M+E3EA, M+E3EB, M+E3EC, M+E3ED, M+E3EE, M+E3EF, M+E006, M+E3F0, M+E3F1, M+E3F2, M+E3F3, M+E3F4, M+E3F5, M+E3F6
M+E007     » »   ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌  ◌ ◌ ◌ ◌ ◌ ◌ ◌  M+E3E8, M+E3E9, M+E3EA, M+E3EB, M+E3EC, M+E3ED, M+E3EE, M+E3EF, M+E007, M+E3F0, M+E3F1, M+E3F2, M+E3F3, M+E3F4, M+E3F5, M+E3F6
M+E008     » »   ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌  ◌ ◌ ◌ ◌ ◌ ◌ ◌  M+E3E8, M+E3E9, M+E3EA, M+E3EB, M+E3EC, M+E3ED, M+E3EE, M+E3EF, M+E008, M+E3F0, M+E3F1, M+E3F2, M+E3F3, M+E3F4, M+E3F5, M+E3F6
M+E009     » »   ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌  ◌ ◌ ◌ ◌ ◌ ◌ ◌  M+E3E8, M+E3E9, M+E3EA, M+E3EB, M+E3EC, M+E3ED, M+E3EE, M+E3EF, M+E009, M+E3F0, M+E3F1, M+E3F2, M+E3F3, M+E3F4, M+E3F5, M+E3F6
M+E00A     » »   ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌  ◌ ◌ ◌ ◌ ◌ ◌ ◌  M+E3E8, M+E3E9, M+E3EA, M+E3EB, M+E3EC, M+E3ED, M+E3EE, M+E3EF, M+E00A, M+E3F0, M+E3F1, M+E3F2, M+E3F3, M+E3F4, M+E3F5, M+E3F6
M+E00B     » »   ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌  ◌ ◌ ◌ ◌ ◌ ◌ ◌  M+E3E8, M+E3E9, M+E3EA, M+E3EB, M+E3EC, M+E3ED, M+E3EE, M+E3EF, M+E00B, M+E3F0, M+E3F1, M+E3F2, M+E3F3, M+E3F4, M+E3F5, M+E3F6
M+E00C     » »   ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌  ◌ ◌ ◌ ◌ ◌ ◌ ◌  M+E3E8, M+E3E9, M+E3EA, M+E3EB, M+E3EC, M+E3ED, M+E3EE + diff --git a/tests/data/snapshots/large-subtable.pdf b/tests/data/snapshots/large-subtable.pdf new file mode 100644 index 000000000..5cceb70b0 Binary files /dev/null and b/tests/data/snapshots/large-subtable.pdf differ diff --git a/tests/data/ttf/NotoSans-GSUB2-BigSubtable-Synthetic.ttf b/tests/data/ttf/NotoSans-GSUB2-BigSubtable-Synthetic.ttf new file mode 100644 index 000000000..861ed1bc2 Binary files /dev/null and b/tests/data/ttf/NotoSans-GSUB2-BigSubtable-Synthetic.ttf differ