function _getClasses($offset) { $this->seek($offset); $ClassFormat = $this->read_ushort(); $GlyphByClass = array(); if ($ClassFormat == 1) { $StartGlyph = $this->read_ushort(); $GlyphCount = $this->read_ushort(); for ($i = 0; $i < $GlyphCount; $i++) { $startGlyphID = $StartGlyph + $i; $endGlyphID = $StartGlyph + $i; $class = $this->read_ushort(); for ($g = $startGlyphID; $g <= $endGlyphID; $g++) { if (isset($this->glyphToChar[$g][0])) { $GlyphByClass[$class][] = unicode_hex($this->glyphToChar[$g][0]); } } } } else { if ($ClassFormat == 2) { $tableCount = $this->read_ushort(); for ($i = 0; $i < $tableCount; $i++) { $startGlyphID = $this->read_ushort(); $endGlyphID = $this->read_ushort(); $class = $this->read_ushort(); for ($g = $startGlyphID; $g <= $endGlyphID; $g++) { if ($this->glyphToChar[$g][0]) { $GlyphByClass[$class][] = unicode_hex($this->glyphToChar[$g][0]); } } } } } $gbc = array(); foreach ($GlyphByClass as $class => $garr) { $gbc[$class] = implode('|', $garr); } return $gbc; }
function _getGPOSarray(&$Lookup, $lul, $scripttag, $level = 1, $lcoverage = '', $exB = '', $exL = '') { // Process (3) LookupList for specific Script-LangSys $html = ''; if ($level == 1) { $html .= '<bookmark level="0" content="GPOS features">'; } foreach ($lul as $luli => $tag) { $html .= '<div class="level' . $level . '">'; $html .= '<h5 class="level' . $level . '">'; if ($level == 1) { $html .= '<bookmark level="1" content="' . $tag . ' [#' . $luli . ']">'; } $html .= 'Lookup #' . $luli . ' [tag: <span style="color:#000066;">' . $tag . '</span>]</h5>'; $ignore = $this->_getGSUBignoreString($Lookup[$luli]['Flag'], $Lookup[$luli]['MarkFilteringSet']); if ($ignore) { $html .= '<div class="ignore">Ignoring: ' . $ignore . '</div> '; } $Type = $Lookup[$luli]['Type']; $Flag = $Lookup[$luli]['Flag']; if (($Flag & 0x1) == 1) { $dir = 'RTL'; } else { $dir = 'LTR'; } for ($c = 0; $c < $Lookup[$luli]['SubtableCount']; $c++) { $html .= '<div class="subtable">Subtable #' . $c; if ($level == 1) { $html .= '<bookmark level="2" content="Subtable #' . $c . '">'; } $html .= '</div>'; // Lets start $subtable_offset = $Lookup[$luli]['Subtables'][$c]; $this->seek($subtable_offset); $PosFormat = $this->read_ushort(); //////////////////////////////////////////////////////////////////////////////// // LookupType 1: Single adjustment Adjust position of a single glyph (e.g. SmallCaps/Sups/Subs) //////////////////////////////////////////////////////////////////////////////// if ($Lookup[$luli]['Type'] == 1) { $html .= '<div class="lookuptype">LookupType 1: Single adjustment [Format ' . $PosFormat . ']</div>'; //=========== // Format 1: //=========== if ($PosFormat == 1) { $Coverage = $subtable_offset + $this->read_ushort(); $ValueFormat = $this->read_ushort(); $Value = $this->_getValueRecord($ValueFormat); $this->seek($Coverage); $glyphs = $this->_getCoverage(); // Array of Hex Glyphs for ($g = 0; $g < count($glyphs); $g++) { if ($level == 2 && strpos($lcoverage, $glyphs[$g]) === false) { continue; } $html .= '<div class="substitution">'; $html .= '<span class="unicode">' . $this->formatUni($glyphs[$g]) . ' </span> '; if ($level == 2 && $exB) { $html .= $exB; } $html .= '<span class="unchanged"> ' . $this->formatEntity($glyphs[$g]) . '</span>'; if ($level == 2 && $exL) { $html .= $exL; } $html .= ' » » '; if ($level == 2 && $exB) { $html .= $exB; } $html .= '<span class="changed" style="font-feature-settings:\'' . $tag . '\' 1;"> ' . $this->formatEntity($glyphs[$g]) . '</span>'; if ($level == 2 && $exL) { $html .= $exL; } $html .= ' <span class="unicode">'; if ($Value['XPlacement']) { $html .= ' Xpl: ' . $Value['XPlacement'] . ';'; } if ($Value['YPlacement']) { $html .= ' YPl: ' . $Value['YPlacement'] . ';'; } if ($Value['XAdvance']) { $html .= ' Xadv: ' . $Value['XAdvance']; } $html .= '</span>'; $html .= '</div>'; } } else { if ($PosFormat == 2) { $Coverage = $subtable_offset + $this->read_ushort(); $ValueFormat = $this->read_ushort(); $ValueCount = $this->read_ushort(); $Values = array(); for ($v = 0; $v < $ValueCount; $v++) { $Values[] = $this->_getValueRecord($ValueFormat); } $this->seek($Coverage); $glyphs = $this->_getCoverage(); // Array of Hex Glyphs for ($g = 0; $g < count($glyphs); $g++) { if ($level == 2 && strpos($lcoverage, $glyphs[$g]) === false) { continue; } $Value = $Values[$g]; $html .= '<div class="substitution">'; $html .= '<span class="unicode">' . $this->formatUni($glyphs[$g]) . ' </span> '; if ($level == 2 && $exB) { $html .= $exB; } $html .= '<span class="unchanged"> ' . $this->formatEntity($glyphs[$g]) . '</span>'; if ($level == 2 && $exL) { $html .= $exL; } $html .= ' » » '; if ($level == 2 && $exB) { $html .= $exB; } $html .= '<span class="changed" style="font-feature-settings:\'' . $tag . '\' 1;"> ' . $this->formatEntity($glyphs[$g]) . '</span>'; if ($level == 2 && $exL) { $html .= $exL; } $html .= ' <span class="unicode">'; if ($Value['XPlacement']) { $html .= ' Xpl: ' . $Value['XPlacement'] . ';'; } if ($Value['YPlacement']) { $html .= ' YPl: ' . $Value['YPlacement'] . ';'; } if ($Value['XAdvance']) { $html .= ' Xadv: ' . $Value['XAdvance']; } $html .= '</span>'; $html .= '</div>'; } } } } else { if ($Lookup[$luli]['Type'] == 2) { $html .= '<div class="lookuptype">LookupType 2: Pair adjustment e.g. Kerning [Format ' . $PosFormat . ']</div>'; $Coverage = $subtable_offset + $this->read_ushort(); $ValueFormat1 = $this->read_ushort(); $ValueFormat2 = $this->read_ushort(); //=========== // Format 1: //=========== if ($PosFormat == 1) { $PairSetCount = $this->read_ushort(); $PairSetOffset = array(); for ($p = 0; $p < $PairSetCount; $p++) { $PairSetOffset[] = $subtable_offset + $this->read_ushort(); } $this->seek($Coverage); $glyphs = $this->_getCoverage(); // Array of Hex Glyphs for ($p = 0; $p < $PairSetCount; $p++) { if ($level == 2 && strpos($lcoverage, $glyphs[$p]) === false) { continue; } $this->seek($PairSetOffset[$p]); // First Glyph = $glyphs[$p] // Takes too long e.g. Calibri font - just list kerning pairs with this: $html .= '<div class="glyphs">'; $html .= '<span class="unchanged"> ' . $this->formatEntity($glyphs[$p]) . ' </span>'; //PairSet table $PairValueCount = $this->read_ushort(); for ($pv = 0; $pv < $PairValueCount; $pv++) { //PairValueRecord $gid = $this->read_ushort(); $SecondGlyph = unicode_hex($this->glyphToChar[$gid][0]); $Value1 = $this->_getValueRecord($ValueFormat1); $Value2 = $this->_getValueRecord($ValueFormat2); // If RTL pairs, GPOS declares a XPlacement e.g. -180 for an XAdvance of -180 to take // account of direction. mPDF does not need the XPlacement adjustment if ($dir == 'RTL' && $Value1['XPlacement']) { $Value1['XPlacement'] -= $Value1['XAdvance']; } if ($ValueFormat2) { // If RTL pairs, GPOS declares a XPlacement e.g. -180 for an XAdvance of -180 to take // account of direction. mPDF does not need the XPlacement adjustment if ($dir == 'RTL' && $Value2['XPlacement'] && $Value2['XAdvance']) { $Value2['XPlacement'] -= $Value2['XAdvance']; } } $html .= ' ' . $this->formatEntity($SecondGlyph) . ' '; /* $html .= '<div class="substitution">'; $html .= '<span class="unicode">'.$this->formatUni($glyphs[$p]).' </span> '; if ($level==2 && $exB) { $html .= $exB; } $html .= '<span class="unchanged"> '.$this->formatEntity($glyphs[$p]).$this->formatEntity($SecondGlyph).'</span>'; if ($level==2 && $exL) { $html .= $exL; } $html .= ' » » '; if ($level==2 && $exB) { $html .= $exB; } $html .= '<span class="changed" style="font-feature-settings:\''.$tag.'\' 1;"> '.$this->formatEntity($glyphs[$p]).$this->formatEntity($SecondGlyph).'</span>'; if ($level==2 && $exL) { $html .= $exL; } $html .= ' <span class="unicode">'; if ($Value1['XPlacement']) { $html .= ' Xpl[1]: '.$Value1['XPlacement'].';'; } if ($Value1['YPlacement']) { $html .= ' YPl[1]: '.$Value1['YPlacement'].';'; } if ($Value1['XAdvance']) { $html .= ' Xadv[1]: '.$Value1['XAdvance']; } if ($Value2['XPlacement']) { $html .= ' Xpl[2]: '.$Value2['XPlacement'].';'; } if ($Value2['YPlacement']) { $html .= ' YPl[2]: '.$Value2['YPlacement'].';'; } if ($Value2['XAdvance']) { $html .= ' Xadv[2]: '.$Value2['XAdvance']; } $html .= '</span>'; $html .= '</div>'; */ } $html .= '</div>'; } } else { if ($PosFormat == 2) { $ClassDef1 = $subtable_offset + $this->read_ushort(); $ClassDef2 = $subtable_offset + $this->read_ushort(); $Class1Count = $this->read_ushort(); $Class2Count = $this->read_ushort(); $sizeOfPair = 2 * $this->count_bits($ValueFormat1) + 2 * $this->count_bits($ValueFormat2); $sizeOfValueRecords = $Class1Count * $Class2Count * $sizeOfPair; // NB Class1Count includes Class 0 even though it is not defined by $ClassDef1 // i.e. Class1Count = 5; Class1 will contain array(indices 1-4); $Class1 = $this->_getClassDefinitionTable($ClassDef1); $Class2 = $this->_getClassDefinitionTable($ClassDef2); $this->seek($subtable_offset + 16); for ($i = 0; $i < $Class1Count; $i++) { for ($j = 0; $j < $Class2Count; $j++) { $Value1 = $this->_getValueRecord($ValueFormat1); $Value2 = $this->_getValueRecord($ValueFormat2); // If RTL pairs, GPOS declares a XPlacement e.g. -180 for an XAdvance of -180 // of direction. mPDF does not need the XPlacement adjustment if ($dir == 'RTL' && $Value1['XPlacement'] && $Value1['XAdvance']) { $Value1['XPlacement'] -= $Value1['XAdvance']; } if ($ValueFormat2) { if ($dir == 'RTL' && $Value2['XPlacement'] && $Value2['XAdvance']) { $Value2['XPlacement'] -= $Value2['XAdvance']; } } for ($c1 = 0; $c1 < count($Class1[$i]); $c1++) { $FirstGlyph = $Class1[$i][$c1]; if ($level == 2 && strpos($lcoverage, $FirstGlyph) === false) { continue; } for ($c2 = 0; $c2 < count($Class2[$j]); $c2++) { $SecondGlyph = $Class2[$j][$c2]; if (!$Value1['XPlacement'] && !$Value1['YPlacement'] && !$Value1['XAdvance'] && !$Value2['XPlacement'] && !$Value2['YPlacement'] && !$Value2['XAdvance']) { continue; } $html .= '<div class="substitution">'; $html .= '<span class="unicode">' . $this->formatUni($FirstGlyph) . ' </span> '; if ($level == 2 && $exB) { $html .= $exB; } $html .= '<span class="unchanged"> ' . $this->formatEntity($FirstGlyph) . $this->formatEntity($SecondGlyph) . '</span>'; if ($level == 2 && $exL) { $html .= $exL; } $html .= ' » » '; if ($level == 2 && $exB) { $html .= $exB; } $html .= '<span class="changed" style="font-feature-settings:\'' . $tag . '\' 1;"> ' . $this->formatEntity($FirstGlyph) . $this->formatEntity($SecondGlyph) . '</span>'; if ($level == 2 && $exL) { $html .= $exL; } $html .= ' <span class="unicode">'; if ($Value1['XPlacement']) { $html .= ' Xpl[1]: ' . $Value1['XPlacement'] . ';'; } if ($Value1['YPlacement']) { $html .= ' YPl[1]: ' . $Value1['YPlacement'] . ';'; } if ($Value1['XAdvance']) { $html .= ' Xadv[1]: ' . $Value1['XAdvance']; } if ($Value2['XPlacement']) { $html .= ' Xpl[2]: ' . $Value2['XPlacement'] . ';'; } if ($Value2['YPlacement']) { $html .= ' YPl[2]: ' . $Value2['YPlacement'] . ';'; } if ($Value2['XAdvance']) { $html .= ' Xadv[2]: ' . $Value2['XAdvance']; } $html .= '</span>'; $html .= '</div>'; } } } } } } } else { if ($Lookup[$luli]['Type'] == 3) { $html .= '<div class="lookuptype">LookupType 3: Cursive attachment </div>'; $Coverage = $subtable_offset + $this->read_ushort(); $EntryExitCount = $this->read_ushort(); $EntryAnchors = array(); $ExitAnchors = array(); for ($i = 0; $i < $EntryExitCount; $i++) { $EntryAnchors[$i] = $this->read_ushort(); $ExitAnchors[$i] = $this->read_ushort(); } $this->seek($Coverage); $Glyphs = $this->_getCoverage(); for ($i = 0; $i < $EntryExitCount; $i++) { // Need default XAdvance for glyph $pdfWidth = $this->mpdf->_getCharWidth($this->mpdf->fonts[$this->fontkey]['cw'], hexdec($Glyphs[$i])); $EntryAnchor = $EntryAnchors[$i]; $ExitAnchor = $ExitAnchors[$i]; $html .= '<div class="glyphs">'; $html .= '<span class="unchanged">' . $this->formatEntity($Glyphs[$i]) . ' </span> '; $html .= '<span class="unicode"> ' . $this->formatUni($Glyphs[$i]) . ' => '; if ($EntryAnchor != 0) { $EntryAnchor += $subtable_offset; list($x, $y) = $this->_getAnchorTable($EntryAnchor); if ($dir == 'RTL') { if (round($pdfWidth) == round($x * 1000 / $this->mpdf->fonts[$this->fontkey]['desc']['unitsPerEm'])) { $x = 0; } else { $x = $x - $pdfWidth * $this->mpdf->fonts[$this->fontkey]['desc']['unitsPerEm'] / 1000; } } $html .= " Entry X: " . $x . " Y: " . $y . "; "; } if ($ExitAnchor != 0) { $ExitAnchor += $subtable_offset; list($x, $y) = $this->_getAnchorTable($ExitAnchor); if ($dir == 'LTR') { if (round($pdfWidth) == round($x * 1000 / $this->mpdf->fonts[$this->fontkey]['desc']['unitsPerEm'])) { $x = 0; } else { $x = $x - $pdfWidth * $this->mpdf->fonts[$this->fontkey]['desc']['unitsPerEm'] / 1000; } } $html .= " Exit X: " . $x . " Y: " . $y . "; "; } $html .= '</span></div>'; } } else { if ($Lookup[$luli]['Type'] == 4) { $html .= '<div class="lookuptype">LookupType 4: MarkToBase attachment </div>'; $MarkCoverage = $subtable_offset + $this->read_ushort(); $BaseCoverage = $subtable_offset + $this->read_ushort(); $this->seek($MarkCoverage); $MarkGlyphs = $this->_getCoverage(); $this->seek($BaseCoverage); $BaseGlyphs = $this->_getCoverage(); $firstMark = ''; $html .= '<div class="glyphs">Marks: '; for ($i = 0; $i < count($MarkGlyphs); $i++) { if ($level == 2 && strpos($lcoverage, $MarkGlyphs[$i]) === false) { continue; } else { if (!$firstMark) { $firstMark = $MarkGlyphs[$i]; } } $html .= ' ' . $this->formatEntity($MarkGlyphs[$i]) . ' '; } $html .= '</div>'; if (!$firstMark) { return; } $html .= '<div class="glyphs">Bases: '; for ($j = 0; $j < count($BaseGlyphs); $j++) { $html .= ' ' . $this->formatEntity($BaseGlyphs[$j]) . ' '; } $html .= '</div>'; // Example $html .= '<div class="glyphs" style="font-feature-settings:\'' . $tag . '\' 1;">Example(s): '; for ($j = 0; $j < min(count($BaseGlyphs), 20); $j++) { $html .= ' ' . $this->formatEntity($BaseGlyphs[$j]) . $this->formatEntity($firstMark, true) . ' '; } $html .= '</div>'; } else { if ($Lookup[$luli]['Type'] == 5) { $html .= '<div class="lookuptype">LookupType 5: MarkToLigature attachment </div>'; $MarkCoverage = $subtable_offset + $this->read_ushort(); //$MarkCoverage is already set in $lcoverage 00065|00073 etc $LigatureCoverage = $subtable_offset + $this->read_ushort(); $ClassCount = $this->read_ushort(); // Number of classes defined for marks = Number of mark glyphs in the MarkCoverage table $MarkArray = $subtable_offset + $this->read_ushort(); // Offset to MarkArray table $LigatureArray = $subtable_offset + $this->read_ushort(); // Offset to LigatureArray table $this->seek($MarkCoverage); $MarkGlyphs = $this->_getCoverage(); $this->seek($LigatureCoverage); $LigatureGlyphs = $this->_getCoverage(); $firstMark = ''; $html .= '<div class="glyphs">Marks: <span class="unchanged">'; $MarkRecord = array(); for ($i = 0; $i < count($MarkGlyphs); $i++) { if ($level == 2 && strpos($lcoverage, $MarkGlyphs[$i]) === false) { continue; } else { if (!$firstMark) { $firstMark = $MarkGlyphs[$i]; } } // Get the relevant MarkRecord $MarkRecord[$i] = $this->_getMarkRecord($MarkArray, $i); //Mark Class is = $MarkRecord[$i]['Class'] $html .= ' ' . $this->formatEntity($MarkGlyphs[$i]) . ' '; } $html .= '</span></div>'; if (!$firstMark) { return; } $this->seek($LigatureArray); $LigatureCount = $this->read_ushort(); $LigatureAttach = array(); $html .= '<div class="glyphs">Ligatures: <span class="unchanged">'; for ($j = 0; $j < count($LigatureGlyphs); $j++) { // Get the relevant LigatureRecord $LigatureAttach[$j] = $LigatureArray + $this->read_ushort(); $html .= ' ' . $this->formatEntity($LigatureGlyphs[$j]) . ' '; } $html .= '</span></div>'; /* for ($i=0;$i<count($MarkGlyphs);$i++) { $html .= '<div class="glyphs">'; $html .= '<span class="unchanged">'.$this->formatEntity($MarkGlyphs[$i]).'</span>'; for ($j=0;$j<count($LigatureGlyphs);$j++) { $this->seek($LigatureAttach[$j]); $ComponentCount = $this->read_ushort(); $html .= '<span class="unchanged">'.$this->formatEntity($LigatureGlyphs[$j]).'</span>'; $offsets = array(); for ($comp=0;$comp<$ComponentCount;$comp++) { // ComponentRecords for ($class=0;$class<$ClassCount;$class++) { $offset = $this->read_ushort(); if ($offset!= 0 && $class == $MarkRecord[$i]['Class']) { $html .= ' ['.$comp.'] '; } } } } $html .= '</span></div>'; } */ } else { if ($Lookup[$luli]['Type'] == 6) { $html .= '<div class="lookuptype">LookupType 6: MarkToMark attachment </div>'; $Mark1Coverage = $subtable_offset + $this->read_ushort(); // Combining Mark //$Mark1Coverage is already set in $LuCoverage 0065|0073 etc $Mark2Coverage = $subtable_offset + $this->read_ushort(); // Base Mark $ClassCount = $this->read_ushort(); // Number of classes defined for marks = No. of Combining mark1 glyphs in the MarkCoverage table $this->seek($Mark1Coverage); $Mark1Glyphs = $this->_getCoverage(); $this->seek($Mark2Coverage); $Mark2Glyphs = $this->_getCoverage(); $firstMark = ''; $html .= '<div class="glyphs">Marks: <span class="unchanged">'; for ($i = 0; $i < count($Mark1Glyphs); $i++) { if ($level == 2 && strpos($lcoverage, $Mark1Glyphs[$i]) === false) { continue; } else { if (!$firstMark) { $firstMark = $Mark1Glyphs[$i]; } } $html .= ' ' . $this->formatEntity($Mark1Glyphs[$i]) . ' '; } $html .= '</span></div>'; if ($firstMark) { $html .= '<div class="glyphs">Bases: <span class="unchanged">'; for ($j = 0; $j < count($Mark2Glyphs); $j++) { $html .= ' ' . $this->formatEntity($Mark2Glyphs[$j]) . ' '; } $html .= '</span></div>'; // Example $html .= '<div class="glyphs" style="font-feature-settings:\'' . $tag . '\' 1;">Example(s): <span class="changed">'; for ($j = 0; $j < min(count($Mark2Glyphs), 20); $j++) { $html .= ' ' . $this->formatEntity($Mark2Glyphs[$j]) . $this->formatEntity($firstMark, true) . ' '; } $html .= '</span></div>'; } } else { if ($Lookup[$luli]['Type'] == 7) { $html .= '<div class="lookuptype">LookupType 7: Context positioning [Format ' . $PosFormat . ']</div>'; //=========== // Format 1: //=========== if ($PosFormat == 1) { die("GPOS Lookup Type " . $Type . " Format " . $PosFormat . " not YET TESTED."); } else { if ($PosFormat == 2) { die("GPOS Lookup Type " . $Type . " Format " . $PosFormat . " not YET TESTED."); } else { if ($PosFormat == 3) { die("GPOS Lookup Type " . $Type . " Format " . $PosFormat . " not YET TESTED."); } else { die("GPOS Lookup Type " . $Type . ", Format " . $PosFormat . " not supported."); } } } } else { if ($Lookup[$luli]['Type'] == 8) { $html .= '<div class="lookuptype">LookupType 8: Chained Context positioning [Format ' . $PosFormat . ']</div>'; //=========== // Format 1: //=========== if ($PosFormat == 1) { die("GPOS Lookup Type " . $Type . " Format " . $PosFormat . " not TESTED YET."); } else { if ($PosFormat == 2) { $html .= '<div>GPOS Lookup Type 8: Format 2 not yet supported in OTL dump</div>'; continue; /* NB When developing - cf. GSUB 6.2 */ die("GPOS Lookup Type " . $Type . " Format " . $PosFormat . " not TESTED YET."); } else { if ($PosFormat == 3) { $BacktrackGlyphCount = $this->read_ushort(); $CoverageBacktrackOffset = array(); for ($b = 0; $b < $BacktrackGlyphCount; $b++) { $CoverageBacktrackOffset[] = $subtable_offset + $this->read_ushort(); // in glyph sequence order } $InputGlyphCount = $this->read_ushort(); $CoverageInputOffset = array(); for ($b = 0; $b < $InputGlyphCount; $b++) { $CoverageInputOffset[] = $subtable_offset + $this->read_ushort(); // in glyph sequence order } $LookaheadGlyphCount = $this->read_ushort(); $CoverageLookaheadOffset = array(); for ($b = 0; $b < $LookaheadGlyphCount; $b++) { $CoverageLookaheadOffset[] = $subtable_offset + $this->read_ushort(); // in glyph sequence order } $PosCount = $this->read_ushort(); $PosLookupRecord = array(); for ($p = 0; $p < $PosCount; $p++) { // PosLookupRecord $PosLookupRecord[$p]['SequenceIndex'] = $this->read_ushort(); $PosLookupRecord[$p]['LookupListIndex'] = $this->read_ushort(); } $backtrackGlyphs = array(); for ($b = 0; $b < $BacktrackGlyphCount; $b++) { $this->seek($CoverageBacktrackOffset[$b]); $backtrackGlyphs[$b] = implode('|', $this->_getCoverage()); } $inputGlyphs = array(); for ($b = 0; $b < $InputGlyphCount; $b++) { $this->seek($CoverageInputOffset[$b]); $inputGlyphs[$b] = implode('|', $this->_getCoverage()); } $lookaheadGlyphs = array(); for ($b = 0; $b < $LookaheadGlyphCount; $b++) { $this->seek($CoverageLookaheadOffset[$b]); $lookaheadGlyphs[$b] = implode('|', $this->_getCoverage()); } $exampleB = array(); $exampleI = array(); $exampleL = array(); $html .= '<div class="context">CONTEXT: '; for ($ff = count($backtrackGlyphs) - 1; $ff >= 0; $ff--) { $html .= '<div>Backtrack #' . $ff . ': <span class="unicode">' . $this->formatUniStr($backtrackGlyphs[$ff]) . '</span></div>'; $exampleB[] = $this->formatEntityFirst($backtrackGlyphs[$ff]); } for ($ff = 0; $ff < count($inputGlyphs); $ff++) { $html .= '<div>Input #' . $ff . ': <span class="unchanged"> ' . $this->formatEntityStr($inputGlyphs[$ff]) . ' </span></div>'; $exampleI[] = $this->formatEntityFirst($inputGlyphs[$ff]); } for ($ff = 0; $ff < count($lookaheadGlyphs); $ff++) { $html .= '<div>Lookahead #' . $ff . ': <span class="unicode">' . $this->formatUniStr($lookaheadGlyphs[$ff]) . '</span></div>'; $exampleL[] = $this->formatEntityFirst($lookaheadGlyphs[$ff]); } $html .= '</div>'; for ($p = 0; $p < $PosCount; $p++) { $lup = $PosLookupRecord[$p]['LookupListIndex']; $seqIndex = $PosLookupRecord[$p]['SequenceIndex']; // GENERATE exampleB[n] exampleI[<seqIndex] .... exampleI[>seqIndex] exampleL[n] $exB = ''; $exL = ''; if (count($exampleB)) { $exB .= '<span class="backtrack">' . implode('‍', $exampleB) . '</span>'; } if ($seqIndex > 0) { $exB .= '<span class="inputother">'; for ($ip = 0; $ip < $seqIndex; $ip++) { $exB .= $exampleI[$ip] . '‍'; } $exB .= '</span>'; } if (count($inputGlyphs) > $seqIndex + 1) { $exL .= '<span class="inputother">'; for ($ip = $seqIndex + 1; $ip < count($inputGlyphs); $ip++) { $exL .= '‍' . $exampleI[$ip]; } $exL .= '</span>'; } if (count($exampleL)) { $exL .= '<span class="lookahead">' . implode('‍', $exampleL) . '</span>'; } $html .= '<div class="sequenceIndex">Substitution Position: ' . $seqIndex . '</div>'; $lul2 = array($lup => $tag); // Only apply if the (first) 'Replace' glyph from the // Lookup list is in the [inputGlyphs] at ['SequenceIndex'] // Pass $inputGlyphs[$seqIndex] e.g. 00636|00645|00656 // to level 2 and only apply if first Replace glyph is in this list $html .= $this->_getGPOSarray($Lookup, $lul2, $scripttag, 2, $inputGlyphs[$seqIndex], $exB, $exL); } } } } } } } } } } } } } $html .= '</div>'; } if ($level == 1) { $this->mpdf->WriteHTML($html); } else { return $html; } //print_r($Lookup); exit; }