| @@ -2,10 +2,10 @@ | ||
| 2 | 2 | |
| 3 | 3 | /******************************************************************************* |
| 4 | 4 | * TTFontFile class * |
| 5 | 5 | * * |
| 6 | -* Version: 4.01 * | |
| 7 | -* Date: 2014-10-25 * | |
| 6 | +* Version: 2.01 * | |
| 7 | +* Date: 2012-02-25 * | |
| 8 | 8 | * Author: Ian Back <[email protected]> * |
| 9 | 9 | * License: LGPL * |
| 10 | 10 | * Copyright (c) Ian Back, 2010 * |
| 11 | 11 | * This class is based on The ReportLab Open Source PDF library * |
| @@ -15,14 +15,8 @@ | ||
| 15 | 15 | * modification of the file. * |
| 16 | 16 | * * |
| 17 | 17 | *******************************************************************************/ |
| 18 | 18 | |
| 19 | - | |
| 20 | - | |
| 21 | -// NOTE*** If you change the defined constants below, be sure to delete all temporary font data files in /ttfontdata/ | |
| 22 | -// to force mPDF to regenerate cached font files. | |
| 23 | -if (!defined('_OTL_OLD_SPEC_COMPAT_2')) define("_OTL_OLD_SPEC_COMPAT_2", true); | |
| 24 | - | |
| 25 | 19 | // Define the value used in the "head" table of a created TTF file |
| 26 | 20 | // 0x74727565 "true" for Mac |
| 27 | 21 | // 0x00010000 for Windows |
| 28 | 22 | // Either seems to work for a font embedded in a PDF file |
| @@ -39,32 +33,13 @@ | ||
| 39 | 33 | define("GF_MORE",(1 << 5)); |
| 40 | 34 | define("GF_XYSCALE",(1 << 6)); |
| 41 | 35 | define("GF_TWOBYTWO",(1 << 7)); |
| 42 | 36 | |
| 43 | -// mPDF 5.7.1 | |
| 44 | -if(!function_exists('unicode_hex')){ | |
| 45 | - function unicode_hex($unicode_dec) { | |
| 46 | - return (sprintf("%05s", strtoupper(dechex($unicode_dec)))); | |
| 47 | - } | |
| 48 | -} | |
| 49 | 37 | |
| 50 | 38 | |
| 51 | 39 | class TTFontFile { |
| 52 | 40 | |
| 53 | -var $GPOSFeatures; // mPDF 5.7.1 | |
| 54 | -var $GPOSLookups; // mPDF 5.7.1 | |
| 55 | -var $GPOSScriptLang; // mPDF 5.7.1 | |
| 56 | -var $MarkAttachmentType; // mPDF 5.7.1 | |
| 57 | -var $MarkGlyphSets; // mPDF 7.5.1 | |
| 58 | -var $GlyphClassMarks; // mPDF 5.7.1 | |
| 59 | -var $GlyphClassLigatures; // mPDF 5.7.1 | |
| 60 | -var $GlyphClassBases; // mPDF 5.7.1 | |
| 61 | -var $GlyphClassComponents; // mPDF 5.7.1 | |
| 62 | -var $GSUBScriptLang; // mPDF 5.7.1 | |
| 63 | -var $rtlPUAstr; // mPDF 5.7.1 | |
| 64 | -//var $rtlPUAarr; // mPDF 5.7.1 | |
| 65 | -var $fontkey; // mPDF 5.7.1 | |
| 66 | -var $useOTL; // mPDF 5.7.1 | |
| 41 | +var $unAGlyphs; // mPDF 5.4.05 | |
| 67 | 42 | var $panose; |
| 68 | 43 | var $maxUni; |
| 69 | 44 | var $sFamilyClass; |
| 70 | 45 | var $sFamilySubClass; |
| @@ -82,20 +57,8 @@ | ||
| 82 | 57 | var $glyphPos; |
| 83 | 58 | var $charToGlyph; |
| 84 | 59 | var $ascent; |
| 85 | 60 | var $descent; |
| 86 | -var $lineGap; // mPDF 6 | |
| 87 | -var $hheaascent; | |
| 88 | -var $hheadescent; | |
| 89 | -var $hhealineGap; // mPDF 6 | |
| 90 | -var $advanceWidthMax; // mPDF 6 | |
| 91 | -var $typoAscender; // mPDF 6 | |
| 92 | -var $typoDescender; // mPDF 6 | |
| 93 | -var $typoLineGap; // mPDF 6 | |
| 94 | -var $usWinAscent; // mPDF 6 | |
| 95 | -var $usWinDescent; // mPDF 6 | |
| 96 | -var $strikeoutSize; | |
| 97 | -var $strikeoutPosition; | |
| 98 | 61 | var $name; |
| 99 | 62 | var $familyName; |
| 100 | 63 | var $styleName; |
| 101 | 64 | var $fullName; |
| @@ -102,9 +65,8 @@ | ||
| 102 | 65 | var $uniqueFontID; |
| 103 | 66 | var $unitsPerEm; |
| 104 | 67 | var $bbox; |
| 105 | 68 | var $capHeight; |
| 106 | -var $xHeight; // mPDF 6 | |
| 107 | 69 | var $stemV; |
| 108 | 70 | var $italicAngle; |
| 109 | 71 | var $flags; |
| 110 | 72 | var $underlinePosition; |
| @@ -115,10 +77,8 @@ | ||
| 115 | 77 | var $numTTCFonts; |
| 116 | 78 | var $TTCFonts; |
| 117 | 79 | var $maxUniChar; |
| 118 | 80 | var $kerninfo; |
| 119 | -var $haskernGPOS; | |
| 120 | -var $hassmallcapsGSUB; | |
| 121 | 81 | |
| 122 | 82 | function TTFontFile() { |
| 123 | 83 | $this->maxStrLenRead = 200000; // Maximum size of glyf table to read in as string (otherwise reads each glyph from file) |
| 124 | 84 | } |
| @@ -123,11 +83,10 @@ | ||
| 123 | 83 | $this->maxStrLenRead = 200000; // Maximum size of glyf table to read in as string (otherwise reads each glyph from file) |
| 124 | 84 | } |
| 125 | 85 | |
| 126 | 86 | |
| 127 | - function getMetrics($file, $fontkey, $TTCfontID=0, $debug=false, $BMPonly=false, $useOTL=0) { // mPDF 5.7.1 | |
| 128 | - $this->useOTL = $useOTL; // mPDF 5.7.1 | |
| 129 | - $this->fontkey = $fontkey; // mPDF 5.7.1 | |
| 87 | + function getMetrics($file, $TTCfontID=0, $debug=false, $BMPonly=false, $kerninfo=false, $unAGlyphs=false) { // mPDF 5.4.05 | |
| 88 | + $this->unAGlyphs = $unAGlyphs; // mPDF 5.4.05 | |
| 130 | 89 | $this->filename = $file; |
| 131 | 90 | $this->fh = fopen($file,'rb') or die('Can\'t open file ' . $file); |
| 132 | 91 | $this->_pos = 0; |
| 133 | 92 | $this->charWidths = ''; |
| @@ -135,29 +94,10 @@ | ||
| 135 | 94 | $this->charToGlyph = array(); |
| 136 | 95 | $this->tables = array(); |
| 137 | 96 | $this->otables = array(); |
| 138 | 97 | $this->kerninfo = array(); |
| 139 | - $this->haskernGPOS = array(); | |
| 140 | - $this->hassmallcapsGSUB = array(); | |
| 141 | 98 | $this->ascent = 0; |
| 142 | 99 | $this->descent = 0; |
| 143 | - $this->lineGap = 0; // mPDF 6 | |
| 144 | - $this->hheaascent = 0; // mPDF 6 | |
| 145 | - $this->hheadescent = 0; // mPDF 6 | |
| 146 | - $this->hhealineGap = 0; // mPDF 6 | |
| 147 | - $this->xHeight = 0; // mPDF 6 | |
| 148 | - $this->capHeight = 0; // mPDF 6 | |
| 149 | - $this->panose = array(); | |
| 150 | - $this->sFamilyClass = 0; | |
| 151 | - $this->sFamilySubClass = 0; | |
| 152 | - $this->typoAscender = 0; // mPDF 6 | |
| 153 | - $this->typoDescender = 0; // mPDF 6 | |
| 154 | - $this->typoLineGap = 0; // mPDF 6 | |
| 155 | - $this->usWinAscent = 0; // mPDF 6 | |
| 156 | - $this->usWinDescent = 0; // mPDF 6 | |
| 157 | - $this->advanceWidthMax = 0; // mPDF 6 | |
| 158 | - $this->strikeoutSize = 0; | |
| 159 | - $this->strikeoutPosition = 0; | |
| 160 | 100 | $this->numTTCFonts = 0; |
| 161 | 101 | $this->TTCFonts = array(); |
| 162 | 102 | $this->version = $version = $this->read_ulong(); |
| 163 | 103 | $this->panose = array(); |
| @@ -178,9 +118,9 @@ | ||
| 178 | 118 | $this->seek($this->TTCFonts[$TTCfontID]['offset']); |
| 179 | 119 | $this->version = $version = $this->read_ulong(); // TTFont version again now |
| 180 | 120 | } |
| 181 | 121 | $this->readTableDirectory($debug); |
| 182 | - $this->extractInfo($debug, $BMPonly, $useOTL); | |
| 122 | + $this->extractInfo($debug, $BMPonly, $kerninfo); | |
| 183 | 123 | fclose($this->fh); |
| 184 | 124 | } |
| 185 | 125 | |
| 186 | 126 | |
| @@ -243,14 +183,12 @@ | ||
| 243 | 183 | $lo += (ord($data[$i+2])<<8) + ord($data[$i+3]); |
| 244 | 184 | $hi += ($lo >> 16) & 0xFFFF; |
| 245 | 185 | $lo = $lo & 0xFFFF; |
| 246 | 186 | } |
| 247 | - $hi = $hi & 0xFFFF; // mPDF 5.7.1 | |
| 248 | 187 | return array($hi, $lo); |
| 249 | 188 | } |
| 250 | 189 | |
| 251 | 190 | function get_table_pos($tag) { |
| 252 | - if (!isset($this->tables[$tag])) { return array(0,0); } | |
| 253 | 191 | $offset = $this->tables[$tag]['offset']; |
| 254 | 192 | $length = $this->tables[$tag]['length']; |
| 255 | 193 | return array($offset, $length); |
| 256 | 194 | } |
| @@ -371,11 +309,10 @@ | ||
| 371 | 309 | |
| 372 | 310 | |
| 373 | 311 | |
| 374 | 312 | ///////////////////////////////////////////////////////////////////////////////////////// |
| 375 | - function getCTG($file, $TTCfontID=0, $debug=false, $useOTL=false) { // mPDF 5.7.1 | |
| 376 | - // Only called if font is not to be used as embedded subset i.e. NOT called for SIP/SMP fonts | |
| 377 | - $this->useOTL = $useOTL; // mPDF 5.7.1 | |
| 313 | + function getCTG($file, $TTCfontID=0, $debug=false, $unAGlyphs=false) { // mPDF 5.4.05 | |
| 314 | + $this->unAGlyphs = $unAGlyphs; // mPDF 5.4.05 | |
| 378 | 315 | $this->filename = $file; |
| 379 | 316 | $this->fh = fopen($file,'rb') or die('Can\'t open file ' . $file); |
| 380 | 317 | $this->_pos = 0; |
| 381 | 318 | $this->charWidths = ''; |
| @@ -429,30 +366,8 @@ | ||
| 429 | 366 | $glyphToChar = array(); |
| 430 | 367 | $charToGlyph = array(); |
| 431 | 368 | $this->getCMAP4($unicode_cmap_offset, $glyphToChar, $charToGlyph ); |
| 432 | 369 | |
| 433 | - /////////////////////////////////// | |
| 434 | - // mPDF 5.7.1 | |
| 435 | - // Map Unmapped glyphs - from $numGlyphs | |
| 436 | - if ($useOTL) { | |
| 437 | - $this->seek_table("maxp"); | |
| 438 | - $this->skip(4); | |
| 439 | - $numGlyphs = $this->read_ushort(); | |
| 440 | - $bctr = 0xE000; | |
| 441 | - for ($gid=1; $gid<$numGlyphs; $gid++) { | |
| 442 | - if (!isset($glyphToChar[$gid])) { | |
| 443 | - while(isset($charToGlyph[$bctr])) { $bctr++; } // Avoid overwriting a glyph already mapped in PUA | |
| 444 | - if ($bctr > 0xF8FF) { | |
| 445 | - die($file." : WARNING - Font cannot map all included glyphs into Private Use Area U+E000 - U+F8FF; cannot use useOTL on this font"); | |
| 446 | - } | |
| 447 | - $glyphToChar[$gid][] = $bctr; | |
| 448 | - $charToGlyph[$bctr] = $gid; | |
| 449 | - $bctr++; | |
| 450 | - } | |
| 451 | - } | |
| 452 | - } | |
| 453 | - /////////////////////////////////// | |
| 454 | - | |
| 455 | 370 | fclose($this->fh); |
| 456 | 371 | return ($charToGlyph); |
| 457 | 372 | } |
| 458 | 373 | |
| @@ -483,10 +398,12 @@ | ||
| 483 | 398 | ///////////////////////////////////////////////////////////////////////////////////////// |
| 484 | 399 | |
| 485 | 400 | ///////////////////////////////////////////////////////////////////////////////////////// |
| 486 | 401 | |
| 487 | - function extractInfo($debug=false, $BMPonly=false, $useOTL=0) { | |
| 488 | - // Values are all set to 0 or blank at start of getMetrics | |
| 402 | + function extractInfo($debug=false, $BMPonly=false, $kerninfo=false) { | |
| 403 | + $this->panose = array(); | |
| 404 | + $this->sFamilyClass = 0; | |
| 405 | + $this->sFamilySubClass = 0; | |
| 489 | 406 | /////////////////////////////////// |
| 490 | 407 | // name - Naming table |
| 491 | 408 | /////////////////////////////////// |
| 492 | 409 | $name_offset = $this->seek_table("name"); |
| @@ -543,24 +460,16 @@ | ||
| 543 | 460 | else |
| 544 | 461 | $psName = ''; |
| 545 | 462 | if (!$psName) |
| 546 | 463 | die("Could not find PostScript font name: ".$this->filename); |
| 547 | - // CHECK IF psName valid (PadaukBook contains illegal characters in Name ID 6 i.e. Postscript Name) | |
| 548 | - $psNameInvalid = false; | |
| 549 | - for ($i=0;$i<count($psName);$i++) { | |
| 464 | + if ($debug) { | |
| 465 | + for ($i=0;$i<count($psName);$i++) { | |
| 550 | 466 | $c = $psName[$i]; |
| 551 | 467 | $oc = ord($c); |
| 552 | - if ($oc>126 || strpos(' [](){}<>/%',$c)!==false) { | |
| 553 | - //die("psName=".$psName." contains invalid character ".$c." ie U+".ord(c)); | |
| 554 | - $psNameInvalid = true; | |
| 555 | - break; | |
| 556 | - } | |
| 468 | + if ($oc>126 || strpos(' [](){}<>/%',$c)!==false) | |
| 469 | + die("psName=".$psName." contains invalid character ".$c." ie U+".ord(c)); | |
| 470 | + } | |
| 557 | 471 | } |
| 558 | - | |
| 559 | - if ($psNameInvalid && $names[4]) | |
| 560 | - $psName = preg_replace('/ /','-',$names[4]); | |
| 561 | - | |
| 562 | - | |
| 563 | 472 | $this->name = $psName; |
| 564 | 473 | if ($names[1]) { $this->familyName = $names[1]; } else { $this->familyName = $psName; } |
| 565 | 474 | if ($names[2]) { $this->styleName = $names[2]; } else { $this->styleName = 'Regular'; } |
| 566 | 475 | if ($names[4]) { $this->fullName = $names[4]; } else { $this->fullName = $psName; } |
| @@ -565,9 +474,9 @@ | ||
| 565 | 474 | if ($names[2]) { $this->styleName = $names[2]; } else { $this->styleName = 'Regular'; } |
| 566 | 475 | if ($names[4]) { $this->fullName = $names[4]; } else { $this->fullName = $psName; } |
| 567 | 476 | if ($names[3]) { $this->uniqueFontID = $names[3]; } else { $this->uniqueFontID = $psName; } |
| 568 | 477 | |
| 569 | - if (!$psNameInvalid && $names[6]) { $this->fullName = $names[6]; } | |
| 478 | + if ($names[6]) { $this->fullName = $names[6]; } | |
| 570 | 479 | |
| 571 | 480 | /////////////////////////////////// |
| 572 | 481 | // head - Font header table |
| 573 | 482 | /////////////////////////////////// |
| @@ -595,9 +504,8 @@ | ||
| 595 | 504 | $yMin = $this->read_short(); |
| 596 | 505 | $xMax = $this->read_short(); |
| 597 | 506 | $yMax = $this->read_short(); |
| 598 | 507 | $this->bbox = array(($xMin*$scale), ($yMin*$scale), ($xMax*$scale), ($yMax*$scale)); |
| 599 | - | |
| 600 | 508 | $this->skip(3*2); |
| 601 | 509 | $indexToLocFormat = $this->read_ushort(); |
| 602 | 510 | $glyphDataFormat = $this->read_ushort(); |
| 603 | 511 | if ($glyphDataFormat != 0) |
| @@ -605,25 +513,21 @@ | ||
| 605 | 513 | |
| 606 | 514 | /////////////////////////////////// |
| 607 | 515 | // hhea metrics table |
| 608 | 516 | /////////////////////////////////// |
| 517 | + // ttf2t1 seems to use this value rather than the one in OS/2 - so put in for compatibility | |
| 609 | 518 | if (isset($this->tables["hhea"])) { |
| 610 | 519 | $this->seek_table("hhea"); |
| 611 | 520 | $this->skip(4); |
| 612 | 521 | $hheaAscender = $this->read_short(); |
| 613 | 522 | $hheaDescender = $this->read_short(); |
| 614 | - $hheaLineGap = $this->read_short(); // mPDF 6 | |
| 615 | - $hheaAdvanceWidthMax = $this->read_ushort(); // mPDF 6 | |
| 616 | - $this->hheaascent = ($hheaAscender *$scale); | |
| 617 | - $this->hheadescent = ($hheaDescender *$scale); | |
| 618 | - $this->hhealineGap = ($hheaLineGap * $scale); // mPDF 6 | |
| 619 | - $this->advanceWidthMax = ($hheaAdvanceWidthMax * $scale); // mPDF 6 | |
| 523 | + $this->ascent = ($hheaAscender *$scale); | |
| 524 | + $this->descent = ($hheaDescender *$scale); | |
| 620 | 525 | } |
| 621 | 526 | |
| 622 | 527 | /////////////////////////////////// |
| 623 | 528 | // OS/2 - OS/2 and Windows metrics table |
| 624 | 529 | /////////////////////////////////// |
| 625 | - $use_typo_metrics = false; | |
| 626 | 530 | if (isset($this->tables["OS/2"])) { |
| 627 | 531 | $this->seek_table("OS/2"); |
| 628 | 532 | $version = $this->read_ushort(); |
| 629 | 533 | $this->skip(2); |
| @@ -630,18 +534,13 @@ | ||
| 630 | 534 | $usWeightClass = $this->read_ushort(); |
| 631 | 535 | $this->skip(2); |
| 632 | 536 | $fsType = $this->read_ushort(); |
| 633 | 537 | if ($fsType == 0x0002 || ($fsType & 0x0300) != 0) { |
| 538 | + global $overrideTTFFontRestriction; | |
| 539 | + if (!$overrideTTFFontRestriction) die('ERROR - Font file '.$this->filename.' cannot be embedded due to copyright restrictions.'); | |
| 634 | 540 | $this->restrictedUse = true; |
| 635 | 541 | } |
| 636 | - | |
| 637 | - // mPDF 6 | |
| 638 | - $this->skip(16); | |
| 639 | - $yStrikeoutSize = $this->read_short(); | |
| 640 | - $yStrikeoutPosition = $this->read_short(); | |
| 641 | - $this->strikeoutSize = ($yStrikeoutSize*$scale); | |
| 642 | - $this->strikeoutPosition = ($yStrikeoutPosition*$scale); | |
| 643 | - | |
| 542 | + $this->skip(20); | |
| 644 | 543 | $sF = $this->read_short(); |
| 645 | 544 | $this->sFamilyClass = ($sF >> 8); |
| 646 | 545 | $this->sFamilySubClass = ($sF & 0xFF); |
| 647 | 546 | $this->_pos += 10; //PANOSE = 10 byte length |
| @@ -647,81 +546,30 @@ | ||
| 647 | 546 | $this->_pos += 10; //PANOSE = 10 byte length |
| 648 | 547 | $panose = fread($this->fh,10); |
| 649 | 548 | $this->panose = array(); |
| 650 | 549 | for ($p=0;$p<strlen($panose);$p++) { $this->panose[] = ord($panose[$p]); } |
| 651 | - //$this->skip(26); | |
| 652 | - // mPDF 6 | |
| 653 | - $this->skip(20); | |
| 654 | - $fsSelection = $this->read_ushort(); | |
| 655 | - $use_typo_metrics = (($fsSelection & 0x80) == 0x80); // bit#7 = USE_TYPO_METRICS | |
| 656 | - $this->skip(4); | |
| 657 | - | |
| 550 | + $this->skip(26); | |
| 658 | 551 | $sTypoAscender = $this->read_short(); |
| 659 | 552 | $sTypoDescender = $this->read_short(); |
| 660 | - $sTypoLineGap = $this->read_short(); // mPDF 6 | |
| 661 | - if ($sTypoAscender) $this->typoAscender = ($sTypoAscender*$scale); // mPDF 6 | |
| 662 | - if ($sTypoDescender) $this->typoDescender = ($sTypoDescender*$scale); // mPDF 6 | |
| 663 | - if ($sTypoLineGap ) $this->typoLineGap = ($sTypoLineGap * $scale); // mPDF 6 | |
| 664 | - | |
| 665 | - $usWinAscent = $this->read_ushort(); // mPDF 6 | |
| 666 | - $usWinDescent = $this->read_ushort(); // mPDF 6 | |
| 667 | - if ($usWinAscent) $this->usWinAscent = ($usWinAscent*$scale); // mPDF 6 | |
| 668 | - if ($usWinDescent) $this->usWinDescent = ($usWinDescent*$scale); // mPDF 6 | |
| 669 | - | |
| 553 | + if (!$this->ascent) $this->ascent = ($sTypoAscender*$scale); | |
| 554 | + if (!$this->descent) $this->descent = ($sTypoDescender*$scale); | |
| 670 | 555 | if ($version > 1) { |
| 671 | - $this->skip(8); // mPDF 6 | |
| 672 | - $sxHeight = $this->read_short(); | |
| 673 | - $this->xHeight = ($sxHeight*$scale); | |
| 556 | + $this->skip(16); | |
| 674 | 557 | $sCapHeight = $this->read_short(); |
| 675 | 558 | $this->capHeight = ($sCapHeight*$scale); |
| 676 | 559 | } |
| 560 | + else { | |
| 561 | + $this->capHeight = $this->ascent; | |
| 562 | + } | |
| 677 | 563 | } |
| 678 | 564 | else { |
| 679 | - $usWeightClass = 400; | |
| 565 | + $usWeightClass = 500; | |
| 566 | + if (!$this->ascent) $this->ascent = ($yMax*$scale); | |
| 567 | + if (!$this->descent) $this->descent = ($yMin*$scale); | |
| 568 | + $this->capHeight = $this->ascent; | |
| 680 | 569 | } |
| 681 | 570 | $this->stemV = 50 + intval(pow(($usWeightClass / 65.0),2)); |
| 682 | 571 | |
| 683 | - | |
| 684 | - // FONT DESCRIPTOR METRICS | |
| 685 | - if (_FONT_DESCRIPTOR == 'winTypo') { | |
| 686 | - $this->ascent = $this->typoAscender; | |
| 687 | - $this->descent = $this->typoDescender; | |
| 688 | - $this->lineGap = $this->typoLineGap; | |
| 689 | - } | |
| 690 | - else if (_FONT_DESCRIPTOR == 'mac') { | |
| 691 | - $this->ascent = $this->hheaascent; | |
| 692 | - $this->descent = $this->hheadescent; | |
| 693 | - $this->lineGap = $this->hhealineGap; | |
| 694 | - } | |
| 695 | - else { // if (_FONT_DESCRIPTOR == 'win') { // default | |
| 696 | - $this->ascent = $this->usWinAscent; | |
| 697 | - $this->descent = -$this->usWinDescent; | |
| 698 | - $this->lineGap = 0; | |
| 699 | - | |
| 700 | - /* Special case - if either the winAscent or winDescent are greater than the | |
| 701 | - font bounding box yMin yMax, then reduce them accordingly. | |
| 702 | - This works with Myanmar Text (Windows 8 version) to give a | |
| 703 | - line-height normal that is equivalent to that produced in browsers. | |
| 704 | - Also Khmer OS = compatible with MSWord, Wordpad and browser. */ | |
| 705 | - if ($this->ascent > $this->bbox[3]) { $this->ascent = $this->bbox[3]; } | |
| 706 | - if ($this->descent < $this->bbox[1]) { $this->descent = $this->bbox[1]; } | |
| 707 | - | |
| 708 | - | |
| 709 | - /* Override case - if the USE_TYPO_METRICS bit is set on OS/2 fsSelection | |
| 710 | - this is telling the font to use the sTypo values and not the usWinAscent values. | |
| 711 | - This works as a fix with Cambria Math to give a normal line-height; | |
| 712 | - at present, this is the only font I have found with this bit set; | |
| 713 | - although note that MS WordPad and windows FF browser uses the big line-height from winAscent | |
| 714 | - but Word 2007 get it right . */ | |
| 715 | - if ($use_typo_metrics && $this->typoAscender) { | |
| 716 | - $this->ascent = $this->typoAscender; | |
| 717 | - $this->descent = $this->typoDescender; | |
| 718 | - $this->lineGap = $this->typoLineGap; | |
| 719 | - } | |
| 720 | - | |
| 721 | - } | |
| 722 | - | |
| 723 | - | |
| 724 | 572 | /////////////////////////////////// |
| 725 | 573 | // post - PostScript table |
| 726 | 574 | /////////////////////////////////// |
| 727 | 575 | $this->seek_table("post"); |
| @@ -813,9 +661,8 @@ | ||
| 813 | 661 | } |
| 814 | 662 | } |
| 815 | 663 | $this->seek($save_pos ); |
| 816 | 664 | } |
| 817 | - | |
| 818 | 665 | if (!$unicode_cmap_offset) |
| 819 | 666 | die('Font ('.$this->filename .') does not have cmap for Unicode (platform 3, encoding 1, format 4, or platform 0, any encoding, format 4)'); |
| 820 | 667 | |
| 821 | 668 | |
| @@ -820,20 +667,8 @@ | ||
| 820 | 667 | |
| 821 | 668 | |
| 822 | 669 | $sipset = false; |
| 823 | 670 | $smpset = false; |
| 824 | - | |
| 825 | - // mPDF 5.7.1 | |
| 826 | - $this->rtlPUAstr = ''; | |
| 827 | - //$this->rtlPUAarr = array(); | |
| 828 | - $this->GSUBScriptLang = array(); | |
| 829 | - $this->GSUBFeatures = array(); | |
| 830 | - $this->GSUBLookups = array(); | |
| 831 | - $this->GPOSScriptLang = array(); | |
| 832 | - $this->GPOSFeatures = array(); | |
| 833 | - $this->GPOSLookups = array(); | |
| 834 | - $this->glyphIDtoUni = ''; | |
| 835 | - | |
| 836 | 671 | // Format 12 CMAP does characters above Unicode BMP i.e. some HKCS characters U+20000 and above |
| 837 | 672 | if ($format == 12 && !$BMPonly) { |
| 838 | 673 | $this->maxUniChar = 0; |
| 839 | 674 | $this->seek($unicode_cmap_offset + 4); |
| @@ -848,11 +683,10 @@ | ||
| 848 | 683 | for($i=0; $i<$nGroups ; $i++) { |
| 849 | 684 | $startCharCode = $this->read_ulong(); |
| 850 | 685 | $endCharCode = $this->read_ulong(); |
| 851 | 686 | $startGlyphCode = $this->read_ulong(); |
| 852 | - // ZZZ98 | |
| 853 | - if ($endCharCode > 0x20000 && $endCharCode < 0x2FFFF) { | |
| 854 | - $sipset = true; | |
| 687 | + if (($endCharCode > 0x20000 && $endCharCode < 0x2A6DF) || ($endCharCode > 0x2F800 && $endCharCode < 0x2FA1F)) { | |
| 688 | + $sipset = true; | |
| 855 | 689 | } |
| 856 | 690 | else if ($endCharCode > 0x10000 && $endCharCode < 0x1FFFF) { |
| 857 | 691 | $smpset = true; |
| 858 | 692 | } |
| @@ -859,14 +693,11 @@ | ||
| 859 | 693 | $offset = 0; |
| 860 | 694 | for ($unichar=$startCharCode;$unichar<=$endCharCode;$unichar++) { |
| 861 | 695 | $glyph = $startGlyphCode + $offset ; |
| 862 | 696 | $offset++; |
| 863 | - // ZZZ98 | |
| 864 | - if ($unichar < 0x30000) { | |
| 865 | - $charToGlyph[$unichar] = $glyph; | |
| 866 | - $this->maxUniChar = max($unichar,$this->maxUniChar); | |
| 867 | - $glyphToChar[$glyph][] = $unichar; | |
| 868 | - } | |
| 697 | + $charToGlyph[$unichar] = $glyph; | |
| 698 | + if ($unichar < 196608) { $this->maxUniChar = max($unichar,$this->maxUniChar); } | |
| 699 | + $glyphToChar[$glyph][] = $unichar; | |
| 869 | 700 | } |
| 870 | 701 | } |
| 871 | 702 | } |
| 872 | 703 | else { |
| @@ -877,106 +708,10 @@ | ||
| 877 | 708 | |
| 878 | 709 | } |
| 879 | 710 | $this->sipset = $sipset ; |
| 880 | 711 | $this->smpset = $smpset ; |
| 881 | - /////////////////////////////////// | |
| 882 | - // mPDF 5.7.1 | |
| 883 | - // Map Unmapped glyphs (or glyphs mapped to upper PUA U+F00000 onwards i.e. > U+2FFFF) - from $numGlyphs | |
| 884 | - if ($this->useOTL) { | |
| 885 | - $bctr = 0xE000; | |
| 886 | - for ($gid=1; $gid<$numGlyphs; $gid++) { | |
| 887 | - if (!isset($glyphToChar[$gid])) { | |
| 888 | - while(isset($charToGlyph[$bctr])) { $bctr++; } // Avoid overwriting a glyph already mapped in PUA | |
| 889 | - // ZZZ98 | |
| 890 | - if (($bctr > 0xF8FF) && ($bctr < 0x2CEB0)) { | |
| 891 | - if (!$BMPonly) { | |
| 892 | - $bctr = 0x2CEB0; // Use unassigned area 0x2CEB0 to 0x2F7FF (space for 10,000 characters) | |
| 893 | - $this->sipset = $sipset = true; // forces subsetting; also ensure charwidths are saved | |
| 894 | - while(isset($charToGlyph[$bctr])) { $bctr++; } | |
| 895 | - } | |
| 896 | - else { die($names[1]." : WARNING - The font does not have enough space to map all (unmapped) included glyphs into Private Use Area U+E000 - U+F8FF"); } | |
| 897 | - } | |
| 898 | - $glyphToChar[$gid][] = $bctr; | |
| 899 | - $charToGlyph[$bctr] = $gid; | |
| 900 | - $this->maxUniChar = max($bctr,$this->maxUniChar); | |
| 901 | - $bctr++; | |
| 902 | - } | |
| 903 | - } | |
| 904 | - } | |
| 905 | 712 | |
| 906 | - $this->glyphToChar = $glyphToChar; | |
| 907 | 713 | /////////////////////////////////// |
| 908 | - // mPDF 5.7.1 OpenType Layout tables | |
| 909 | - $this->GSUBScriptLang=array(); | |
| 910 | - $this->rtlPUAstr = ''; | |
| 911 | - //$this->rtlPUAarr = array(); | |
| 912 | - if ($useOTL) { | |
| 913 | - $this->_getGDEFtables(); | |
| 914 | - list($this->GSUBScriptLang, $this->GSUBFeatures, $this->GSUBLookups, $this->rtlPUAstr) = $this->_getGSUBtables(); | |
| 915 | - // , $this->rtlPUAarr not needed | |
| 916 | - list($this->GPOSScriptLang, $this->GPOSFeatures, $this->GPOSLookups) = $this->_getGPOStables(); | |
| 917 | - $this->glyphIDtoUni = str_pad('', 256*256*3, "\x00"); | |
| 918 | - foreach($glyphToChar AS $gid=>$arr) { | |
| 919 | - if (isset($glyphToChar[$gid][0])) { | |
| 920 | - $char = $glyphToChar[$gid][0]; | |
| 921 | - | |
| 922 | - if ($char != 0 && $char != 65535) { | |
| 923 | - $this->glyphIDtoUni[$gid*3] = chr($char >> 16); | |
| 924 | - $this->glyphIDtoUni[$gid*3 + 1] = chr(($char >> 8) & 0xFF); | |
| 925 | - $this->glyphIDtoUni[$gid*3 + 2] = chr($char & 0xFF); | |
| 926 | - } | |
| 927 | - } | |
| 928 | - } | |
| 929 | - } | |
| 930 | - /////////////////////////////////// | |
| 931 | - | |
| 932 | - | |
| 933 | - // if xHeight and/or CapHeight are not available from OS/2 (e.g. eraly versions) | |
| 934 | - // Calculate from yMax of 'x' or 'H' Glyphs... | |
| 935 | - if ($this->xHeight == 0) { | |
| 936 | - if (isset($charToGlyph[0x78])) { | |
| 937 | - $gidx = $charToGlyph[0x78]; // U+0078 (LATIN SMALL LETTER X) | |
| 938 | - $start = $this->seek_table('loca'); | |
| 939 | - if ($indexToLocFormat == 0) { | |
| 940 | - $this->skip($gidx*2); | |
| 941 | - $locax = $this->read_ushort() * 2; | |
| 942 | - } | |
| 943 | - else if ($indexToLocFormat == 1) { | |
| 944 | - $this->skip($gidx*4); | |
| 945 | - $locax = $this->read_ulong(); | |
| 946 | - } | |
| 947 | - $start = $this->seek_table('glyf'); | |
| 948 | - $this->skip($locax); | |
| 949 | - $this->skip(8); | |
| 950 | - $yMaxx = $this->read_short(); | |
| 951 | - $this->xHeight = $yMaxx * $scale; | |
| 952 | - } | |
| 953 | - } | |
| 954 | - if ($this->capHeight == 0) { | |
| 955 | - if (isset($charToGlyph[0x48])) { | |
| 956 | - $gidH = $charToGlyph[0x48]; // U+0048 (LATIN CAPITAL LETTER H) | |
| 957 | - $start = $this->seek_table('loca'); | |
| 958 | - if ($indexToLocFormat == 0) { | |
| 959 | - $this->skip($gidH*2); | |
| 960 | - $locaH = $this->read_ushort() * 2; | |
| 961 | - } | |
| 962 | - else if ($indexToLocFormat == 1) { | |
| 963 | - $this->skip($gidH*4); | |
| 964 | - $locaH = $this->read_ulong(); | |
| 965 | - } | |
| 966 | - $start = $this->seek_table('glyf'); | |
| 967 | - $this->skip($locaH); | |
| 968 | - $this->skip(8); | |
| 969 | - $yMaxH = $this->read_short(); | |
| 970 | - $this->capHeight = $yMaxH * $scale; | |
| 971 | - } | |
| 972 | - else { $this->capHeight = $this->ascent; } // final default is to set it = to Ascent | |
| 973 | - } | |
| 974 | - | |
| 975 | - | |
| 976 | - | |
| 977 | - | |
| 978 | - /////////////////////////////////// | |
| 979 | 714 | // hmtx - Horizontal metrics table |
| 980 | 715 | /////////////////////////////////// |
| 981 | 716 | $this->getHMTX($numberOfHMetrics, $numGlyphs, $glyphToChar, $scale); |
| 982 | 717 | |
| @@ -982,2298 +717,42 @@ | ||
| 982 | 717 | |
| 983 | 718 | /////////////////////////////////// |
| 984 | 719 | // kern - Kerning pair table |
| 985 | 720 | /////////////////////////////////// |
| 986 | - // Recognises old form of Kerning table - as required by Windows - Format 0 only | |
| 987 | - $kern_offset = $this->seek_table("kern"); | |
| 988 | - $version = $this->read_ushort(); | |
| 989 | - $nTables = $this->read_ushort(); | |
| 990 | - // subtable header | |
| 991 | - $sversion = $this->read_ushort(); | |
| 992 | - $slength = $this->read_ushort(); | |
| 993 | - $scoverage = $this->read_ushort(); | |
| 994 | - $format = $scoverage >> 8; | |
| 995 | - if ($kern_offset && $version==0 && $format==0) { | |
| 996 | - // Format 0 | |
| 997 | - $nPairs = $this->read_ushort(); | |
| 998 | - $this->skip(6); | |
| 999 | - for ($i=0; $i<$nPairs; $i++) { | |
| 1000 | - $left = $this->read_ushort(); | |
| 1001 | - $right = $this->read_ushort(); | |
| 1002 | - $val = $this->read_short(); | |
| 1003 | - if (count($glyphToChar[$left])==1 && count($glyphToChar[$right])==1) { | |
| 1004 | - if ($left != 32 && $right != 32) { | |
| 1005 | - $this->kerninfo[$glyphToChar[$left][0]][$glyphToChar[$right][0]] = intval($val*$scale); | |
| 1006 | - } | |
| 1007 | - } | |
| 1008 | - } | |
| 1009 | - } | |
| 1010 | - } | |
| 1011 | - | |
| 1012 | - | |
| 1013 | -///////////////////////////////////////////////////////////////////////////////////////// | |
| 1014 | - function _getGDEFtables() { | |
| 1015 | - /////////////////////////////////// | |
| 1016 | - // GDEF - Glyph Definition | |
| 1017 | - /////////////////////////////////// | |
| 1018 | - // http://www.microsoft.com/typography/otspec/gdef.htm | |
| 1019 | - if (isset($this->tables["GDEF"])) { | |
| 1020 | - $gdef_offset = $this->seek_table("GDEF"); | |
| 1021 | - // ULONG Version of the GDEF table-currently 0x00010000 | |
| 1022 | - $ver_maj = $this->read_ushort(); | |
| 1023 | - $ver_min = $this->read_ushort(); | |
| 1024 | - $GlyphClassDef_offset = $this->read_ushort(); | |
| 1025 | - $AttachList_offset = $this->read_ushort(); | |
| 1026 | - $LigCaretList_offset = $this->read_ushort(); | |
| 1027 | - $MarkAttachClassDef_offset = $this->read_ushort(); | |
| 1028 | - // Version 0x00010002 of GDEF header contains additional Offset to a list defining mark glyph set definitions (MarkGlyphSetDef) | |
| 1029 | - if ($ver_min == 2) { | |
| 1030 | - $MarkGlyphSetsDef_offset = $this->read_ushort(); | |
| 1031 | - } | |
| 1032 | - | |
| 1033 | - // GlyphClassDef | |
| 1034 | - if ($GlyphClassDef_offset) { | |
| 1035 | - $this->seek($gdef_offset+$GlyphClassDef_offset ); | |
| 1036 | - /* | |
| 1037 | - 1 Base glyph (single character, spacing glyph) | |
| 1038 | - 2 Ligature glyph (multiple character, spacing glyph) | |
| 1039 | - 3 Mark glyph (non-spacing combining glyph) | |
| 1040 | - 4 Component glyph (part of single character, spacing glyph) | |
| 1041 | - */ | |
| 1042 | - $GlyphByClass = $this->_getClassDefinitionTable(); | |
| 1043 | - } | |
| 1044 | - else { $GlyphByClass = array(); } | |
| 1045 | - | |
| 1046 | - if (isset($GlyphByClass[1]) && count($GlyphByClass[1])>0) { $this->GlyphClassBases = ' '.implode('| ',$GlyphByClass[1]); } | |
| 1047 | - else { $this->GlyphClassBases = ''; } | |
| 1048 | - if (isset($GlyphByClass[2]) && count($GlyphByClass[2])>0) { $this->GlyphClassLigatures = ' '.implode('| ',$GlyphByClass[2]); } | |
| 1049 | - else { $this->GlyphClassLigatures = ''; } | |
| 1050 | - if (isset($GlyphByClass[3]) && count($GlyphByClass[3])>0) { $this->GlyphClassMarks = ' '.implode('| ',$GlyphByClass[3]); } | |
| 1051 | - else { $this->GlyphClassMarks = ''; } | |
| 1052 | - if (isset($GlyphByClass[4]) && count($GlyphByClass[4])>0) { $this->GlyphClassComponents = ' '.implode('| ',$GlyphByClass[4]); } | |
| 1053 | - else { $this->GlyphClassComponents = ''; } | |
| 1054 | - | |
| 1055 | - if (isset($GlyphByClass[3]) && count($GlyphByClass[3])>0) { $Marks = $GlyphByClass[3]; } // to use for MarkAttachmentType | |
| 1056 | - else { $Marks = array(); } | |
| 1057 | - | |
| 1058 | - | |
| 1059 | - | |
| 1060 | -/* Required for GPOS | |
| 1061 | - // Attachment List | |
| 1062 | - if ($AttachList_offset) { | |
| 1063 | - $this->seek($gdef_offset+$AttachList_offset ); | |
| 1064 | - } | |
| 1065 | -The Attachment Point List table (AttachmentList) identifies all the attachment points defined in the GPOS table and their associated glyphs so a client can quickly access coordinates for each glyph's attachment points. As a result, the client can cache coordinates for attachment points along with glyph bitmaps and avoid recalculating the attachment points each time it displays a glyph. Without this table, processing speed would be slower because the client would have to decode the GPOS lookups that define attachment points and compile the points in a list. | |
| 1066 | - | |
| 1067 | -The Attachment List table (AttachList) may be used to cache attachment point coordinates along with glyph bitmaps. | |
| 1068 | - | |
| 1069 | -The table consists of an offset to a Coverage table (Coverage) listing all glyphs that define attachment points in the GPOS table, a count of the glyphs with attachment points (GlyphCount), and an array of offsets to AttachPoint tables (AttachPoint). The array lists the AttachPoint tables, one for each glyph in the Coverage table, in the same order as the Coverage Index. | |
| 1070 | -AttachList table | |
| 1071 | -Type Name Description | |
| 1072 | -Offset Coverage Offset to Coverage table - from beginning of AttachList table | |
| 1073 | -uint16 GlyphCount Number of glyphs with attachment points | |
| 1074 | -Offset AttachPoint[GlyphCount] Array of offsets to AttachPoint tables-from beginning of AttachList table-in Coverage Index order | |
| 1075 | - | |
| 1076 | -An AttachPoint table consists of a count of the attachment points on a single glyph (PointCount) and an array of contour indices of those points (PointIndex), listed in increasing numerical order. | |
| 1077 | - | |
| 1078 | -AttachPoint table | |
| 1079 | -Type Name Description | |
| 1080 | -uint16 PointCount Number of attachment points on this glyph | |
| 1081 | -uint16 PointIndex[PointCount] Array of contour point indices -in increasing numerical order | |
| 1082 | - | |
| 1083 | -See Example 3 - http://www.microsoft.com/typography/otspec/gdef.htm | |
| 1084 | -*/ | |
| 1085 | - | |
| 1086 | - | |
| 1087 | - // Ligature Caret List | |
| 1088 | - // The Ligature Caret List table (LigCaretList) defines caret positions for all the ligatures in a font. | |
| 1089 | - // Not required for mDPF | |
| 1090 | - | |
| 1091 | - | |
| 1092 | - // MarkAttachmentType | |
| 1093 | - if ($MarkAttachClassDef_offset) { | |
| 1094 | - $this->seek($gdef_offset+$MarkAttachClassDef_offset); | |
| 1095 | - $MarkAttachmentTypes = $this->_getClassDefinitionTable(); | |
| 1096 | - foreach($MarkAttachmentTypes AS $class=>$glyphs) { | |
| 1097 | - | |
| 1098 | - if (is_array($Marks) && count($Marks)) { | |
| 1099 | - $mat = array_diff($Marks, $MarkAttachmentTypes[$class]); | |
| 1100 | - sort($mat, SORT_STRING); | |
| 721 | + if ($kerninfo) { | |
| 722 | + // Recognises old form of Kerning table - as required by Windows - Format 0 only | |
| 723 | + $kern_offset = $this->seek_table("kern"); | |
| 724 | + $version = $this->read_ushort(); | |
| 725 | + $nTables = $this->read_ushort(); | |
| 726 | + // subtable header | |
| 727 | + $sversion = $this->read_ushort(); | |
| 728 | + $slength = $this->read_ushort(); | |
| 729 | + $scoverage = $this->read_ushort(); | |
| 730 | + $format = $scoverage >> 8; | |
| 731 | + if ($kern_offset && $version==0 && $format==0) { | |
| 732 | + // Format 0 | |
| 733 | + $nPairs = $this->read_ushort(); | |
| 734 | + $this->skip(6); | |
| 735 | + for ($i=0; $i<$nPairs; $i++) { | |
| 736 | + $left = $this->read_ushort(); | |
| 737 | + $right = $this->read_ushort(); | |
| 738 | + $val = $this->read_short(); | |
| 739 | + if (count($glyphToChar[$left])==1 && count($glyphToChar[$right])==1) { | |
| 740 | + if ($left != 32 && $right != 32) { | |
| 741 | + $this->kerninfo[$glyphToChar[$left][0]][$glyphToChar[$right][0]] = intval($val*$scale); | |
| 742 | + } | |
| 1101 | 743 | } |
| 1102 | - else { $mat = array(); } | |
| 1103 | - | |
| 1104 | - $this->MarkAttachmentType[$class] = ' '.implode('| ',$mat); | |
| 1105 | 744 | } |
| 1106 | 745 | } |
| 1107 | - else { $this->MarkAttachmentType = array(); } | |
| 1108 | - | |
| 1109 | - | |
| 1110 | - // MarkGlyphSets only in Version 0x00010002 of GDEF | |
| 1111 | - if ($ver_min == 2 && $MarkGlyphSetsDef_offset) { | |
| 1112 | - $this->seek($gdef_offset+$MarkGlyphSetsDef_offset); | |
| 1113 | - $MarkSetTableFormat = $this->read_ushort(); | |
| 1114 | - $MarkSetCount = $this->read_ushort(); | |
| 1115 | - $MarkSetOffset = array(); | |
| 1116 | - for ($i=0;$i<$MarkSetCount;$i++) { | |
| 1117 | - $MarkSetOffset[] = $this->read_ulong(); | |
| 1118 | - } | |
| 1119 | - for ($i=0;$i<$MarkSetCount;$i++) { | |
| 1120 | - $this->seek($MarkSetOffset[$i]); | |
| 1121 | - $glyphs = $this->_getCoverage(); | |
| 1122 | - $this->MarkGlyphSets[$i] = ' '.implode('| ',$glyphs); | |
| 1123 | - } | |
| 1124 | - } | |
| 1125 | - else { $this->MarkGlyphSets = array(); } | |
| 1126 | 746 | } |
| 1127 | - else { die('Warning - You cannot set this font ('.$this->filename.') to use OTL, as it does not include OTL tables (or at least, not a GDEF table).'); } | |
| 1128 | - | |
| 1129 | - //===================================================================================== | |
| 1130 | - //===================================================================================== | |
| 1131 | - //===================================================================================== | |
| 1132 | - $GSUB_offset = 0; | |
| 1133 | - $GPOS_offset = 0; | |
| 1134 | - $GSUB_length = 0; | |
| 1135 | - $s = ''; | |
| 1136 | - if (isset($this->tables["GSUB"])) { | |
| 1137 | - $GSUB_offset = $this->seek_table("GSUB"); | |
| 1138 | - $GSUB_length = $this->tables["GSUB"]['length']; | |
| 1139 | - $s .= fread($this->fh,$this->tables["GSUB"]['length']); | |
| 1140 | - } | |
| 1141 | - if (isset($this->tables["GPOS"])) { | |
| 1142 | - $GPOS_offset = $this->seek_table("GPOS"); | |
| 1143 | - $s .= fread($this->fh,$this->tables["GPOS"]['length']); | |
| 1144 | - } | |
| 1145 | - if ($s) file_put_contents(_MPDF_TTFONTDATAPATH.$this->fontkey.'.GSUBGPOStables.dat', $s); | |
| 1146 | - | |
| 1147 | - //===================================================================================== | |
| 1148 | - //===================================================================================== | |
| 1149 | - | |
| 1150 | - $s = '<?php | |
| 1151 | -$GSUB_offset = '.$GSUB_offset.'; | |
| 1152 | -$GPOS_offset = '.$GPOS_offset.'; | |
| 1153 | -$GSUB_length = '.$GSUB_length.'; | |
| 1154 | -$GlyphClassBases = \''.$this->GlyphClassBases.'\'; | |
| 1155 | -$GlyphClassMarks = \''.$this->GlyphClassMarks.'\'; | |
| 1156 | -$GlyphClassLigatures = \''.$this->GlyphClassLigatures.'\'; | |
| 1157 | -$GlyphClassComponents = \''.$this->GlyphClassComponents.'\'; | |
| 1158 | -$MarkGlyphSets = '.var_export($this->MarkGlyphSets , true).'; | |
| 1159 | -$MarkAttachmentType = '.var_export($this->MarkAttachmentType , true).'; | |
| 1160 | -?>'; | |
| 1161 | - | |
| 1162 | - | |
| 1163 | - file_put_contents(_MPDF_TTFONTDATAPATH.$this->fontkey.'.GDEFdata.php', $s); | |
| 1164 | - | |
| 1165 | - //===================================================================================== | |
| 1166 | - | |
| 1167 | - | |
| 1168 | -//echo $this->GlyphClassMarks ; exit; | |
| 1169 | -//print_r($GlyphClass); exit; | |
| 1170 | -//print_r($GlyphByClass); exit; | |
| 1171 | 747 | } |
| 1172 | 748 | |
| 1173 | - function _getClassDefinitionTable() { | |
| 1174 | 749 | |
| 1175 | - // NB Any glyph not included in the range of covered GlyphIDs automatically belongs to Class 0. This is not returned by this function | |
| 1176 | - $ClassFormat = $this->read_ushort(); | |
| 1177 | - $GlyphByClass = array(); | |
| 1178 | - if ($ClassFormat == 1) { | |
| 1179 | - $StartGlyph = $this->read_ushort(); | |
| 1180 | - $GlyphCount = $this->read_ushort(); | |
| 1181 | - for ($i=0;$i<$GlyphCount;$i++) { | |
| 1182 | - $gid = $StartGlyph + $i; | |
| 1183 | - $class = $this->read_ushort(); | |
| 1184 | - // Several fonts (mainly dejavu.../Freeserif etc) have a MarkAttachClassDef Format 1, where StartGlyph is 0 and GlyphCount is 1 | |
| 1185 | - // This doesn't seem to do anything useful? | |
| 1186 | - // Freeserif does not have $this->glyphToChar[0] allocated and would throw an error, so check if isset: | |
| 1187 | - if (isset($this->glyphToChar[$gid][0])) { | |
| 1188 | - $GlyphByClass[$class][] = unicode_hex($this->glyphToChar[$gid][0]); | |
| 1189 | - } | |
| 1190 | - } | |
| 1191 | - } | |
| 1192 | - else if ($ClassFormat == 2) { | |
| 1193 | - $tableCount = $this->read_ushort(); | |
| 1194 | - for ($i=0;$i<$tableCount;$i++) { | |
| 1195 | - $startGlyphID = $this->read_ushort(); | |
| 1196 | - $endGlyphID = $this->read_ushort(); | |
| 1197 | - $class = $this->read_ushort(); | |
| 1198 | - for($gid=$startGlyphID;$gid<=$endGlyphID;$gid++) { | |
| 1199 | - if (isset($this->glyphToChar[$gid][0])) { | |
| 1200 | - $GlyphByClass[$class][] = unicode_hex($this->glyphToChar[$gid][0]); | |
| 1201 | - } | |
| 1202 | - } | |
| 1203 | - } | |
| 1204 | - } | |
| 1205 | - foreach($GlyphByClass AS $class=>$glyphs) { | |
| 1206 | - sort($GlyphByClass[$class], SORT_STRING); // SORT makes it easier to read in development ? order not important ??? | |
| 1207 | - } | |
| 1208 | - ksort($GlyphByClass); | |
| 1209 | - return $GlyphByClass; | |
| 1210 | - } | |
| 1211 | - | |
| 1212 | - function _getGSUBtables() { | |
| 1213 | - /////////////////////////////////// | |
| 1214 | - // GSUB - Glyph Substitution | |
| 1215 | - /////////////////////////////////// | |
| 1216 | - if (isset($this->tables["GSUB"])) { | |
| 1217 | - $ffeats = array(); | |
| 1218 | - $gsub_offset = $this->seek_table("GSUB"); | |
| 1219 | - $this->skip(4); | |
| 1220 | - $ScriptList_offset = $gsub_offset + $this->read_ushort(); | |
| 1221 | - $FeatureList_offset = $gsub_offset + $this->read_ushort(); | |
| 1222 | - $LookupList_offset = $gsub_offset + $this->read_ushort(); | |
| 1223 | - | |
| 1224 | - // ScriptList | |
| 1225 | - $this->seek($ScriptList_offset ); | |
| 1226 | - $ScriptCount = $this->read_ushort(); | |
| 1227 | - for ($i=0;$i<$ScriptCount;$i++) { | |
| 1228 | - $ScriptTag = $this->read_tag(); // = "beng", "deva" etc. | |
| 1229 | - $ScriptTableOffset = $this->read_ushort(); | |
| 1230 | - $ffeats[$ScriptTag] = $ScriptList_offset + $ScriptTableOffset; | |
| 1231 | - } | |
| 1232 | - | |
| 1233 | - // Script Table | |
| 1234 | - foreach($ffeats AS $t=>$o) { | |
| 1235 | - $ls = array(); | |
| 1236 | - $this->seek($o); | |
| 1237 | - $DefLangSys_offset = $this->read_ushort(); | |
| 1238 | - if ($DefLangSys_offset > 0) { | |
| 1239 | - $ls['DFLT'] = $DefLangSys_offset + $o; | |
| 1240 | - } | |
| 1241 | - $LangSysCount = $this->read_ushort(); | |
| 1242 | - for ($i=0;$i<$LangSysCount;$i++) { | |
| 1243 | - $LangTag = $this->read_tag(); // = | |
| 1244 | - $LangTableOffset = $this->read_ushort(); | |
| 1245 | - $ls[$LangTag] = $o + $LangTableOffset; | |
| 1246 | - } | |
| 1247 | - $ffeats[$t] = $ls; | |
| 1248 | - } | |
| 1249 | -//print_r($ffeats); exit; | |
| 1250 | - | |
| 1251 | - | |
| 1252 | - // Get FeatureIndexList | |
| 1253 | - // LangSys Table - from first listed langsys | |
| 1254 | - foreach($ffeats AS $st=>$scripts) { | |
| 1255 | - foreach($scripts AS $t=>$o) { | |
| 1256 | - $FeatureIndex = array(); | |
| 1257 | - $langsystable_offset = $o; | |
| 1258 | - $this->seek($langsystable_offset); | |
| 1259 | - $LookUpOrder = $this->read_ushort(); //==NULL | |
| 1260 | - $ReqFeatureIndex = $this->read_ushort(); | |
| 1261 | - if ($ReqFeatureIndex != 0xFFFF) { $FeatureIndex[] = $ReqFeatureIndex; } | |
| 1262 | - $FeatureCount = $this->read_ushort(); | |
| 1263 | - for ($i=0;$i<$FeatureCount;$i++) { | |
| 1264 | - $FeatureIndex[] = $this->read_ushort(); // = index of feature | |
| 1265 | - } | |
| 1266 | - $ffeats[$st][$t] = $FeatureIndex; | |
| 1267 | - } | |
| 1268 | - } | |
| 1269 | -//print_r($ffeats); exit; | |
| 1270 | - | |
| 1271 | - | |
| 1272 | - // Feauture List => LookupListIndex es | |
| 1273 | - $this->seek($FeatureList_offset ); | |
| 1274 | - $FeatureCount = $this->read_ushort(); | |
| 1275 | - $Feature = array(); | |
| 1276 | - for ($i=0;$i<$FeatureCount;$i++) { | |
| 1277 | - $tag = $this->read_tag() ; | |
| 1278 | - if ($tag == 'smcp') { $this->hassmallcapsGSUB = true; } | |
| 1279 | - $Feature[$i] = array('tag' => $tag); | |
| 1280 | - $Feature[$i]['offset'] = $FeatureList_offset + $this->read_ushort(); | |
| 1281 | - } | |
| 1282 | - for ($i=0;$i<$FeatureCount;$i++) { | |
| 1283 | - $this->seek($Feature[$i]['offset']); | |
| 1284 | - $this->read_ushort(); // null [FeatureParams] | |
| 1285 | - $Feature[$i]['LookupCount'] = $Lookupcount = $this->read_ushort(); | |
| 1286 | - $Feature[$i]['LookupListIndex'] = array(); | |
| 1287 | - for ($c=0;$c<$Lookupcount;$c++) { | |
| 1288 | - $Feature[$i]['LookupListIndex'][] = $this->read_ushort(); | |
| 1289 | - } | |
| 1290 | - } | |
| 1291 | - | |
| 1292 | -//print_r($Feature); exit; | |
| 1293 | - | |
| 1294 | - foreach($ffeats AS $st=>$scripts) { | |
| 1295 | - foreach($scripts AS $t=>$o) { | |
| 1296 | - $FeatureIndex = $ffeats[$st][$t]; | |
| 1297 | - foreach($FeatureIndex AS $k=>$fi) { | |
| 1298 | - $ffeats[$st][$t][$k] = $Feature[$fi]; | |
| 1299 | - } | |
| 1300 | - } | |
| 1301 | - } | |
| 1302 | - //===================================================================================== | |
| 1303 | - $gsub = array(); | |
| 1304 | - $GSUBScriptLang = array(); | |
| 1305 | - foreach($ffeats AS $st=>$scripts) { | |
| 1306 | - foreach($scripts AS $t=>$langsys) { | |
| 1307 | - $lg = array(); | |
| 1308 | - foreach($langsys AS $ft) { | |
| 1309 | - $lg[$ft['LookupListIndex'][0]] = $ft; | |
| 1310 | - } | |
| 1311 | - // list of Lookups in order they need to be run i.e. order listed in Lookup table | |
| 1312 | - ksort($lg); | |
| 1313 | - foreach($lg AS $ft) { | |
| 1314 | - $gsub[$st][$t][$ft['tag']] = $ft['LookupListIndex']; | |
| 1315 | - } | |
| 1316 | - if (!isset($GSUBScriptLang[$st])) { $GSUBScriptLang[$st] = ''; } | |
| 1317 | - $GSUBScriptLang[$st] .= $t.' '; | |
| 1318 | - } | |
| 1319 | - } | |
| 1320 | - | |
| 1321 | -//print_r($gsub); exit; | |
| 1322 | - | |
| 1323 | - | |
| 1324 | - | |
| 1325 | - //===================================================================================== | |
| 1326 | - // Get metadata and offsets for whole Lookup List table | |
| 1327 | - $this->seek($LookupList_offset ); | |
| 1328 | - $LookupCount = $this->read_ushort(); | |
| 1329 | - $GSLookup = array(); | |
| 1330 | - $Offsets = array(); | |
| 1331 | - $SubtableCount = array(); | |
| 1332 | - for ($i=0;$i<$LookupCount;$i++) { | |
| 1333 | - $Offsets[$i] = $LookupList_offset + $this->read_ushort(); | |
| 1334 | - } | |
| 1335 | - for ($i=0;$i<$LookupCount;$i++) { | |
| 1336 | - $this->seek($Offsets[$i]); | |
| 1337 | - $GSLookup[$i]['Type'] = $this->read_ushort(); | |
| 1338 | - $GSLookup[$i]['Flag'] = $flag = $this->read_ushort(); | |
| 1339 | - $GSLookup[$i]['SubtableCount'] = $SubtableCount[$i] = $this->read_ushort(); | |
| 1340 | - for ($c=0;$c<$SubtableCount[$i] ;$c++) { | |
| 1341 | - $GSLookup[$i]['Subtables'][$c] = $Offsets[$i] + $this->read_ushort(); | |
| 1342 | - | |
| 1343 | - } | |
| 1344 | - // MarkFilteringSet = Index (base 0) into GDEF mark glyph sets structure | |
| 1345 | - if (($flag & 0x0010) == 0x0010) { | |
| 1346 | - $GSLookup[$i]['MarkFilteringSet'] = $this->read_ushort(); | |
| 1347 | - } | |
| 1348 | - else { $GSLookup[$i]['MarkFilteringSet'] = ''; } | |
| 1349 | - | |
| 1350 | - // Lookup Type 7: Extension | |
| 1351 | - if ($GSLookup[$i]['Type'] == 7) { | |
| 1352 | - // Overwrites new offset (32-bit) for each subtable, and a new lookup Type | |
| 1353 | - for ($c=0;$c<$SubtableCount[$i] ;$c++) { | |
| 1354 | - $this->seek($GSLookup[$i]['Subtables'][$c]); | |
| 1355 | - $ExtensionPosFormat = $this->read_ushort(); | |
| 1356 | - $type = $this->read_ushort(); | |
| 1357 | - $ext_offset = $this->read_ulong(); | |
| 1358 | - $GSLookup[$i]['Subtables'][$c] = $GSLookup[$i]['Subtables'][$c] + $ext_offset; | |
| 1359 | - } | |
| 1360 | - $GSLookup[$i]['Type'] = $type; | |
| 1361 | - } | |
| 1362 | - } | |
| 1363 | - | |
| 1364 | -//print_r($GSLookup); exit; | |
| 1365 | - //===================================================================================== | |
| 1366 | - // Process Whole LookupList - Get LuCoverage = Lookup coverage just for first glyph | |
| 1367 | - $this->GSLuCoverage = array(); | |
| 1368 | - for ($i=0;$i<$LookupCount;$i++) { | |
| 1369 | - for ($c=0;$c<$GSLookup[$i]['SubtableCount'] ;$c++) { | |
| 1370 | - | |
| 1371 | - $this->seek($GSLookup[$i]['Subtables'][$c]); | |
| 1372 | - $PosFormat= $this->read_ushort(); | |
| 1373 | - | |
| 1374 | - if ($GSLookup[$i]['Type']==5 && $PosFormat==3) { $this->skip(4); } | |
| 1375 | - else if ($GSLookup[$i]['Type']==6 && $PosFormat==3) { | |
| 1376 | - $BacktrackGlyphCount= $this->read_ushort(); | |
| 1377 | - $this->skip(2*$BacktrackGlyphCount + 2); | |
| 1378 | - } | |
| 1379 | - // NB Coverage only looks at glyphs for position 1 (i.e. 5.3 and 6.3) // NEEDS TO READ ALL ******************** | |
| 1380 | - $Coverage = $GSLookup[$i]['Subtables'][$c] + $this->read_ushort(); | |
| 1381 | - $this->seek($Coverage); | |
| 1382 | - $glyphs = $this->_getCoverage(false,2); | |
| 1383 | - $this->GSLuCoverage[$i][$c] = $glyphs; | |
| 1384 | - } | |
| 1385 | - } | |
| 1386 | - | |
| 1387 | -// $this->GSLuCoverage and $GSLookup | |
| 1388 | - | |
| 1389 | - //===================================================================================== | |
| 1390 | - //===================================================================================== | |
| 1391 | - $s = '<?php | |
| 1392 | -$GSLuCoverage = '.var_export($this->GSLuCoverage , true).'; | |
| 1393 | -?>'; | |
| 1394 | - | |
| 1395 | - file_put_contents(_MPDF_TTFONTDATAPATH.$this->fontkey.'.GSUBdata.php', $s); | |
| 1396 | - | |
| 1397 | - //===================================================================================== | |
| 1398 | - //===================================================================================== | |
| 1399 | - //===================================================================================== | |
| 1400 | - //===================================================================================== | |
| 1401 | -// Now repeats as original to get Substitution rules | |
| 1402 | - //===================================================================================== | |
| 1403 | - //===================================================================================== | |
| 1404 | - //===================================================================================== | |
| 1405 | - // Get metadata and offsets for whole Lookup List table | |
| 1406 | - $this->seek($LookupList_offset ); | |
| 1407 | - $LookupCount = $this->read_ushort(); | |
| 1408 | - $Lookup = array(); | |
| 1409 | - for ($i=0;$i<$LookupCount;$i++) { | |
| 1410 | - $Lookup[$i]['offset'] = $LookupList_offset + $this->read_ushort(); | |
| 1411 | - } | |
| 1412 | - for ($i=0;$i<$LookupCount;$i++) { | |
| 1413 | - $this->seek($Lookup[$i]['offset']); | |
| 1414 | - $Lookup[$i]['Type'] = $this->read_ushort(); | |
| 1415 | - $Lookup[$i]['Flag'] = $flag = $this->read_ushort(); | |
| 1416 | - $Lookup[$i]['SubtableCount'] = $this->read_ushort(); | |
| 1417 | - for ($c=0;$c<$Lookup[$i]['SubtableCount'] ;$c++) { | |
| 1418 | - $Lookup[$i]['Subtable'][$c]['Offset'] = $Lookup[$i]['offset'] + $this->read_ushort(); | |
| 1419 | - | |
| 1420 | - } | |
| 1421 | - // MarkFilteringSet = Index (base 0) into GDEF mark glyph sets structure | |
| 1422 | - if (($flag & 0x0010) == 0x0010) { | |
| 1423 | - $Lookup[$i]['MarkFilteringSet'] = $this->read_ushort(); | |
| 1424 | - } | |
| 1425 | - else { $Lookup[$i]['MarkFilteringSet'] = ''; } | |
| 1426 | - | |
| 1427 | - // Lookup Type 7: Extension | |
| 1428 | - if ($Lookup[$i]['Type'] == 7) { | |
| 1429 | - // Overwrites new offset (32-bit) for each subtable, and a new lookup Type | |
| 1430 | - for ($c=0;$c<$Lookup[$i]['SubtableCount'] ;$c++) { | |
| 1431 | - $this->seek($Lookup[$i]['Subtable'][$c]['Offset']); | |
| 1432 | - $ExtensionPosFormat = $this->read_ushort(); | |
| 1433 | - $type = $this->read_ushort(); | |
| 1434 | - $Lookup[$i]['Subtable'][$c]['Offset'] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->read_ulong(); | |
| 1435 | - } | |
| 1436 | - $Lookup[$i]['Type'] = $type; | |
| 1437 | - } | |
| 1438 | - | |
| 1439 | - } | |
| 1440 | - | |
| 1441 | -//print_r($Lookup); exit; | |
| 1442 | - //===================================================================================== | |
| 1443 | - // Process (1) Whole LookupList | |
| 1444 | - for ($i=0;$i<$LookupCount;$i++) { | |
| 1445 | - for ($c=0;$c<$Lookup[$i]['SubtableCount'] ;$c++) { | |
| 1446 | - | |
| 1447 | - $this->seek($Lookup[$i]['Subtable'][$c]['Offset']); | |
| 1448 | - $SubstFormat= $this->read_ushort(); | |
| 1449 | - $Lookup[$i]['Subtable'][$c]['Format'] = $SubstFormat; | |
| 1450 | - | |
| 1451 | -/* | |
| 1452 | -Lookup['Type'] Enumeration table for glyph substitution | |
| 1453 | -Value Type Description | |
| 1454 | -1 Single Replace one glyph with one glyph | |
| 1455 | -2 Multiple Replace one glyph with more than one glyph | |
| 1456 | -3 Alternate Replace one glyph with one of many glyphs | |
| 1457 | -4 Ligature Replace multiple glyphs with one glyph | |
| 1458 | -5 Context Replace one or more glyphs in context | |
| 1459 | -6 Chaining Context Replace one or more glyphs in chained context | |
| 1460 | -7 Extension Substitution Extension mechanism for other substitutions (i.e. this excludes the Extension type substitution itself) | |
| 1461 | -8 Reverse chaining context single Applied in reverse order, replace single glyph in chaining context | |
| 1462 | -*/ | |
| 1463 | - | |
| 1464 | - // LookupType 1: Single Substitution Subtable | |
| 1465 | - if ($Lookup[$i]['Type'] == 1) { | |
| 1466 | - $Lookup[$i]['Subtable'][$c]['CoverageTableOffset'] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->read_ushort(); | |
| 1467 | - if ($SubstFormat==1) { // Calculated output glyph indices | |
| 1468 | - $Lookup[$i]['Subtable'][$c]['DeltaGlyphID'] = $this->read_short(); | |
| 1469 | - } | |
| 1470 | - else if ($SubstFormat==2) { // Specified output glyph indices | |
| 1471 | - $GlyphCount = $this->read_ushort(); | |
| 1472 | - for ($g=0;$g<$GlyphCount;$g++) { | |
| 1473 | - $Lookup[$i]['Subtable'][$c]['Glyphs'][] = $this->read_ushort(); | |
| 1474 | - } | |
| 1475 | - } | |
| 1476 | - } | |
| 1477 | - // LookupType 2: Multiple Substitution Subtable | |
| 1478 | - else if ($Lookup[$i]['Type'] == 2) { | |
| 1479 | - $Lookup[$i]['Subtable'][$c]['CoverageTableOffset'] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->read_ushort(); | |
| 1480 | - $Lookup[$i]['Subtable'][$c]['SequenceCount'] = $SequenceCount = $this->read_short(); | |
| 1481 | - for($s=0;$s<$SequenceCount;$s++) { | |
| 1482 | - $Lookup[$i]['Subtable'][$c]['Sequences'][$s]['Offset'] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->read_short(); | |
| 1483 | - } | |
| 1484 | - for($s=0;$s<$SequenceCount;$s++) { | |
| 1485 | - // Sequence Tables | |
| 1486 | - $this->seek($Lookup[$i]['Subtable'][$c]['Sequences'][$s]['Offset']); | |
| 1487 | - $Lookup[$i]['Subtable'][$c]['Sequences'][$s]['GlyphCount'] = $this->read_short(); | |
| 1488 | - for ($g=0;$g<$Lookup[$i]['Subtable'][$c]['Sequences'][$s]['GlyphCount'];$g++) { | |
| 1489 | - $Lookup[$i]['Subtable'][$c]['Sequences'][$s]['SubstituteGlyphID'][] = $this->read_ushort(); | |
| 1490 | - } | |
| 1491 | - } | |
| 1492 | - } | |
| 1493 | - // LookupType 3: Alternate Forms | |
| 1494 | - else if ($Lookup[$i]['Type'] == 3) { | |
| 1495 | - $Lookup[$i]['Subtable'][$c]['CoverageTableOffset'] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->read_ushort(); | |
| 1496 | - $Lookup[$i]['Subtable'][$c]['AlternateSetCount'] = $AlternateSetCount = $this->read_short(); | |
| 1497 | - for($s=0;$s<$AlternateSetCount;$s++) { | |
| 1498 | - $Lookup[$i]['Subtable'][$c]['AlternateSets'][$s]['Offset'] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->read_short(); | |
| 1499 | - } | |
| 1500 | - | |
| 1501 | - for($s=0;$s<$AlternateSetCount;$s++) { | |
| 1502 | - // AlternateSet Tables | |
| 1503 | - $this->seek($Lookup[$i]['Subtable'][$c]['AlternateSets'][$s]['Offset']); | |
| 1504 | - $Lookup[$i]['Subtable'][$c]['AlternateSets'][$s]['GlyphCount'] = $this->read_short(); | |
| 1505 | - for ($g=0;$g<$Lookup[$i]['Subtable'][$c]['AlternateSets'][$s]['GlyphCount'];$g++) { | |
| 1506 | - $Lookup[$i]['Subtable'][$c]['AlternateSets'][$s]['SubstituteGlyphID'][] = $this->read_ushort(); | |
| 1507 | - } | |
| 1508 | - } | |
| 1509 | - } | |
| 1510 | - // LookupType 4: Ligature Substitution Subtable | |
| 1511 | - else if ($Lookup[$i]['Type'] == 4) { | |
| 1512 | - $Lookup[$i]['Subtable'][$c]['CoverageTableOffset'] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->read_ushort(); | |
| 1513 | - $Lookup[$i]['Subtable'][$c]['LigSetCount'] = $LigSetCount = $this->read_short(); | |
| 1514 | - for($s=0;$s<$LigSetCount;$s++) { | |
| 1515 | - $Lookup[$i]['Subtable'][$c]['LigSet'][$s]['Offset'] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->read_short(); | |
| 1516 | - } | |
| 1517 | - for($s=0;$s<$LigSetCount;$s++) { | |
| 1518 | - // LigatureSet Tables | |
| 1519 | - $this->seek($Lookup[$i]['Subtable'][$c]['LigSet'][$s]['Offset']); | |
| 1520 | - $Lookup[$i]['Subtable'][$c]['LigSet'][$s]['LigCount'] = $this->read_short(); | |
| 1521 | - for ($g=0;$g<$Lookup[$i]['Subtable'][$c]['LigSet'][$s]['LigCount'];$g++) { | |
| 1522 | - $Lookup[$i]['Subtable'][$c]['LigSet'][$s]['LigatureOffset'][$g] = $Lookup[$i]['Subtable'][$c]['LigSet'][$s]['Offset'] + $this->read_ushort(); | |
| 1523 | - } | |
| 1524 | - } | |
| 1525 | - for($s=0;$s<$LigSetCount;$s++) { | |
| 1526 | - for ($g=0;$g<$Lookup[$i]['Subtable'][$c]['LigSet'][$s]['LigCount'];$g++) { | |
| 1527 | - // Ligature tables | |
| 1528 | - $this->seek($Lookup[$i]['Subtable'][$c]['LigSet'][$s]['LigatureOffset'][$g]); | |
| 1529 | - $Lookup[$i]['Subtable'][$c]['LigSet'][$s]['Ligature'][$g]['LigGlyph'] = $this->read_ushort(); | |
| 1530 | - $Lookup[$i]['Subtable'][$c]['LigSet'][$s]['Ligature'][$g]['CompCount'] = $this->read_ushort(); | |
| 1531 | - for ($l=1;$l<$Lookup[$i]['Subtable'][$c]['LigSet'][$s]['Ligature'][$g]['CompCount'];$l++) { | |
| 1532 | - $Lookup[$i]['Subtable'][$c]['LigSet'][$s]['Ligature'][$g]['GlyphID'][$l] = $this->read_ushort(); | |
| 1533 | - } | |
| 1534 | - } | |
| 1535 | - } | |
| 1536 | - } | |
| 1537 | - | |
| 1538 | - // LookupType 5: Contextual Substitution Subtable | |
| 1539 | - else if ($Lookup[$i]['Type'] == 5) { | |
| 1540 | - // Format 1: Context Substitution | |
| 1541 | - if ($SubstFormat==1) { | |
| 1542 | - $Lookup[$i]['Subtable'][$c]['CoverageTableOffset'] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->read_ushort(); | |
| 1543 | - $Lookup[$i]['Subtable'][$c]['SubRuleSetCount'] = $SubRuleSetCount = $this->read_short(); | |
| 1544 | - for($s=0;$s<$SubRuleSetCount;$s++) { | |
| 1545 | - $Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['Offset'] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->read_short(); | |
| 1546 | - } | |
| 1547 | - for($s=0;$s<$SubRuleSetCount;$s++) { | |
| 1548 | - // SubRuleSet Tables | |
| 1549 | - $this->seek($Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['Offset']); | |
| 1550 | - $Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['SubRuleCount'] = $this->read_short(); | |
| 1551 | - for ($g=0;$g<$Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['SubRuleCount'];$g++) { | |
| 1552 | - $Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['SubRuleOffset'][$g] = $Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['Offset'] + $this->read_ushort(); | |
| 1553 | - } | |
| 1554 | - } | |
| 1555 | - for($s=0;$s<$SubRuleSetCount;$s++) { | |
| 1556 | - // SubRule Tables | |
| 1557 | - for ($g=0;$g<$Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['SubRuleCount'];$g++) { | |
| 1558 | - // Ligature tables | |
| 1559 | - $this->seek($Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['SubRuleOffset'][$g]); | |
| 1560 | - | |
| 1561 | - $Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['SubRule'][$g]['GlyphCount'] = $this->read_ushort(); | |
| 1562 | - $Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['SubRule'][$g]['SubstCount'] = $this->read_ushort(); | |
| 1563 | - // "Input"::[GlyphCount - 1]::Array of input GlyphIDs-start with second glyph | |
| 1564 | - for ($l=1;$l<$Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['SubRule'][$g]['GlyphCount'];$l++) { | |
| 1565 | - $Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['SubRule'][$g]['Input'][$l] = $this->read_ushort(); | |
| 1566 | - } | |
| 1567 | - // "SubstLookupRecord"::[SubstCount]::Array of SubstLookupRecords-in design order | |
| 1568 | - for ($l=0;$l<$Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['SubRule'][$g]['SubstCount'];$l++) { | |
| 1569 | - $Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['SubRule'][$g]['SubstLookupRecord'][$l]['SequenceIndex'] = $this->read_ushort(); | |
| 1570 | - $Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['SubRule'][$g]['SubstLookupRecord'][$l]['LookupListIndex'] = $this->read_ushort(); | |
| 1571 | - } | |
| 1572 | - | |
| 1573 | - } | |
| 1574 | - } | |
| 1575 | - | |
| 1576 | - } | |
| 1577 | - // Format 2: Class-based Context Glyph Substitution | |
| 1578 | - else if ($SubstFormat==2) { | |
| 1579 | - $Lookup[$i]['Subtable'][$c]['CoverageTableOffset'] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->read_ushort(); | |
| 1580 | - $Lookup[$i]['Subtable'][$c]['ClassDefOffset'] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->read_ushort(); | |
| 1581 | - $Lookup[$i]['Subtable'][$c]['SubClassSetCnt'] = $this->read_ushort(); | |
| 1582 | - for ($b=0;$b<$Lookup[$i]['Subtable'][$c]['SubClassSetCnt'];$b++) { | |
| 1583 | - $offset = $this->read_ushort(); | |
| 1584 | - if ($offset==0x0000) { | |
| 1585 | - $Lookup[$i]['Subtable'][$c]['SubClassSetOffset'][] = 0; | |
| 1586 | - } | |
| 1587 | - else { | |
| 1588 | - $Lookup[$i]['Subtable'][$c]['SubClassSetOffset'][] = $Lookup[$i]['Subtable'][$c]['Offset'] + $offset; | |
| 1589 | - } | |
| 1590 | - } | |
| 1591 | - } | |
| 1592 | - else { die("GPOS Lookup Type ".$Lookup[$i]['Type'].", Format ".$SubstFormat." not supported (ttfontsuni.php)."); } | |
| 1593 | - } | |
| 1594 | - | |
| 1595 | - // LookupType 6: Chaining Contextual Substitution Subtable | |
| 1596 | - else if ($Lookup[$i]['Type'] == 6) { | |
| 1597 | - // Format 1: Simple Chaining Context Glyph Substitution p255 | |
| 1598 | - if ($SubstFormat==1) { | |
| 1599 | - $Lookup[$i]['Subtable'][$c]['CoverageTableOffset'] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->read_ushort(); | |
| 1600 | - $Lookup[$i]['Subtable'][$c]['ChainSubRuleSetCount'] = $this->read_ushort(); | |
| 1601 | - for ($b=0;$b<$Lookup[$i]['Subtable'][$c]['ChainSubRuleSetCount'];$b++) { | |
| 1602 | - $Lookup[$i]['Subtable'][$c]['ChainSubRuleSetOffset'][] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->read_ushort(); | |
| 1603 | - } | |
| 1604 | - } | |
| 1605 | - // Format 2: Class-based Chaining Context Glyph Substitution p257 | |
| 1606 | - else if ($SubstFormat==2) { | |
| 1607 | - $Lookup[$i]['Subtable'][$c]['CoverageTableOffset'] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->read_ushort(); | |
| 1608 | - $Lookup[$i]['Subtable'][$c]['BacktrackClassDefOffset'] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->read_ushort(); | |
| 1609 | - $Lookup[$i]['Subtable'][$c]['InputClassDefOffset'] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->read_ushort(); | |
| 1610 | - $Lookup[$i]['Subtable'][$c]['LookaheadClassDefOffset'] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->read_ushort(); | |
| 1611 | - $Lookup[$i]['Subtable'][$c]['ChainSubClassSetCnt'] = $this->read_ushort(); | |
| 1612 | - for ($b=0;$b<$Lookup[$i]['Subtable'][$c]['ChainSubClassSetCnt'];$b++) { | |
| 1613 | - $offset = $this->read_ushort(); | |
| 1614 | - if ($offset==0x0000) { | |
| 1615 | - $Lookup[$i]['Subtable'][$c]['ChainSubClassSetOffset'][] = $offset; | |
| 1616 | - } | |
| 1617 | - else { | |
| 1618 | - $Lookup[$i]['Subtable'][$c]['ChainSubClassSetOffset'][] = $Lookup[$i]['Subtable'][$c]['Offset'] + $offset; | |
| 1619 | - } | |
| 1620 | - } | |
| 1621 | - } | |
| 1622 | - // Format 3: Coverage-based Chaining Context Glyph Substitution p259 | |
| 1623 | - else if ($SubstFormat==3) { | |
| 1624 | - $Lookup[$i]['Subtable'][$c]['BacktrackGlyphCount'] = $this->read_ushort(); | |
| 1625 | - for ($b=0;$b<$Lookup[$i]['Subtable'][$c]['BacktrackGlyphCount'];$b++) { | |
| 1626 | - $Lookup[$i]['Subtable'][$c]['CoverageBacktrack'][] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->read_ushort(); | |
| 1627 | - } | |
| 1628 | - $Lookup[$i]['Subtable'][$c]['InputGlyphCount'] = $this->read_ushort(); | |
| 1629 | - for ($b=0;$b<$Lookup[$i]['Subtable'][$c]['InputGlyphCount'];$b++) { | |
| 1630 | - $Lookup[$i]['Subtable'][$c]['CoverageInput'][] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->read_ushort(); | |
| 1631 | - } | |
| 1632 | - $Lookup[$i]['Subtable'][$c]['LookaheadGlyphCount'] = $this->read_ushort(); | |
| 1633 | - for ($b=0;$b<$Lookup[$i]['Subtable'][$c]['LookaheadGlyphCount'];$b++) { | |
| 1634 | - $Lookup[$i]['Subtable'][$c]['CoverageLookahead'][] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->read_ushort(); | |
| 1635 | - } | |
| 1636 | - $Lookup[$i]['Subtable'][$c]['SubstCount'] = $this->read_ushort(); | |
| 1637 | - for ($b=0;$b<$Lookup[$i]['Subtable'][$c]['SubstCount'];$b++) { | |
| 1638 | - $Lookup[$i]['Subtable'][$c]['SubstLookupRecord'][$b]['SequenceIndex'] = $this->read_ushort(); | |
| 1639 | - $Lookup[$i]['Subtable'][$c]['SubstLookupRecord'][$b]['LookupListIndex'] = $this->read_ushort(); | |
| 1640 | -/* | |
| 1641 | -Substitution Lookup Record | |
| 1642 | -All contextual substitution subtables specify the substitution data in a Substitution Lookup Record (SubstLookupRecord). Each record contains a SequenceIndex, which indicates the position where the substitution will occur in the glyph sequence. In addition, a LookupListIndex identifies the lookup to be applied at the glyph position specified by the SequenceIndex. | |
| 1643 | -*/ | |
| 1644 | - | |
| 1645 | - } | |
| 1646 | - } | |
| 1647 | - } | |
| 1648 | - else { die("Lookup Type ".$Lookup[$i]['Type']." not supported."); } | |
| 1649 | - } | |
| 1650 | - } | |
| 1651 | -//print_r($Lookup); exit; | |
| 1652 | - | |
| 1653 | - | |
| 1654 | - | |
| 1655 | - | |
| 1656 | - //===================================================================================== | |
| 1657 | - // Process (2) Whole LookupList | |
| 1658 | - // Get Coverage tables and prepare preg_replace | |
| 1659 | - for ($i=0;$i<$LookupCount;$i++) { | |
| 1660 | - for ($c=0;$c<$Lookup[$i]['SubtableCount'] ;$c++) { | |
| 1661 | - $SubstFormat= $Lookup[$i]['Subtable'][$c]['Format'] ; | |
| 1662 | - | |
| 1663 | - // LookupType 1: Single Substitution Subtable 1 => 1 | |
| 1664 | - if ($Lookup[$i]['Type'] == 1) { | |
| 1665 | - $this->seek($Lookup[$i]['Subtable'][$c]['CoverageTableOffset']); | |
| 1666 | - $glyphs = $this->_getCoverage(false); | |
| 1667 | - for ($g=0;$g<count($glyphs);$g++) { | |
| 1668 | - $replace = array(); | |
| 1669 | - $substitute = array(); | |
| 1670 | - $replace[] = unicode_hex($this->glyphToChar[$glyphs[$g]][0]); | |
| 1671 | - // Flag = Ignore | |
| 1672 | - if ($this->_checkGSUBignore($Lookup[$i]['Flag'], $replace[0], $Lookup[$i]['MarkFilteringSet'])) { continue; } | |
| 1673 | - if (isset($Lookup[$i]['Subtable'][$c]['DeltaGlyphID'])) { // Format 1 | |
| 1674 | - $substitute[] = unicode_hex($this->glyphToChar[($glyphs[$g]+$Lookup[$i]['Subtable'][$c]['DeltaGlyphID'])][0]); | |
| 1675 | - } | |
| 1676 | - else { // Format 2 | |
| 1677 | - $substitute[] = unicode_hex($this->glyphToChar[($Lookup[$i]['Subtable'][$c]['Glyphs'][$g])][0]); | |
| 1678 | - } | |
| 1679 | - $Lookup[$i]['Subtable'][$c]['subs'][] = array('Replace'=>$replace, 'substitute'=>$substitute); | |
| 1680 | - } | |
| 1681 | - } | |
| 1682 | - | |
| 1683 | - // LookupType 2: Multiple Substitution Subtable 1 => n | |
| 1684 | - else if ($Lookup[$i]['Type'] == 2) { | |
| 1685 | - $this->seek($Lookup[$i]['Subtable'][$c]['CoverageTableOffset']); | |
| 1686 | - $glyphs = $this->_getCoverage(); | |
| 1687 | - for ($g=0;$g<count($glyphs);$g++) { | |
| 1688 | - $replace = array(); | |
| 1689 | - $substitute = array(); | |
| 1690 | - $replace[] = $glyphs[$g]; | |
| 1691 | - // Flag = Ignore | |
| 1692 | - if ($this->_checkGSUBignore($Lookup[$i]['Flag'], $replace[0], $Lookup[$i]['MarkFilteringSet'])) { continue; } | |
| 1693 | -if (!isset($Lookup[$i]['Subtable'][$c]['Sequences'][$g]['SubstituteGlyphID']) || count($Lookup[$i]['Subtable'][$c]['Sequences'][$g]['SubstituteGlyphID'])==0) { continue; } // Illegal for GlyphCount to be 0; either error in font, or something has gone wrong - lets carry on for now! | |
| 1694 | - foreach($Lookup[$i]['Subtable'][$c]['Sequences'][$g]['SubstituteGlyphID'] AS $sub) { | |
| 1695 | - $substitute[] = unicode_hex($this->glyphToChar[$sub][0]); | |
| 1696 | - } | |
| 1697 | - $Lookup[$i]['Subtable'][$c]['subs'][] = array('Replace'=>$replace, 'substitute'=>$substitute); | |
| 1698 | - } | |
| 1699 | - } | |
| 1700 | - // LookupType 3: Alternate Forms 1 => 1 (only first alternate form is used) | |
| 1701 | - else if ($Lookup[$i]['Type'] == 3) { | |
| 1702 | - $this->seek($Lookup[$i]['Subtable'][$c]['CoverageTableOffset']); | |
| 1703 | - $glyphs = $this->_getCoverage(); | |
| 1704 | - for ($g=0;$g<count($glyphs);$g++) { | |
| 1705 | - $replace = array(); | |
| 1706 | - $substitute = array(); | |
| 1707 | - $replace[] = $glyphs[$g]; | |
| 1708 | - // Flag = Ignore | |
| 1709 | - if ($this->_checkGSUBignore($Lookup[$i]['Flag'], $replace[0], $Lookup[$i]['MarkFilteringSet'])) { continue; } | |
| 1710 | - $gid = $Lookup[$i]['Subtable'][$c]['AlternateSets'][$g]['SubstituteGlyphID'][0]; | |
| 1711 | - if (!isset($this->glyphToChar[$gid][0])) { continue; } | |
| 1712 | - $substitute[] = unicode_hex($this->glyphToChar[$gid][0]); | |
| 1713 | - $Lookup[$i]['Subtable'][$c]['subs'][] = array('Replace'=>$replace, 'substitute'=>$substitute); | |
| 1714 | - } | |
| 1715 | - } | |
| 1716 | - // LookupType 4: Ligature Substitution Subtable n => 1 | |
| 1717 | - else if ($Lookup[$i]['Type'] == 4) { | |
| 1718 | - $this->seek($Lookup[$i]['Subtable'][$c]['CoverageTableOffset']); | |
| 1719 | - $glyphs = $this->_getCoverage(); | |
| 1720 | - $LigSetCount = $Lookup[$i]['Subtable'][$c]['LigSetCount']; | |
| 1721 | - for($s=0;$s<$LigSetCount;$s++) { | |
| 1722 | - for ($g=0;$g<$Lookup[$i]['Subtable'][$c]['LigSet'][$s]['LigCount'];$g++) { | |
| 1723 | - $replace = array(); | |
| 1724 | - $substitute = array(); | |
| 1725 | - $replace[] = $glyphs[$s]; | |
| 1726 | - // Flag = Ignore | |
| 1727 | - if ($this->_checkGSUBignore($Lookup[$i]['Flag'], $replace[0], $Lookup[$i]['MarkFilteringSet'])) { continue; } | |
| 1728 | - for ($l=1;$l<$Lookup[$i]['Subtable'][$c]['LigSet'][$s]['Ligature'][$g]['CompCount'];$l++) { | |
| 1729 | - $gid = $Lookup[$i]['Subtable'][$c]['LigSet'][$s]['Ligature'][$g]['GlyphID'][$l]; | |
| 1730 | - $rpl = unicode_hex($this->glyphToChar[$gid][0]); | |
| 1731 | - // Flag = Ignore | |
| 1732 | - if ($this->_checkGSUBignore($Lookup[$i]['Flag'], $rpl, $Lookup[$i]['MarkFilteringSet'])) { continue 2; } | |
| 1733 | - $replace[] = $rpl; | |
| 1734 | - } | |
| 1735 | - $gid = $Lookup[$i]['Subtable'][$c]['LigSet'][$s]['Ligature'][$g]['LigGlyph']; | |
| 1736 | - if (!isset($this->glyphToChar[$gid][0])) { continue; } | |
| 1737 | - $substitute[] = unicode_hex($this->glyphToChar[$gid][0]); | |
| 1738 | - $Lookup[$i]['Subtable'][$c]['subs'][] = array('Replace'=>$replace, 'substitute'=>$substitute, 'CompCount' => $Lookup[$i]['Subtable'][$c]['LigSet'][$s]['Ligature'][$g]['CompCount']); | |
| 1739 | - } | |
| 1740 | - } | |
| 1741 | - } | |
| 1742 | - | |
| 1743 | - // LookupType 5: Contextual Substitution Subtable | |
| 1744 | - else if ($Lookup[$i]['Type'] == 5) { | |
| 1745 | - // Format 1: Context Substitution | |
| 1746 | - if ($SubstFormat==1) { | |
| 1747 | - $this->seek($Lookup[$i]['Subtable'][$c]['CoverageTableOffset']); | |
| 1748 | - $Lookup[$i]['Subtable'][$c]['CoverageGlyphs'] = $CoverageGlyphs = $this->_getCoverage(); | |
| 1749 | - | |
| 1750 | - for ($s=0;$s<$Lookup[$i]['Subtable'][$c]['SubRuleSetCount'];$s++) { | |
| 1751 | - $SubRuleSet = $Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]; | |
| 1752 | - $Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['FirstGlyph'] = $CoverageGlyphs[$s]; | |
| 1753 | - for ($r=0;$r<$Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['SubRuleCount'];$r++) { | |
| 1754 | - $GlyphCount = $Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['SubRule'][$r]['GlyphCount']; | |
| 1755 | - for ($g=1;$g<$GlyphCount;$g++) { | |
| 1756 | - $glyphID = $Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['SubRule'][$r]['Input'][$g]; | |
| 1757 | - $Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['SubRule'][$r]['InputGlyphs'][$g] = unicode_hex($this->glyphToChar[$glyphID][0]); | |
| 1758 | - } | |
| 1759 | - | |
| 1760 | - } | |
| 1761 | - } | |
| 1762 | - } | |
| 1763 | - // Format 2: Class-based Context Glyph Substitution | |
| 1764 | - else if ($SubstFormat==2) { | |
| 1765 | - $this->seek($Lookup[$i]['Subtable'][$c]['CoverageTableOffset']); | |
| 1766 | - $Lookup[$i]['Subtable'][$c]['CoverageGlyphs'] = $CoverageGlyphs = $this->_getCoverage(); | |
| 1767 | - | |
| 1768 | - $InputClasses = $this->_getClasses($Lookup[$i]['Subtable'][$c]['ClassDefOffset']); | |
| 1769 | - $Lookup[$i]['Subtable'][$c]['InputClasses'] = $InputClasses; | |
| 1770 | - for ($s=0;$s<$Lookup[$i]['Subtable'][$c]['SubClassSetCnt'];$s++) { | |
| 1771 | - if ($Lookup[$i]['Subtable'][$c]['SubClassSetOffset'][$s]>0) { | |
| 1772 | - $this->seek($Lookup[$i]['Subtable'][$c]['SubClassSetOffset'][$s]); | |
| 1773 | - $Lookup[$i]['Subtable'][$c]['SubClassSet'][$s]['SubClassRuleCnt'] = $SubClassRuleCnt = $this->read_ushort(); | |
| 1774 | - $SubClassRule = array(); | |
| 1775 | - for($b=0;$b<$SubClassRuleCnt;$b++) { | |
| 1776 | - $SubClassRule[$b] = $Lookup[$i]['Subtable'][$c]['SubClassSetOffset'][$s]+$this->read_ushort(); | |
| 1777 | - $Lookup[$i]['Subtable'][$c]['SubClassSet'][$s]['SubClassRule'][$b] = $SubClassRule[$b]; | |
| 1778 | - } | |
| 1779 | - } | |
| 1780 | - } | |
| 1781 | - | |
| 1782 | - for ($s=0;$s<$Lookup[$i]['Subtable'][$c]['SubClassSetCnt'];$s++) { | |
| 1783 | - if ($Lookup[$i]['Subtable'][$c]['SubClassSetOffset'][$s]>0) { | |
| 1784 | - $SubClassRuleCnt = $Lookup[$i]['Subtable'][$c]['SubClassSet'][$s]['SubClassRuleCnt']; | |
| 1785 | - for($b=0;$b<$SubClassRuleCnt;$b++) { | |
| 1786 | - $this->seek($Lookup[$i]['Subtable'][$c]['SubClassSet'][$s]['SubClassRule'][$b]); | |
| 1787 | - $Rule = array(); | |
| 1788 | - $Rule['InputGlyphCount'] = $this->read_ushort(); | |
| 1789 | - $Rule['SubstCount'] = $this->read_ushort(); | |
| 1790 | - for ($r=1;$r<$Rule['InputGlyphCount'];$r++) { | |
| 1791 | - $Rule['Input'][$r] = $this->read_ushort(); | |
| 1792 | - } | |
| 1793 | - for ($r=0;$r<$Rule['SubstCount'];$r++) { | |
| 1794 | - $Rule['SequenceIndex'][$r] = $this->read_ushort(); | |
| 1795 | - $Rule['LookupListIndex'][$r] = $this->read_ushort(); | |
| 1796 | - } | |
| 1797 | - | |
| 1798 | - $Lookup[$i]['Subtable'][$c]['SubClassSet'][$s]['SubClassRule'][$b] = $Rule; | |
| 1799 | - } | |
| 1800 | - } | |
| 1801 | - } | |
| 1802 | - } | |
| 1803 | - // Format 3: Coverage-based Context Glyph Substitution | |
| 1804 | - else if ($SubstFormat==3) { | |
| 1805 | - for ($b=0;$b<$Lookup[$i]['Subtable'][$c]['InputGlyphCount'];$b++) { | |
| 1806 | - $this->seek($Lookup[$i]['Subtable'][$c]['CoverageInput'][$b]); | |
| 1807 | - $glyphs = $this->_getCoverage(); | |
| 1808 | - $Lookup[$i]['Subtable'][$c]['CoverageInputGlyphs'][] = implode("|",$glyphs); | |
| 1809 | - } | |
| 1810 | - die("Lookup Type 5, SubstFormat 3 not tested. Please report this with the name of font used - ".$this->fontkey); | |
| 1811 | - } | |
| 1812 | - | |
| 1813 | - } | |
| 1814 | - | |
| 1815 | - // LookupType 6: Chaining Contextual Substitution Subtable | |
| 1816 | - else if ($Lookup[$i]['Type'] == 6) { | |
| 1817 | - // Format 1: Simple Chaining Context Glyph Substitution p255 | |
| 1818 | - if ($SubstFormat==1) { | |
| 1819 | - $this->seek($Lookup[$i]['Subtable'][$c]['CoverageTableOffset']); | |
| 1820 | - $Lookup[$i]['Subtable'][$c]['CoverageGlyphs'] = $CoverageGlyphs = $this->_getCoverage(); | |
| 1821 | - | |
| 1822 | - $ChainSubRuleSetCnt = $Lookup[$i]['Subtable'][$c]['ChainSubRuleSetCount']; | |
| 1823 | - | |
| 1824 | - for ($s=0;$s<$ChainSubRuleSetCnt;$s++) { | |
| 1825 | - $this->seek($Lookup[$i]['Subtable'][$c]['ChainSubRuleSetOffset'][$s]); | |
| 1826 | - $ChainSubRuleCnt = $Lookup[$i]['Subtable'][$c]['ChainSubRuleSet'][$s]['ChainSubRuleCount'] = $this->read_ushort(); | |
| 1827 | - for ($r=0;$r<$ChainSubRuleCnt;$r++) { | |
| 1828 | - $Lookup[$i]['Subtable'][$c]['ChainSubRuleSet'][$s]['ChainSubRuleOffset'][$r] = $Lookup[$i]['Subtable'][$c]['ChainSubRuleSetOffset'][$s] + $this->read_ushort(); | |
| 1829 | - | |
| 1830 | - } | |
| 1831 | - } | |
| 1832 | - for ($s=0;$s<$ChainSubRuleSetCnt;$s++) { | |
| 1833 | - $ChainSubRuleCnt = $Lookup[$i]['Subtable'][$c]['ChainSubRuleSet'][$s]['ChainSubRuleCount']; | |
| 1834 | - for ($r=0;$r<$ChainSubRuleCnt;$r++) { | |
| 1835 | - // ChainSubRule | |
| 1836 | - $this->seek($Lookup[$i]['Subtable'][$c]['ChainSubRuleSet'][$s]['ChainSubRuleOffset'][$r]); | |
| 1837 | - | |
| 1838 | - $BacktrackGlyphCount = $Lookup[$i]['Subtable'][$c]['ChainSubRuleSet'][$s]['ChainSubRule'][$r]['BacktrackGlyphCount'] = $this->read_ushort(); | |
| 1839 | - for ($g=0;$g<$BacktrackGlyphCount;$g++) { | |
| 1840 | - $glyphID = $this->read_ushort(); | |
| 1841 | - $Lookup[$i]['Subtable'][$c]['ChainSubRuleSet'][$s]['ChainSubRule'][$r]['BacktrackGlyphs'][$g] = unicode_hex($this->glyphToChar[$glyphID][0]); | |
| 1842 | - } | |
| 1843 | - | |
| 1844 | - $InputGlyphCount = $Lookup[$i]['Subtable'][$c]['ChainSubRuleSet'][$s]['ChainSubRule'][$r]['InputGlyphCount'] = $this->read_ushort(); | |
| 1845 | - for ($g=1;$g<$InputGlyphCount;$g++) { | |
| 1846 | - $glyphID = $this->read_ushort(); | |
| 1847 | - $Lookup[$i]['Subtable'][$c]['ChainSubRuleSet'][$s]['ChainSubRule'][$r]['InputGlyphs'][$g] = unicode_hex($this->glyphToChar[$glyphID][0]); | |
| 1848 | - } | |
| 1849 | - | |
| 1850 | - | |
| 1851 | - $LookaheadGlyphCount = $Lookup[$i]['Subtable'][$c]['ChainSubRuleSet'][$s]['ChainSubRule'][$r]['LookaheadGlyphCount'] = $this->read_ushort(); | |
| 1852 | - for ($g=0;$g<$LookaheadGlyphCount;$g++) { | |
| 1853 | - $glyphID = $this->read_ushort(); | |
| 1854 | - $Lookup[$i]['Subtable'][$c]['ChainSubRuleSet'][$s]['ChainSubRule'][$r]['LookaheadGlyphs'][$g] = unicode_hex($this->glyphToChar[$glyphID][0]); | |
| 1855 | - } | |
| 1856 | - | |
| 1857 | - $SubstCount = $Lookup[$i]['Subtable'][$c]['ChainSubRuleSet'][$s]['ChainSubRule'][$r]['SubstCount'] = $this->read_ushort(); | |
| 1858 | - for ($lu=0;$lu<$SubstCount;$lu++) { | |
| 1859 | - $Lookup[$i]['Subtable'][$c]['ChainSubRuleSet'][$s]['ChainSubRule'][$r]['SequenceIndex'][$lu] = $this->read_ushort(); | |
| 1860 | - $Lookup[$i]['Subtable'][$c]['ChainSubRuleSet'][$s]['ChainSubRule'][$r]['LookupListIndex'][$lu] = $this->read_ushort(); | |
| 1861 | - } | |
| 1862 | - } | |
| 1863 | - } | |
| 1864 | - | |
| 1865 | - } | |
| 1866 | - // Format 2: Class-based Chaining Context Glyph Substitution p257 | |
| 1867 | - else if ($SubstFormat==2) { | |
| 1868 | - $this->seek($Lookup[$i]['Subtable'][$c]['CoverageTableOffset']); | |
| 1869 | - $Lookup[$i]['Subtable'][$c]['CoverageGlyphs'] = $CoverageGlyphs = $this->_getCoverage(); | |
| 1870 | - | |
| 1871 | - $BacktrackClasses = $this->_getClasses($Lookup[$i]['Subtable'][$c]['BacktrackClassDefOffset']); | |
| 1872 | - $Lookup[$i]['Subtable'][$c]['BacktrackClasses'] = $BacktrackClasses; | |
| 1873 | - | |
| 1874 | - $InputClasses = $this->_getClasses($Lookup[$i]['Subtable'][$c]['InputClassDefOffset']); | |
| 1875 | - $Lookup[$i]['Subtable'][$c]['InputClasses'] = $InputClasses; | |
| 1876 | - | |
| 1877 | - $LookaheadClasses = $this->_getClasses($Lookup[$i]['Subtable'][$c]['LookaheadClassDefOffset']); | |
| 1878 | - $Lookup[$i]['Subtable'][$c]['LookaheadClasses'] = $LookaheadClasses; | |
| 1879 | - | |
| 1880 | - for ($s=0;$s<$Lookup[$i]['Subtable'][$c]['ChainSubClassSetCnt'];$s++) { | |
| 1881 | - if ($Lookup[$i]['Subtable'][$c]['ChainSubClassSetOffset'][$s]>0) { | |
| 1882 | - $this->seek($Lookup[$i]['Subtable'][$c]['ChainSubClassSetOffset'][$s]); | |
| 1883 | - $Lookup[$i]['Subtable'][$c]['ChainSubClassSet'][$s]['ChainSubClassRuleCnt'] = $ChainSubClassRuleCnt = $this->read_ushort(); | |
| 1884 | - $ChainSubClassRule = array(); | |
| 1885 | - for($b=0;$b<$ChainSubClassRuleCnt;$b++) { | |
| 1886 | - $ChainSubClassRule[$b] = $Lookup[$i]['Subtable'][$c]['ChainSubClassSetOffset'][$s]+$this->read_ushort(); | |
| 1887 | - $Lookup[$i]['Subtable'][$c]['ChainSubClassSet'][$s]['ChainSubClassRule'][$b] = $ChainSubClassRule[$b]; | |
| 1888 | - } | |
| 1889 | - } | |
| 1890 | - } | |
| 1891 | - | |
| 1892 | - for ($s=0;$s<$Lookup[$i]['Subtable'][$c]['ChainSubClassSetCnt'];$s++) { | |
| 1893 | - if (isset($Lookup[$i]['Subtable'][$c]['ChainSubClassSet'][$s]['ChainSubClassRuleCnt'])) { | |
| 1894 | - $ChainSubClassRuleCnt = $Lookup[$i]['Subtable'][$c]['ChainSubClassSet'][$s]['ChainSubClassRuleCnt']; | |
| 1895 | - } | |
| 1896 | - else { $ChainSubClassRuleCnt = 0; } | |
| 1897 | - for($b=0;$b<$ChainSubClassRuleCnt;$b++) { | |
| 1898 | - if ($Lookup[$i]['Subtable'][$c]['ChainSubClassSetOffset'][$s]>0) { | |
| 1899 | - $this->seek($Lookup[$i]['Subtable'][$c]['ChainSubClassSet'][$s]['ChainSubClassRule'][$b]); | |
| 1900 | - $Rule = array(); | |
| 1901 | - $Rule['BacktrackGlyphCount'] = $this->read_ushort(); | |
| 1902 | - for ($r=0;$r<$Rule['BacktrackGlyphCount'];$r++) { | |
| 1903 | - $Rule['Backtrack'][$r] = $this->read_ushort(); | |
| 1904 | - } | |
| 1905 | - $Rule['InputGlyphCount'] = $this->read_ushort(); | |
| 1906 | - for ($r=1;$r<$Rule['InputGlyphCount'];$r++) { | |
| 1907 | - $Rule['Input'][$r] = $this->read_ushort(); | |
| 1908 | - } | |
| 1909 | - $Rule['LookaheadGlyphCount'] = $this->read_ushort(); | |
| 1910 | - for ($r=0;$r<$Rule['LookaheadGlyphCount'];$r++) { | |
| 1911 | - $Rule['Lookahead'][$r] = $this->read_ushort(); | |
| 1912 | - } | |
| 1913 | - $Rule['SubstCount'] = $this->read_ushort(); | |
| 1914 | - for ($r=0;$r<$Rule['SubstCount'];$r++) { | |
| 1915 | - $Rule['SequenceIndex'][$r] = $this->read_ushort(); | |
| 1916 | - $Rule['LookupListIndex'][$r] = $this->read_ushort(); | |
| 1917 | - } | |
| 1918 | - | |
| 1919 | - $Lookup[$i]['Subtable'][$c]['ChainSubClassSet'][$s]['ChainSubClassRule'][$b] = $Rule; | |
| 1920 | - } | |
| 1921 | - } | |
| 1922 | - } | |
| 1923 | - } | |
| 1924 | - // Format 3: Coverage-based Chaining Context Glyph Substitution p259 | |
| 1925 | - else if ($SubstFormat==3) { | |
| 1926 | - for ($b=0;$b<$Lookup[$i]['Subtable'][$c]['BacktrackGlyphCount'];$b++) { | |
| 1927 | - $this->seek($Lookup[$i]['Subtable'][$c]['CoverageBacktrack'][$b]); | |
| 1928 | - $glyphs = $this->_getCoverage(); | |
| 1929 | - $Lookup[$i]['Subtable'][$c]['CoverageBacktrackGlyphs'][] = implode("|",$glyphs); | |
| 1930 | - } | |
| 1931 | - for ($b=0;$b<$Lookup[$i]['Subtable'][$c]['InputGlyphCount'];$b++) { | |
| 1932 | - $this->seek($Lookup[$i]['Subtable'][$c]['CoverageInput'][$b]); | |
| 1933 | - $glyphs = $this->_getCoverage(); | |
| 1934 | - $Lookup[$i]['Subtable'][$c]['CoverageInputGlyphs'][] = implode("|",$glyphs); | |
| 1935 | - // Don't use above value as these are ordered numerically not as need to process | |
| 1936 | - } | |
| 1937 | - for ($b=0;$b<$Lookup[$i]['Subtable'][$c]['LookaheadGlyphCount'];$b++) { | |
| 1938 | - $this->seek($Lookup[$i]['Subtable'][$c]['CoverageLookahead'][$b]); | |
| 1939 | - $glyphs = $this->_getCoverage(); | |
| 1940 | - $Lookup[$i]['Subtable'][$c]['CoverageLookaheadGlyphs'][] = implode("|",$glyphs); | |
| 1941 | - } | |
| 1942 | - | |
| 1943 | - } | |
| 1944 | - } | |
| 1945 | - } | |
| 1946 | - } | |
| 1947 | - | |
| 1948 | - | |
| 1949 | - //===================================================================================== | |
| 1950 | - //===================================================================================== | |
| 1951 | - //===================================================================================== | |
| 1952 | - //===================================================================================== | |
| 1953 | - | |
| 1954 | - $GSUBScriptLang = array(); | |
| 1955 | - $rtlpua = array(); // All glyphs added to PUA [for magic_reverse] | |
| 1956 | - foreach($gsub AS $st=>$scripts) { | |
| 1957 | - foreach($scripts AS $t=>$langsys) { | |
| 1958 | - $lul = array(); // array of LookupListIndexes | |
| 1959 | - $tags = array(); // corresponding array of feature tags e.g. 'ccmp' | |
| 1960 | -//print_r($langsys ); exit; | |
| 1961 | - foreach($langsys AS $tag=>$ft) { | |
| 1962 | - foreach($ft AS $ll) { | |
| 1963 | - $lul[$ll] = $tag; | |
| 1964 | - } | |
| 1965 | - } | |
| 1966 | - ksort($lul); // Order the Lookups in the order they are in the GUSB table, regardless of Feature order | |
| 1967 | - $volt = $this->_getGSUBarray($Lookup, $lul, $st); | |
| 1968 | -//print_r($lul); exit; | |
| 1969 | - | |
| 1970 | - //===================================================================================== | |
| 1971 | - //===================================================================================== | |
| 1972 | - // Interrogate $volt | |
| 1973 | - // isol, fin, medi, init(arab syrc) into $rtlSUB for use in ArabJoin | |
| 1974 | - // but also identify all RTL chars in PUA for magic_reverse (arab syrc hebr thaa nko samr) | |
| 1975 | - // identify reph, matras, vatu, half forms etc for Indic for final re-ordering | |
| 1976 | - //===================================================================================== | |
| 1977 | - //===================================================================================== | |
| 1978 | - $rtl = array(); | |
| 1979 | - $rtlSUB = "array()"; | |
| 1980 | - $finals = ''; | |
| 1981 | - if (strpos('arab syrc hebr thaa nko samr', $st)!==false) { // all RTL scripts [any/all languages] ? Mandaic | |
| 1982 | -//print_r($volt); exit; | |
| 1983 | - foreach($volt AS $v) { | |
| 1984 | - // isol fina fin2 fin3 medi med2 for Syriac | |
| 1985 | - // ISOLATED FORM :: FINAL :: INITIAL :: MEDIAL :: MED2 :: FIN2 :: FIN3 | |
| 1986 | - if (strpos('isol fina init medi fin2 fin3 med2',$v['tag'])!==false) { | |
| 1987 | - $key = $v['match']; | |
| 1988 | - $key = preg_replace('/[\(\)]*/','',$key); | |
| 1989 | - $sub = $v['replace']; | |
| 1990 | - if ($v['tag'] == 'isol') $kk = 0; | |
| 1991 | - else if ($v['tag'] == 'fina') $kk = 1; | |
| 1992 | - else if ($v['tag'] == 'init') $kk = 2; | |
| 1993 | - else if ($v['tag'] == 'medi') $kk = 3; | |
| 1994 | - else if ($v['tag'] == 'med2') $kk = 4; | |
| 1995 | - else if ($v['tag'] == 'fin2') $kk = 5; | |
| 1996 | - else if ($v['tag'] == 'fin3') $kk = 6; | |
| 1997 | - $rtl[$key][$kk] = $sub; | |
| 1998 | - if (isset($v['prel']) && count($v['prel'])) $rtl[$key]['prel'][$kk] = $v['prel']; | |
| 1999 | - if (isset($v['postl']) && count($v['postl'])) $rtl[$key]['postl'][$kk] = $v['postl']; | |
| 2000 | - if (isset($v['ignore']) && $v['ignore']) { | |
| 2001 | - $rtl[$key]['ignore'][$kk] = $v['ignore']; | |
| 2002 | - } | |
| 2003 | - $rtlpua[] = $sub; | |
| 2004 | - } | |
| 2005 | - // Add any other glyphs which are in PUA | |
| 2006 | - else { | |
| 2007 | - if (isset($v['context']) && $v['context']) { | |
| 2008 | - foreach($v['rules'] AS $vs) { | |
| 2009 | - for($i=0;$i<count($vs['match']);$i++) { | |
| 2010 | - if (isset($vs['replace'][$i]) && preg_match('/^0[A-F0-9]{4}$/', $vs['match'][$i])) { | |
| 2011 | - if (preg_match('/^0[EF][A-F0-9]{3}$/', $vs['replace'][$i])) { | |
| 2012 | - $rtlpua[] = $vs['replace'][$i]; | |
| 2013 | - } | |
| 2014 | - } | |
| 2015 | - } | |
| 2016 | - } | |
| 2017 | - } | |
| 2018 | - else { | |
| 2019 | - preg_match_all('/\((0[A-F0-9]{4})\)/', $v['match'], $m); | |
| 2020 | - for($i=0;$i<count($m[0]);$i++) { | |
| 2021 | - $sb = explode(' ',$v['replace']); | |
| 2022 | - foreach($sb AS $sbg) { | |
| 2023 | - if (preg_match('/(0[EF][A-F0-9]{3})/', $sbg, $mr)) { | |
| 2024 | - $rtlpua[] = $mr[1]; | |
| 2025 | - } | |
| 2026 | - } | |
| 2027 | - } | |
| 2028 | - } | |
| 2029 | - } | |
| 2030 | - } | |
| 2031 | -//print_r($rtl); exit; | |
| 2032 | - // For kashida, need to determine all final forms except ones already identified by kashida | |
| 2033 | - // priority rules (see otl.php) | |
| 2034 | - foreach($rtl AS $base=>$variants) { | |
| 2035 | - if (isset($variants[1])) { // i.e. final form | |
| 2036 | - if (strpos('0FE8E 0FE94 0FEA2 0FEAA 0FEAE 0FEC2 0FEDA 0FEDE 0FB93 0FECA 0FED2 0FED6 0FEEE 0FEF0 0FEF2', $variants[1])===false) { // not already included | |
| 2037 | - | |
| 2038 | - // This version does not exclude RA (0631) FEAE; Ya (064A) FEF2; Alef Maqsurah (0649) FEF0 which | |
| 2039 | - // are selected in priority if connected to a medial Bah | |
| 2040 | - //if (strpos('0FE8E 0FE94 0FEA2 0FEAA 0FEC2 0FEDA 0FEDE 0FB93 0FECA 0FED2 0FED6 0FEEE', $variants[1])===false) { // not already included | |
| 2041 | - $finals .= $variants[1].' '; | |
| 2042 | - } | |
| 2043 | - } | |
| 2044 | - } | |
| 2045 | -//echo $finals ; exit; | |
| 2046 | -//print_r($rtlpua); exit; | |
| 2047 | - ksort($rtl); | |
| 2048 | - $a = var_export($rtl, true); | |
| 2049 | - $a = preg_replace('/\\\\\\\\/',"\\",$a); | |
| 2050 | - $a = preg_replace('/\'/','"',$a); | |
| 2051 | - $a = preg_replace('/\r/','',$a); | |
| 2052 | - $a = preg_replace('/> \n/','>',$a); | |
| 2053 | - $a = preg_replace('/\n \)/',')',$a); | |
| 2054 | - $a= preg_replace('/\n /',' ',$a); | |
| 2055 | - $a = preg_replace('/\[IGNORE(\d+)\]/','".$ignore[\\1]."',$a); | |
| 2056 | - $rtlSUB = preg_replace('/[ ]+/',' ',$a); | |
| 2057 | - | |
| 2058 | - } | |
| 2059 | - //===================================================================================== | |
| 2060 | - // INDIC - Dynamic properties | |
| 2061 | - //===================================================================================== | |
| 2062 | - $rphf = array(); | |
| 2063 | - $half = array(); | |
| 2064 | - $pref = array(); | |
| 2065 | - $blwf = array(); | |
| 2066 | - $pstf = array(); | |
| 2067 | - if (strpos('dev2 bng2 gur2 gjr2 ory2 tml2 tel2 knd2 mlm2 deva beng guru gujr orya taml telu knda mlym', $st)!==false) { // all INDIC scripts [any/all languages] | |
| 2068 | - | |
| 2069 | - if (strpos('deva beng guru gujr orya taml telu knda mlym', $st)!==false) { $is_old_spec = true; } | |
| 2070 | - else { $is_old_spec = false; } | |
| 2071 | - | |
| 2072 | - // First get 'locl' substitutions (reversed!) | |
| 2073 | - $loclsubs = array(); | |
| 2074 | - foreach($volt AS $v) { | |
| 2075 | - if (strpos('locl',$v['tag'])!==false) { | |
| 2076 | - $key = $v['match']; | |
| 2077 | - $key = preg_replace('/[\(\)]*/','',$key); | |
| 2078 | - $sub = $v['replace']; | |
| 2079 | - if ($key && strlen(trim($key))==5 && $sub) { $loclsubs[$sub] = $key; } | |
| 2080 | - } | |
| 2081 | - } | |
| 2082 | -//if (count($loclsubs)) { print_r($loclsubs); exit; } | |
| 2083 | - | |
| 2084 | - foreach($volt AS $v) { | |
| 2085 | - // <rphf> <half> <pref> <blwf> <pstf> | |
| 2086 | - // defines consonant types: | |
| 2087 | - // Reph <rphf> | |
| 2088 | - // Half forms <half> | |
| 2089 | - // Pre-base-reordering forms of Ra/Rra <pref> | |
| 2090 | - // Below-base forms <blwf> | |
| 2091 | - // Post-base forms <pstf> | |
| 2092 | - | |
| 2093 | - // applied together with <locl> feature to input sequences consisting of two characters | |
| 2094 | - // This is done for each consonant | |
| 2095 | - // for <rphf> and <half>, features are applied to Consonant + Halant combinations | |
| 2096 | - // for <pref>, <blwf> and <pstf>, features are applied to Halant + Consonant combinations | |
| 2097 | - // Old version eg 'deva' <pref>, <blwf> and <pstf>, features are applied to Consonant + Halant | |
| 2098 | - // Some malformed fonts still do Consonant + Halant for these - so match both?? | |
| 2099 | - // If these two glyphs form a ligature, with no additional glyphs in context | |
| 2100 | - // this means the consonant has the corresponding form | |
| 2101 | - | |
| 2102 | - // Currently set to cope with both | |
| 2103 | - // See also classes/otl.php | |
| 2104 | - | |
| 2105 | - if (strpos('rphf half pref blwf pstf',$v['tag'])!==false) { | |
| 2106 | - if (isset($v['context']) && $v['context'] && $v['nBacktrack']==0 && $v['nLookahead']==0) { | |
| 2107 | - foreach($v['rules'] AS $vs) { | |
| 2108 | - if (count($vs['match'])==2 && count($vs['replace'])==1) { | |
| 2109 | - $sub = $vs['replace'][0]; | |
| 2110 | - // If Halant Cons <pref>, <blwf> and <pstf> in New version only | |
| 2111 | - if (strpos('0094D 009CD 00A4D 00ACD 00B4D 00BCD 00C4D 00CCD 00D4D',$vs['match'][0])!==false && strpos('pref blwf pstf',$v['tag'])!==false && !$is_old_spec ) { | |
| 2112 | - $key = $vs['match'][1]; | |
| 2113 | - $tag = $v['tag']; | |
| 2114 | - if (isset($loclsubs[$key])) { | |
| 2115 | - $$tag[$loclsubs[$key]] = $sub; | |
| 2116 | - } | |
| 2117 | - $tmp = &$$tag; | |
| 2118 | - $tmp[hexdec($key)] = hexdec($sub); | |
| 2119 | - } | |
| 2120 | - // If Cons Halant <rphf> and <half> always | |
| 2121 | - // and <pref>, <blwf> and <pstf> in Old version | |
| 2122 | - else if (strpos('0094D 009CD 00A4D 00ACD 00B4D 00BCD 00C4D 00CCD 00D4D',$vs['match'][1])!==false && (strpos('rphf half',$v['tag'])!==false || (strpos('pref blwf pstf',$v['tag'])!==false && ($is_old_spec || _OTL_OLD_SPEC_COMPAT_2)))) { | |
| 2123 | - $key = $vs['match'][0]; | |
| 2124 | - $tag = $v['tag']; | |
| 2125 | - if (isset($loclsubs[$key])) { | |
| 2126 | - $$tag[$loclsubs[$key]] = $sub; | |
| 2127 | - } | |
| 2128 | - $tmp = &$$tag; | |
| 2129 | - $tmp[hexdec($key)] = hexdec($sub); | |
| 2130 | - } | |
| 2131 | - } | |
| 2132 | - } | |
| 2133 | - } | |
| 2134 | - else if (!isset($v['context'])) { | |
| 2135 | - $key = $v['match']; | |
| 2136 | - $key = preg_replace('/[\(\)]*/','',$key); | |
| 2137 | - $sub = $v['replace']; | |
| 2138 | - if ($key && strlen(trim($key))==11 && $sub) { | |
| 2139 | - // If Cons Halant <rphf> and <half> always | |
| 2140 | - // and <pref>, <blwf> and <pstf> in Old version | |
| 2141 | - // If Halant Cons <pref>, <blwf> and <pstf> in New version only | |
| 2142 | - if (strpos('0094D 009CD 00A4D 00ACD 00B4D 00BCD 00C4D 00CCD 00D4D',substr($key, 0, 5))!==false && strpos('pref blwf pstf',$v['tag'])!==false && !$is_old_spec ) { | |
| 2143 | - $key = substr($key, 6, 5); | |
| 2144 | - $tag = $v['tag']; | |
| 2145 | - if (isset($loclsubs[$key])) { | |
| 2146 | - $$tag[$loclsubs[$key]] = $sub; | |
| 2147 | - } | |
| 2148 | - $tmp = &$$tag; | |
| 2149 | - $tmp[hexdec($key)] = hexdec($sub); | |
| 2150 | - } | |
| 2151 | - else if (strpos('0094D 009CD 00A4D 00ACD 00B4D 00BCD 00C4D 00CCD 00D4D',substr($key, 6, 5))!==false && (strpos('rphf half',$v['tag'])!==false || (strpos('pref blwf pstf',$v['tag'])!==false && ($is_old_spec || _OTL_OLD_SPEC_COMPAT_2)))) { | |
| 2152 | - $key = substr($key, 0, 5); | |
| 2153 | - $tag = $v['tag']; | |
| 2154 | - if (isset($loclsubs[$key])) { | |
| 2155 | - $$tag[$loclsubs[$key]] = $sub; | |
| 2156 | - } | |
| 2157 | - $tmp= &$$tag; | |
| 2158 | - $tmp[hexdec($key)] = hexdec($sub); | |
| 2159 | - } | |
| 2160 | - } | |
| 2161 | - } | |
| 2162 | - } | |
| 2163 | - } | |
| 2164 | -/* | |
| 2165 | -print_r($rphf ); | |
| 2166 | -print_r($half ); | |
| 2167 | -print_r($pref ); | |
| 2168 | -print_r($blwf ); | |
| 2169 | -print_r($pstf ); exit; | |
| 2170 | -*/ | |
| 2171 | - | |
| 2172 | - } | |
| 2173 | -//print_r($rtlpua); exit; | |
| 2174 | - //===================================================================================== | |
| 2175 | - //===================================================================================== | |
| 2176 | - //===================================================================================== | |
| 2177 | - //===================================================================================== | |
| 2178 | - if (count($rtl) || count($rphf ) || count($half ) || count($pref ) || count($blwf ) || count($pstf ) || $finals) { | |
| 2179 | - // SAVE LOOKUPS TO FILE fontname.GSUB.scripttag.langtag.php | |
| 2180 | - | |
| 2181 | - | |
| 2182 | - $s = '<?php | |
| 2183 | - | |
| 2184 | -$rtlSUB = '.$rtlSUB.'; | |
| 2185 | -$finals = \''.$finals.'\'; | |
| 2186 | -$rphf = '.var_export($rphf , true).'; | |
| 2187 | -$half = '.var_export($half , true).'; | |
| 2188 | -$pref = '.var_export($pref , true).'; | |
| 2189 | -$blwf = '.var_export($blwf , true).'; | |
| 2190 | -$pstf = '.var_export($pstf , true).'; | |
| 2191 | - | |
| 2192 | - '."\n".'?>'; | |
| 2193 | - | |
| 2194 | - | |
| 2195 | - file_put_contents(_MPDF_TTFONTDATAPATH.$this->fontkey.'.GSUB.'.$st.'.'.$t.'.php', $s); | |
| 2196 | - | |
| 2197 | - } | |
| 2198 | - //===================================================================================== | |
| 2199 | - if (!isset($GSUBScriptLang[$st])) { $GSUBScriptLang[$st] = ''; } | |
| 2200 | - $GSUBScriptLang[$st] .= $t.' '; | |
| 2201 | - //===================================================================================== | |
| 2202 | - | |
| 2203 | - } | |
| 2204 | - } | |
| 2205 | - //print_r($rtlpua); exit; | |
| 2206 | - | |
| 2207 | - // All RTL glyphs from font added to (or already in) PUA [reqd for magic_reverse] | |
| 2208 | - $rtlPUAstr = ""; | |
| 2209 | - if (count($rtlpua)) { | |
| 2210 | - $rtlpua = array_unique($rtlpua); | |
| 2211 | - sort($rtlpua); | |
| 2212 | - $n = count($rtlpua); | |
| 2213 | - for($i=0;$i<$n;$i++) { | |
| 2214 | - if (hexdec($rtlpua[$i])<hexdec('E000') || hexdec($rtlpua[$i])>hexdec('F8FF')) { | |
| 2215 | - unset($rtlpua[$i]); | |
| 2216 | - } | |
| 2217 | - } | |
| 2218 | - sort($rtlpua, SORT_STRING); | |
| 2219 | - | |
| 2220 | - $rangeid = -1; | |
| 2221 | - $range = array(); | |
| 2222 | - $prevgid = -2; | |
| 2223 | - // for each character | |
| 2224 | - foreach ($rtlpua as $gidhex) { | |
| 2225 | - $gid = hexdec($gidhex); | |
| 2226 | - if ($gid == ($prevgid + 1)) { | |
| 2227 | - $range[$rangeid]['end'] = $gidhex; | |
| 2228 | - $range[$rangeid]['count']++; | |
| 2229 | - } else { | |
| 2230 | - // new range | |
| 2231 | - $rangeid++; | |
| 2232 | - $range[$rangeid] = array(); | |
| 2233 | - $range[$rangeid]['start'] = $gidhex; | |
| 2234 | - $range[$rangeid]['end'] = $gidhex; | |
| 2235 | - $range[$rangeid]['count'] = 1; | |
| 2236 | - } | |
| 2237 | - $prevgid = $gid; | |
| 2238 | - } | |
| 2239 | - foreach($range AS $rg) { | |
| 2240 | - if ($rg['count'] == 1) { $rtlPUAstr .= "\x{".$rg['start']."}"; } | |
| 2241 | - else if ($rg['count'] == 2) { $rtlPUAstr .= "\x{".$rg['start']."}\x{".$rg['end']."}"; } | |
| 2242 | - else { $rtlPUAstr .= "\x{".$rg['start']."}-\x{".$rg['end']."}"; } | |
| 2243 | - | |
| 2244 | - } | |
| 2245 | - } | |
| 2246 | - | |
| 2247 | - //print_r($rtlPUAstr ); exit; | |
| 2248 | - | |
| 2249 | - | |
| 2250 | - //===================================================================================== | |
| 2251 | - //===================================================================================== | |
| 2252 | - //===================================================================================== | |
| 2253 | - //===================================================================================== | |
| 2254 | - //print_r($rtlpua); exit; | |
| 2255 | - //print_r($GSUBScriptLang); exit; | |
| 2256 | - | |
| 2257 | - | |
| 2258 | - | |
| 2259 | - } | |
| 2260 | -//print_r($Lookup); exit; | |
| 2261 | - | |
| 2262 | - return array($GSUBScriptLang, $gsub, $GSLookup, $rtlPUAstr); // , $rtlPUAarr Not needed | |
| 2263 | - | |
| 2264 | - } | |
| 2265 | 750 | ///////////////////////////////////////////////////////////////////////////////////////// |
| 2266 | - // GSUB functions | |
| 2267 | - function _getGSUBarray(&$Lookup, &$lul, $scripttag) { | |
| 2268 | - // Process (3) LookupList for specific Script-LangSys | |
| 2269 | - // Generate preg_replace | |
| 2270 | - $volt = array(); | |
| 2271 | - $reph = ''; | |
| 2272 | - $matraE = ''; | |
| 2273 | - $vatu = ''; | |
| 2274 | - foreach($lul AS $i=>$tag) { | |
| 2275 | - for ($c=0;$c<$Lookup[$i]['SubtableCount'] ;$c++) { | |
| 2276 | 751 | |
| 2277 | - $SubstFormat= $Lookup[$i]['Subtable'][$c]['Format'] ; | |
| 2278 | 752 | |
| 2279 | - // LookupType 1: Single Substitution Subtable | |
| 2280 | - if ($Lookup[$i]['Type'] == 1) { | |
| 2281 | - for ($s=0;$s<count($Lookup[$i]['Subtable'][$c]['subs']);$s++) { | |
| 2282 | - $inputGlyphs = $Lookup[$i]['Subtable'][$c]['subs'][$s]['Replace']; | |
| 2283 | - $substitute = $Lookup[$i]['Subtable'][$c]['subs'][$s]['substitute'][0]; | |
| 2284 | - // Ignore has already been applied earlier on | |
| 2285 | - $repl = $this->_makeGSUBinputMatch($inputGlyphs, "()"); | |
| 2286 | - $subs = $this->_makeGSUBinputReplacement(1, $substitute, "()", 0, 1, 0); | |
| 2287 | - $volt[] = array('match'=>$repl, 'replace'=>$subs, 'tag'=>$tag, 'key'=>$inputGlyphs[0], 'type' => 1); | |
| 2288 | - } | |
| 2289 | - } | |
| 2290 | - // LookupType 2: Multiple Substitution Subtable | |
| 2291 | - else if ($Lookup[$i]['Type'] == 2) { | |
| 2292 | - for ($s=0;$s<count($Lookup[$i]['Subtable'][$c]['subs']);$s++) { | |
| 2293 | - $inputGlyphs = $Lookup[$i]['Subtable'][$c]['subs'][$s]['Replace']; | |
| 2294 | - $substitute = implode(" ", $Lookup[$i]['Subtable'][$c]['subs'][$s]['substitute']); | |
| 2295 | - // Ignore has already been applied earlier on | |
| 2296 | - $repl = $this->_makeGSUBinputMatch($inputGlyphs,"()"); | |
| 2297 | - $subs = $this->_makeGSUBinputReplacement(1, $substitute, "()", 0, 1, 0); | |
| 2298 | - $volt[] = array('match'=>$repl, 'replace'=>$subs, 'tag'=>$tag, 'key'=>$inputGlyphs[0], 'type' => 2); | |
| 2299 | - } | |
| 2300 | - } | |
| 2301 | - // LookupType 3: Alternate Forms | |
| 2302 | - else if ($Lookup[$i]['Type'] == 3) { | |
| 2303 | - for ($s=0;$s<count($Lookup[$i]['Subtable'][$c]['subs']);$s++) { | |
| 2304 | - $inputGlyphs = $Lookup[$i]['Subtable'][$c]['subs'][$s]['Replace']; | |
| 2305 | - $substitute = $Lookup[$i]['Subtable'][$c]['subs'][$s]['substitute'][0]; | |
| 2306 | - // Ignore has already been applied earlier on | |
| 2307 | - $repl = $this->_makeGSUBinputMatch($inputGlyphs, "()"); | |
| 2308 | - $subs = $this->_makeGSUBinputReplacement(1, $substitute, "()", 0, 1, 0); | |
| 2309 | - $volt[] = array('match'=>$repl, 'replace'=>$subs, 'tag'=>$tag, 'key'=>$inputGlyphs[0], 'type' => 3); | |
| 2310 | - } | |
| 2311 | - } | |
| 2312 | - // LookupType 4: Ligature Substitution Subtable | |
| 2313 | - else if ($Lookup[$i]['Type'] == 4) { | |
| 2314 | - for ($s=0;$s<count($Lookup[$i]['Subtable'][$c]['subs']);$s++) { | |
| 2315 | - $inputGlyphs = $Lookup[$i]['Subtable'][$c]['subs'][$s]['Replace']; | |
| 2316 | - $substitute = $Lookup[$i]['Subtable'][$c]['subs'][$s]['substitute'][0]; | |
| 2317 | - // Ignore has already been applied earlier on | |
| 2318 | - $ignore = $this->_getGSUBignoreString($Lookup[$i]['Flag'], $Lookup[$i]['MarkFilteringSet']); | |
| 2319 | - $repl = $this->_makeGSUBinputMatch($inputGlyphs, $ignore); | |
| 2320 | - $subs = $this->_makeGSUBinputReplacement(count($inputGlyphs), $substitute, $ignore, 0, count($inputGlyphs), 0); | |
| 2321 | - $volt[] = array('match'=>$repl, 'replace'=>$subs, 'tag'=>$tag, 'key'=>$inputGlyphs[0], 'type' => 4, 'CompCount' => $Lookup[$i]['Subtable'][$c]['subs'][$s]['CompCount'], 'Lig' => $substitute); | |
| 2322 | - } | |
| 2323 | - } | |
| 2324 | - | |
| 2325 | - // LookupType 5: Chaining Contextual Substitution Subtable | |
| 2326 | - else if ($Lookup[$i]['Type'] == 5) { | |
| 2327 | - // Format 1: Context Substitution | |
| 2328 | - if ($SubstFormat==1) { | |
| 2329 | - $ignore = $this->_getGSUBignoreString($Lookup[$i]['Flag'], $Lookup[$i]['MarkFilteringSet']); | |
| 2330 | - for($s=0;$s<$Lookup[$i]['Subtable'][$c]['SubRuleSetCount'];$s++) { | |
| 2331 | - // SubRuleSet | |
| 2332 | -$subRule = array(); | |
| 2333 | - foreach($Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['SubRule'] AS $rule) { | |
| 2334 | - // SubRule | |
| 2335 | - $inputGlyphs = array(); | |
| 2336 | - if ($rule['GlyphCount']>1) { | |
| 2337 | - $inputGlyphs = $rule['InputGlyphs']; | |
| 2338 | - } | |
| 2339 | - $inputGlyphs[0] = $Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['FirstGlyph']; | |
| 2340 | - ksort($inputGlyphs); | |
| 2341 | - $nInput = count($inputGlyphs); | |
| 2342 | - | |
| 2343 | - $contextInputMatch = $this->_makeGSUBcontextInputMatch($inputGlyphs, $ignore, array(), 0); | |
| 2344 | - $subRule = array('context' => 1, 'tag' => $tag, 'matchback' => '', 'match' => $contextInputMatch, 'nBacktrack' => 0, 'nInput' => $nInput, 'nLookahead' => 0, 'rules' => array(), ); | |
| 2345 | - | |
| 2346 | - for ($b=0;$b<$rule['SubstCount'];$b++) { | |
| 2347 | - $lup = $rule['SubstLookupRecord'][$b]['LookupListIndex']; | |
| 2348 | - $seqIndex = $rule['SubstLookupRecord'][$b]['SequenceIndex']; | |
| 2349 | - | |
| 2350 | - // $Lookup[$lup] = secondary Lookup | |
| 2351 | - for($lus=0;$lus<$Lookup[$lup]['SubtableCount'];$lus++) { | |
| 2352 | - if (count($Lookup[$lup]['Subtable'][$lus]['subs'])) { | |
| 2353 | - foreach($Lookup[$lup]['Subtable'][$lus]['subs'] AS $luss) { | |
| 2354 | - | |
| 2355 | - $lookupGlyphs = $luss['Replace']; | |
| 2356 | - $mLen = count($lookupGlyphs); | |
| 2357 | - | |
| 2358 | - // Only apply if the (first) 'Replace' glyph from the | |
| 2359 | - // Lookup list is in the [inputGlyphs] at ['SequenceIndex'] | |
| 2360 | - // then apply the substitution | |
| 2361 | - if (strpos($inputGlyphs[$seqIndex],$lookupGlyphs[0])===false) { continue; } | |
| 2362 | - $REPL = implode(" ",$luss['substitute']); | |
| 2363 | - if (strpos("isol fina fin2 fin3 medi med2 init ",$tag)!==false && $scripttag=='arab') { | |
| 2364 | - $volt[] = array('match'=>$lookupGlyphs[0], 'replace'=>$REPL, 'tag'=>$tag, 'prel'=>$backtrackGlyphs, 'postl'=>$lookaheadGlyphs, 'ignore'=>$ignore); | |
| 2365 | - } | |
| 2366 | - else { | |
| 2367 | - $subRule['rules'][] = array('type' => $Lookup[$lup]['Type'], 'match' => $lookupGlyphs, 'replace' => $luss['substitute'], 'seqIndex' => $seqIndex, 'key' => $lookupGlyphs[0], ); | |
| 2368 | - } | |
| 2369 | - } | |
| 2370 | - } | |
| 2371 | - } | |
| 2372 | - } | |
| 2373 | - | |
| 2374 | - | |
| 2375 | - if (count($subRule['rules'])) $volt[] = $subRule; | |
| 2376 | - | |
| 2377 | - } | |
| 2378 | - } | |
| 2379 | - } | |
| 2380 | - // Format 2: Class-based Context Glyph Substitution | |
| 2381 | - else if ($SubstFormat==2) { | |
| 2382 | - $ignore = $this->_getGSUBignoreString($Lookup[$i]['Flag'], $Lookup[$i]['MarkFilteringSet']); | |
| 2383 | - foreach($Lookup[$i]['Subtable'][$c]['SubClassSet'] AS $inputClass=>$cscs) { | |
| 2384 | - for($cscrule=0;$cscrule<$cscs['SubClassRuleCnt'];$cscrule++) { | |
| 2385 | - $rule = $cscs['SubClassRule'][$cscrule]; | |
| 2386 | - | |
| 2387 | - $inputGlyphs = array(); | |
| 2388 | - | |
| 2389 | - $inputGlyphs[0] = $Lookup[$i]['Subtable'][$c]['InputClasses'][$inputClass]; | |
| 2390 | - if ($rule['InputGlyphCount']>1) { | |
| 2391 | - // NB starts at 1 | |
| 2392 | - for ($gcl=1;$gcl<$rule['InputGlyphCount'];$gcl++) { | |
| 2393 | - $classindex = $rule['Input'][$gcl]; | |
| 2394 | - if (isset($Lookup[$i]['Subtable'][$c]['InputClasses'][$classindex])) { | |
| 2395 | - $inputGlyphs[$gcl] = $Lookup[$i]['Subtable'][$c]['InputClasses'][$classindex]; | |
| 2396 | - } | |
| 2397 | - // if class[0] = all glyphs excluding those specified in all other classes | |
| 2398 | - // set to blank '' for now | |
| 2399 | - else { $inputGlyphs[$gcl] = ''; } | |
| 2400 | - } | |
| 2401 | - } | |
| 2402 | - | |
| 2403 | - $nInput = $rule['InputGlyphCount']; | |
| 2404 | - | |
| 2405 | - $nIsubs = (2*$nInput)-1; | |
| 2406 | - | |
| 2407 | - $contextInputMatch = $this->_makeGSUBcontextInputMatch($inputGlyphs, $ignore, array(), 0); | |
| 2408 | - $subRule = array('context' => 1, 'tag' => $tag, 'matchback' => '', 'match' => $contextInputMatch, 'nBacktrack' => 0, 'nInput' => $nInput, 'nLookahead' => 0, 'rules' => array(), ); | |
| 2409 | - | |
| 2410 | - for ($b=0;$b<$rule['SubstCount'];$b++) { | |
| 2411 | - $lup = $rule['LookupListIndex'][$b]; | |
| 2412 | - $seqIndex = $rule['SequenceIndex'][$b]; | |
| 2413 | - | |
| 2414 | - // $Lookup[$lup] = secondary Lookup | |
| 2415 | - for($lus=0;$lus<$Lookup[$lup]['SubtableCount'];$lus++) { | |
| 2416 | - if (isset($Lookup[$lup]['Subtable'][$lus]['subs']) && count($Lookup[$lup]['Subtable'][$lus]['subs'])) { | |
| 2417 | - foreach($Lookup[$lup]['Subtable'][$lus]['subs'] AS $luss) { | |
| 2418 | - | |
| 2419 | - $lookupGlyphs = $luss['Replace']; | |
| 2420 | - $mLen = count($lookupGlyphs); | |
| 2421 | - | |
| 2422 | - // Only apply if the (first) 'Replace' glyph from the | |
| 2423 | - // Lookup list is in the [inputGlyphs] at ['SequenceIndex'] | |
| 2424 | - // then apply the substitution | |
| 2425 | - if (strpos($inputGlyphs[$seqIndex],$lookupGlyphs[0])===false) { continue; } | |
| 2426 | - | |
| 2427 | - // Returns e.g. �(0612)�(ignore) (0613)�(ignore) (0614)� | |
| 2428 | - $contextInputMatch = $this->_makeGSUBcontextInputMatch($inputGlyphs, $ignore, $lookupGlyphs, $seqIndex); | |
| 2429 | - $REPL = implode(" ",$luss['substitute']); | |
| 2430 | - // Returns e.g. "REPL\${6}\${8}" or "\${1}\${2} \${3} REPL\${4}\${6}\${8} \${9}" | |
| 2431 | - | |
| 2432 | - if (strpos("isol fina fin2 fin3 medi med2 init ",$tag)!==false && $scripttag=='arab') { | |
| 2433 | - $volt[] = array('match'=>$lookupGlyphs[0], 'replace'=>$REPL, 'tag'=>$tag, 'prel'=>$backtrackGlyphs, 'postl'=>$lookaheadGlyphs, 'ignore'=>$ignore); | |
| 2434 | - } | |
| 2435 | - else { | |
| 2436 | - $subRule['rules'][] = array('type' => $Lookup[$lup]['Type'], 'match' => $lookupGlyphs, 'replace' => $luss['substitute'], 'seqIndex' => $seqIndex, 'key' => $lookupGlyphs[0], ); | |
| 2437 | - } | |
| 2438 | - } | |
| 2439 | - } | |
| 2440 | - } | |
| 2441 | - } | |
| 2442 | - if (count($subRule['rules'])) $volt[] = $subRule; | |
| 2443 | - | |
| 2444 | - } | |
| 2445 | - } | |
| 2446 | - | |
| 2447 | - | |
| 2448 | - | |
| 2449 | - } | |
| 2450 | - // Format 3: Coverage-based Context Glyph Substitution p259 | |
| 2451 | - else if ($SubstFormat==3) { | |
| 2452 | - // IgnoreMarks flag set on main Lookup table | |
| 2453 | - $ignore = $this->_getGSUBignoreString($Lookup[$i]['Flag'], $Lookup[$i]['MarkFilteringSet']); | |
| 2454 | - $inputGlyphs = $Lookup[$i]['Subtable'][$c]['CoverageInputGlyphs']; | |
| 2455 | - $CoverageInputGlyphs = implode('|', $inputGlyphs); | |
| 2456 | - $nInput = $Lookup[$i]['Subtable'][$c]['InputGlyphCount']; | |
| 2457 | - | |
| 2458 | - if ($Lookup[$i]['Subtable'][$c]['BacktrackGlyphCount']) { | |
| 2459 | - $backtrackGlyphs = $Lookup[$i]['Subtable'][$c]['CoverageBacktrackGlyphs']; | |
| 2460 | - } | |
| 2461 | - else { $backtrackGlyphs = array(); } | |
| 2462 | - // Returns e.g. �(FEEB|FEEC)(ignore) �(FD12|FD13)(ignore) � | |
| 2463 | - $backtrackMatch = $this->_makeGSUBbacktrackMatch($backtrackGlyphs, $ignore); | |
| 2464 | - | |
| 2465 | - if ($Lookup[$i]['Subtable'][$c]['LookaheadGlyphCount']) { | |
| 2466 | - $lookaheadGlyphs = $Lookup[$i]['Subtable'][$c]['CoverageLookaheadGlyphs']; | |
| 2467 | - } | |
| 2468 | - else { $lookaheadGlyphs = array(); } | |
| 2469 | - // Returns e.g. �(ignore) (FD12|FD13)�(ignore) (FEEB|FEEC)� | |
| 2470 | - $lookaheadMatch = $this->_makeGSUBlookaheadMatch($lookaheadGlyphs, $ignore); | |
| 2471 | - | |
| 2472 | - $nBsubs = 2*count($backtrackGlyphs); | |
| 2473 | - $nIsubs = (2*$nInput)-1; | |
| 2474 | - $contextInputMatch = $this->_makeGSUBcontextInputMatch($inputGlyphs, $ignore, array(), 0); | |
| 2475 | - $subRule = array('context' => 1, 'tag' => $tag, 'matchback' => $backtrackMatch, 'match' => ($contextInputMatch . $lookaheadMatch), 'nBacktrack' => count($backtrackGlyphs), 'nInput' => $nInput, 'nLookahead' => count($lookaheadGlyphs), 'rules' => array(), ); | |
| 2476 | - | |
| 2477 | - for ($b=0;$b<$Lookup[$i]['Subtable'][$c]['SubstCount'];$b++) { | |
| 2478 | - $lup = $Lookup[$i]['Subtable'][$c]['SubstLookupRecord'][$b]['LookupListIndex']; | |
| 2479 | - $seqIndex = $Lookup[$i]['Subtable'][$c]['SubstLookupRecord'][$b]['SequenceIndex']; | |
| 2480 | - for($lus=0;$lus<$Lookup[$lup]['SubtableCount'];$lus++) { | |
| 2481 | - if (count($Lookup[$lup]['Subtable'][$lus]['subs'])) { | |
| 2482 | - foreach($Lookup[$lup]['Subtable'][$lus]['subs'] AS $luss) { | |
| 2483 | - $lookupGlyphs = $luss['Replace']; | |
| 2484 | - $mLen = count($lookupGlyphs); | |
| 2485 | - | |
| 2486 | - // Only apply if the (first) 'Replace' glyph from the | |
| 2487 | - // Lookup list is in the [inputGlyphs] at ['SequenceIndex'] | |
| 2488 | - // then apply the substitution | |
| 2489 | - if (strpos($inputGlyphs[$seqIndex],$lookupGlyphs[0])===false) { continue; } | |
| 2490 | - | |
| 2491 | - // Returns e.g. �(0612)�(ignore) (0613)�(ignore) (0614)� | |
| 2492 | - $contextInputMatch = $this->_makeGSUBcontextInputMatch($inputGlyphs, $ignore, $lookupGlyphs, $seqIndex); | |
| 2493 | - $REPL = implode(" ",$luss['substitute']); | |
| 2494 | - | |
| 2495 | - if (strpos("isol fina fin2 fin3 medi med2 init ",$tag)!==false && $scripttag=='arab') { | |
| 2496 | - $volt[] = array('match'=>$lookupGlyphs[0], 'replace'=>$REPL, 'tag'=>$tag, 'prel'=>$backtrackGlyphs, 'postl'=>$lookaheadGlyphs, 'ignore'=>$ignore); | |
| 2497 | - } | |
| 2498 | - else { | |
| 2499 | - $subRule['rules'][] = array('type' => $Lookup[$lup]['Type'], 'match' => $lookupGlyphs, 'replace' => $luss['substitute'], 'seqIndex' => $seqIndex, 'key' => $lookupGlyphs[0], ); | |
| 2500 | - } | |
| 2501 | - } | |
| 2502 | - } | |
| 2503 | - } | |
| 2504 | - } | |
| 2505 | - if (count($subRule['rules'])) $volt[] = $subRule; | |
| 2506 | - } | |
| 2507 | - | |
| 2508 | -//print_r($Lookup[$i]); | |
| 2509 | -//print_r($volt[(count($volt)-1)]); exit; | |
| 2510 | - } | |
| 2511 | - // LookupType 6: ing Contextual Substitution Subtable | |
| 2512 | - else if ($Lookup[$i]['Type'] == 6) { | |
| 2513 | - // Format 1: Simple Chaining Context Glyph Substitution p255 | |
| 2514 | - if ($SubstFormat==1) { | |
| 2515 | - $ignore = $this->_getGSUBignoreString($Lookup[$i]['Flag'], $Lookup[$i]['MarkFilteringSet']); | |
| 2516 | - for($s=0;$s<$Lookup[$i]['Subtable'][$c]['ChainSubRuleSetCount'];$s++) { | |
| 2517 | - // ChainSubRuleSet | |
| 2518 | - $subRule = array(); | |
| 2519 | - $firstInputGlyph = $Lookup[$i]['Subtable'][$c]['CoverageGlyphs'][$s]; // First input gyyph | |
| 2520 | - foreach($Lookup[$i]['Subtable'][$c]['ChainSubRuleSet'][$s]['ChainSubRule'] AS $rule) { | |
| 2521 | - // ChainSubRule | |
| 2522 | - $inputGlyphs = array(); | |
| 2523 | - if ($rule['InputGlyphCount']>1) { | |
| 2524 | - $inputGlyphs = $rule['InputGlyphs']; | |
| 2525 | - } | |
| 2526 | - $inputGlyphs[0] = $firstInputGlyph; | |
| 2527 | - ksort($inputGlyphs); | |
| 2528 | - $nInput = count($inputGlyphs); | |
| 2529 | - | |
| 2530 | - if ($rule['BacktrackGlyphCount']) { $backtrackGlyphs = $rule['BacktrackGlyphs']; } | |
| 2531 | - else { $backtrackGlyphs = array(); } | |
| 2532 | - $backtrackMatch = $this->_makeGSUBbacktrackMatch($backtrackGlyphs, $ignore); | |
| 2533 | - | |
| 2534 | - if ($rule['LookaheadGlyphCount']) { $lookaheadGlyphs = $rule['LookaheadGlyphs']; } | |
| 2535 | - else { $lookaheadGlyphs = array(); } | |
| 2536 | - | |
| 2537 | - $lookaheadMatch = $this->_makeGSUBlookaheadMatch($lookaheadGlyphs, $ignore); | |
| 2538 | - | |
| 2539 | - $nBsubs = 2*count($backtrackGlyphs); | |
| 2540 | - $nIsubs = (2*$nInput)-1; | |
| 2541 | - | |
| 2542 | - $contextInputMatch = $this->_makeGSUBcontextInputMatch($inputGlyphs, $ignore, array(), 0); | |
| 2543 | - $subRule = array('context' => 1, 'tag' => $tag, 'matchback' => $backtrackMatch, 'match' => ($contextInputMatch . $lookaheadMatch), 'nBacktrack' => count($backtrackGlyphs), 'nInput' => $nInput, 'nLookahead' => count($lookaheadGlyphs), 'rules' => array(), ); | |
| 2544 | - | |
| 2545 | - | |
| 2546 | - for ($b=0;$b<$rule['SubstCount'];$b++) { | |
| 2547 | - $lup = $rule['LookupListIndex'][$b]; | |
| 2548 | - $seqIndex = $rule['SequenceIndex'][$b]; | |
| 2549 | - | |
| 2550 | - // $Lookup[$lup] = secondary Lookup | |
| 2551 | - for($lus=0;$lus<$Lookup[$lup]['SubtableCount'];$lus++) { | |
| 2552 | - if (count($Lookup[$lup]['Subtable'][$lus]['subs'])) { | |
| 2553 | - foreach($Lookup[$lup]['Subtable'][$lus]['subs'] AS $luss) { | |
| 2554 | - | |
| 2555 | - $lookupGlyphs = $luss['Replace']; | |
| 2556 | - $mLen = count($lookupGlyphs); | |
| 2557 | - | |
| 2558 | - // Only apply if the (first) 'Replace' glyph from the | |
| 2559 | - // Lookup list is in the [inputGlyphs] at ['SequenceIndex'] | |
| 2560 | - // then apply the substitution | |
| 2561 | - if (strpos($inputGlyphs[$seqIndex],$lookupGlyphs[0])===false) { continue; } | |
| 2562 | - | |
| 2563 | - // Returns e.g. �(0612)�(ignore) (0613)�(ignore) (0614)� | |
| 2564 | - $contextInputMatch = $this->_makeGSUBcontextInputMatch($inputGlyphs, $ignore, $lookupGlyphs, $seqIndex); | |
| 2565 | - | |
| 2566 | - $REPL = implode(" ",$luss['substitute']); | |
| 2567 | - | |
| 2568 | - if (strpos("isol fina fin2 fin3 medi med2 init ",$tag)!==false && $scripttag=='arab') { | |
| 2569 | - $volt[] = array('match'=>$lookupGlyphs[0], 'replace'=>$REPL, 'tag'=>$tag, 'prel'=>$backtrackGlyphs, 'postl'=>$lookaheadGlyphs, 'ignore'=>$ignore); | |
| 2570 | - } | |
| 2571 | - else { | |
| 2572 | - $subRule['rules'][] = array('type' => $Lookup[$lup]['Type'], 'match' => $lookupGlyphs, 'replace' => $luss['substitute'], 'seqIndex' => $seqIndex, 'key' => $lookupGlyphs[0], ); | |
| 2573 | - } | |
| 2574 | - } | |
| 2575 | - } | |
| 2576 | - } | |
| 2577 | - } | |
| 2578 | - | |
| 2579 | - | |
| 2580 | - if (count($subRule['rules'])) $volt[] = $subRule; | |
| 2581 | - | |
| 2582 | - | |
| 2583 | - | |
| 2584 | - } | |
| 2585 | - } | |
| 2586 | - | |
| 2587 | - } | |
| 2588 | - // Format 2: Class-based Chaining Context Glyph Substitution p257 | |
| 2589 | - else if ($SubstFormat==2) { | |
| 2590 | - $ignore = $this->_getGSUBignoreString($Lookup[$i]['Flag'], $Lookup[$i]['MarkFilteringSet']); | |
| 2591 | - foreach($Lookup[$i]['Subtable'][$c]['ChainSubClassSet'] AS $inputClass=>$cscs) { | |
| 2592 | - for($cscrule=0;$cscrule<$cscs['ChainSubClassRuleCnt'];$cscrule++) { | |
| 2593 | - $rule = $cscs['ChainSubClassRule'][$cscrule]; | |
| 2594 | - | |
| 2595 | - // These contain classes of glyphs as strings | |
| 2596 | - // $Lookup[$i]['Subtable'][$c]['InputClasses'][(class)] e.g. 02E6|02E7|02E8 | |
| 2597 | - // $Lookup[$i]['Subtable'][$c]['LookaheadClasses'][(class)] | |
| 2598 | - // $Lookup[$i]['Subtable'][$c]['BacktrackClasses'][(class)] | |
| 2599 | - | |
| 2600 | - // These contain arrays of classIndexes | |
| 2601 | - // [Backtrack] [Lookahead] and [Input] (Input is from the second position only) | |
| 2602 | - | |
| 2603 | - $inputGlyphs = array(); | |
| 2604 | - | |
| 2605 | - if (isset($Lookup[$i]['Subtable'][$c]['InputClasses'][$inputClass])) { | |
| 2606 | - $inputGlyphs[0] = $Lookup[$i]['Subtable'][$c]['InputClasses'][$inputClass]; | |
| 2607 | - } | |
| 2608 | - else { $inputGlyphs[0] = ''; } | |
| 2609 | - if ($rule['InputGlyphCount']>1) { | |
| 2610 | - // NB starts at 1 | |
| 2611 | - for ($gcl=1;$gcl<$rule['InputGlyphCount'];$gcl++) { | |
| 2612 | - $classindex = $rule['Input'][$gcl]; | |
| 2613 | - if (isset($Lookup[$i]['Subtable'][$c]['InputClasses'][$classindex])) { | |
| 2614 | - $inputGlyphs[$gcl] = $Lookup[$i]['Subtable'][$c]['InputClasses'][$classindex]; | |
| 2615 | - } | |
| 2616 | - // if class[0] = all glyphs excluding those specified in all other classes | |
| 2617 | - // set to blank '' for now | |
| 2618 | - else { $inputGlyphs[$gcl] = ''; } | |
| 2619 | - } | |
| 2620 | - } | |
| 2621 | - | |
| 2622 | - $nInput = $rule['InputGlyphCount']; | |
| 2623 | - | |
| 2624 | - if ($rule['BacktrackGlyphCount']) { | |
| 2625 | - for ($gcl=0;$gcl<$rule['BacktrackGlyphCount'];$gcl++) { | |
| 2626 | - $classindex = $rule['Backtrack'][$gcl]; | |
| 2627 | - if (isset($Lookup[$i]['Subtable'][$c]['BacktrackClasses'][$classindex])) { | |
| 2628 | - $backtrackGlyphs[$gcl] = $Lookup[$i]['Subtable'][$c]['BacktrackClasses'][$classindex]; | |
| 2629 | - } | |
| 2630 | - // if class[0] = all glyphs excluding those specified in all other classes | |
| 2631 | - // set to blank '' for now | |
| 2632 | - else { $backtrackGlyphs[$gcl] = ''; } | |
| 2633 | - } | |
| 2634 | - } | |
| 2635 | - else { $backtrackGlyphs = array(); } | |
| 2636 | - // Returns e.g. �(FEEB|FEEC)(ignore) �(FD12|FD13)(ignore) � | |
| 2637 | - $backtrackMatch = $this->_makeGSUBbacktrackMatch($backtrackGlyphs, $ignore); | |
| 2638 | - | |
| 2639 | - if ($rule['LookaheadGlyphCount']) { | |
| 2640 | - for ($gcl=0;$gcl<$rule['LookaheadGlyphCount'];$gcl++) { | |
| 2641 | - $classindex = $rule['Lookahead'][$gcl]; | |
| 2642 | - if (isset($Lookup[$i]['Subtable'][$c]['LookaheadClasses'][$classindex])) { | |
| 2643 | - $lookaheadGlyphs[$gcl] = $Lookup[$i]['Subtable'][$c]['LookaheadClasses'][$classindex]; | |
| 2644 | - } | |
| 2645 | - // if class[0] = all glyphs excluding those specified in all other classes | |
| 2646 | - // set to blank '' for now | |
| 2647 | - else { $lookaheadGlyphs[$gcl] = ''; } | |
| 2648 | - } | |
| 2649 | - } | |
| 2650 | - else { $lookaheadGlyphs = array(); } | |
| 2651 | - // Returns e.g. �(ignore) (FD12|FD13)�(ignore) (FEEB|FEEC)� | |
| 2652 | - $lookaheadMatch = $this->_makeGSUBlookaheadMatch($lookaheadGlyphs, $ignore); | |
| 2653 | - | |
| 2654 | - $nBsubs = 2*count($backtrackGlyphs); | |
| 2655 | - $nIsubs = (2*$nInput)-1; | |
| 2656 | - | |
| 2657 | - $contextInputMatch = $this->_makeGSUBcontextInputMatch($inputGlyphs, $ignore, array(), 0); | |
| 2658 | - $subRule = array('context' => 1, 'tag' => $tag, 'matchback' => $backtrackMatch, 'match' => ($contextInputMatch . $lookaheadMatch), 'nBacktrack' => count($backtrackGlyphs), 'nInput' => $nInput, 'nLookahead' => count($lookaheadGlyphs), 'rules' => array(), ); | |
| 2659 | - | |
| 2660 | - for ($b=0;$b<$rule['SubstCount'];$b++) { | |
| 2661 | - $lup = $rule['LookupListIndex'][$b]; | |
| 2662 | - $seqIndex = $rule['SequenceIndex'][$b]; | |
| 2663 | - | |
| 2664 | - // $Lookup[$lup] = secondary Lookup | |
| 2665 | - for($lus=0;$lus<$Lookup[$lup]['SubtableCount'];$lus++) { | |
| 2666 | - if (count($Lookup[$lup]['Subtable'][$lus]['subs'])) { | |
| 2667 | - foreach($Lookup[$lup]['Subtable'][$lus]['subs'] AS $luss) { | |
| 2668 | - | |
| 2669 | - $lookupGlyphs = $luss['Replace']; | |
| 2670 | - $mLen = count($lookupGlyphs); | |
| 2671 | - | |
| 2672 | - // Only apply if the (first) 'Replace' glyph from the | |
| 2673 | - // Lookup list is in the [inputGlyphs] at ['SequenceIndex'] | |
| 2674 | - // then apply the substitution | |
| 2675 | - if (strpos($inputGlyphs[$seqIndex],$lookupGlyphs[0])===false) { continue; } | |
| 2676 | - | |
| 2677 | - // Returns e.g. �(0612)�(ignore) (0613)�(ignore) (0614)� | |
| 2678 | - $contextInputMatch = $this->_makeGSUBcontextInputMatch($inputGlyphs, $ignore, $lookupGlyphs, $seqIndex); | |
| 2679 | - $REPL = implode(" ",$luss['substitute']); | |
| 2680 | - // Returns e.g. "REPL\${6}\${8}" or "\${1}\${2} \${3} REPL\${4}\${6}\${8} \${9}" | |
| 2681 | - | |
| 2682 | - if (strpos("isol fina fin2 fin3 medi med2 init ",$tag)!==false && $scripttag=='arab') { | |
| 2683 | - $volt[] = array('match'=>$lookupGlyphs[0], 'replace'=>$REPL, 'tag'=>$tag, 'prel'=>$backtrackGlyphs, 'postl'=>$lookaheadGlyphs, 'ignore'=>$ignore); | |
| 2684 | - } | |
| 2685 | - else { | |
| 2686 | - $subRule['rules'][] = array('type' => $Lookup[$lup]['Type'], 'match' => $lookupGlyphs, 'replace' => $luss['substitute'], 'seqIndex' => $seqIndex, 'key' => $lookupGlyphs[0], ); | |
| 2687 | - } | |
| 2688 | - } | |
| 2689 | - } | |
| 2690 | - } | |
| 2691 | - } | |
| 2692 | - if (count($subRule['rules'])) $volt[] = $subRule; | |
| 2693 | - | |
| 2694 | - } | |
| 2695 | - } | |
| 2696 | - | |
| 2697 | - | |
| 2698 | -//print_r($Lookup[$i]['Subtable'][$c]); exit; | |
| 2699 | - | |
| 2700 | - } | |
| 2701 | - // Format 3: Coverage-based Chaining Context Glyph Substitution p259 | |
| 2702 | - else if ($SubstFormat==3) { | |
| 2703 | - // IgnoreMarks flag set on main Lookup table | |
| 2704 | - $ignore = $this->_getGSUBignoreString($Lookup[$i]['Flag'], $Lookup[$i]['MarkFilteringSet']); | |
| 2705 | - $inputGlyphs = $Lookup[$i]['Subtable'][$c]['CoverageInputGlyphs']; | |
| 2706 | - $CoverageInputGlyphs = implode('|', $inputGlyphs); | |
| 2707 | - $nInput = $Lookup[$i]['Subtable'][$c]['InputGlyphCount']; | |
| 2708 | - | |
| 2709 | - if ($Lookup[$i]['Subtable'][$c]['BacktrackGlyphCount']) { | |
| 2710 | - $backtrackGlyphs = $Lookup[$i]['Subtable'][$c]['CoverageBacktrackGlyphs']; | |
| 2711 | - } | |
| 2712 | - else { $backtrackGlyphs = array(); } | |
| 2713 | - // Returns e.g. �(FEEB|FEEC)(ignore) �(FD12|FD13)(ignore) � | |
| 2714 | - $backtrackMatch = $this->_makeGSUBbacktrackMatch($backtrackGlyphs, $ignore); | |
| 2715 | - | |
| 2716 | - if ($Lookup[$i]['Subtable'][$c]['LookaheadGlyphCount']) { | |
| 2717 | - $lookaheadGlyphs = $Lookup[$i]['Subtable'][$c]['CoverageLookaheadGlyphs']; | |
| 2718 | - } | |
| 2719 | - else { $lookaheadGlyphs = array(); } | |
| 2720 | - // Returns e.g. �(ignore) (FD12|FD13)�(ignore) (FEEB|FEEC)� | |
| 2721 | - $lookaheadMatch = $this->_makeGSUBlookaheadMatch($lookaheadGlyphs, $ignore); | |
| 2722 | - | |
| 2723 | - $nBsubs = 2*count($backtrackGlyphs); | |
| 2724 | - $nIsubs = (2*$nInput)-1; | |
| 2725 | - $contextInputMatch = $this->_makeGSUBcontextInputMatch($inputGlyphs, $ignore, array(), 0); | |
| 2726 | - $subRule = array('context' => 1, 'tag' => $tag, 'matchback' => $backtrackMatch, 'match' => ($contextInputMatch . $lookaheadMatch), 'nBacktrack' => count($backtrackGlyphs), 'nInput' => $nInput, 'nLookahead' => count($lookaheadGlyphs), 'rules' => array(), ); | |
| 2727 | - | |
| 2728 | - for ($b=0;$b<$Lookup[$i]['Subtable'][$c]['SubstCount'];$b++) { | |
| 2729 | - $lup = $Lookup[$i]['Subtable'][$c]['SubstLookupRecord'][$b]['LookupListIndex']; | |
| 2730 | - $seqIndex = $Lookup[$i]['Subtable'][$c]['SubstLookupRecord'][$b]['SequenceIndex']; | |
| 2731 | - for($lus=0;$lus<$Lookup[$lup]['SubtableCount'];$lus++) { | |
| 2732 | - if (count($Lookup[$lup]['Subtable'][$lus]['subs'])) { | |
| 2733 | - foreach($Lookup[$lup]['Subtable'][$lus]['subs'] AS $luss) { | |
| 2734 | - $lookupGlyphs = $luss['Replace']; | |
| 2735 | - $mLen = count($lookupGlyphs); | |
| 2736 | - | |
| 2737 | - // Only apply if the (first) 'Replace' glyph from the | |
| 2738 | - // Lookup list is in the [inputGlyphs] at ['SequenceIndex'] | |
| 2739 | - // then apply the substitution | |
| 2740 | - if (strpos($inputGlyphs[$seqIndex],$lookupGlyphs[0])===false) { continue; } | |
| 2741 | - | |
| 2742 | - // Returns e.g. �(0612)�(ignore) (0613)�(ignore) (0614)� | |
| 2743 | - $contextInputMatch = $this->_makeGSUBcontextInputMatch($inputGlyphs, $ignore, $lookupGlyphs, $seqIndex); | |
| 2744 | - $REPL = implode(" ",$luss['substitute']); | |
| 2745 | - | |
| 2746 | - if (strpos("isol fina fin2 fin3 medi med2 init ",$tag)!==false && $scripttag=='arab') { | |
| 2747 | - $volt[] = array('match'=>$lookupGlyphs[0], 'replace'=>$REPL, 'tag'=>$tag, 'prel'=>$backtrackGlyphs, 'postl'=>$lookaheadGlyphs, 'ignore'=>$ignore); | |
| 2748 | - } | |
| 2749 | - else { | |
| 2750 | - $subRule['rules'][] = array('type' => $Lookup[$lup]['Type'], 'match' => $lookupGlyphs, 'replace' => $luss['substitute'], 'seqIndex' => $seqIndex, 'key' => $lookupGlyphs[0], ); | |
| 2751 | - } | |
| 2752 | - } | |
| 2753 | - } | |
| 2754 | - } | |
| 2755 | - } | |
| 2756 | - if (count($subRule['rules'])) $volt[] = $subRule; | |
| 2757 | - } | |
| 2758 | - } | |
| 2759 | - } | |
| 2760 | - } | |
| 2761 | -//print_r($Lookup); exit; | |
| 2762 | - return $volt; | |
| 2763 | - } | |
| 2764 | - //===================================================================================== | |
| 2765 | - //===================================================================================== | |
| 2766 | - // mPDF 5.7.1 | |
| 2767 | - function _checkGSUBignore($flag, $glyph, $MarkFilteringSet) { | |
| 2768 | - $ignore = false; | |
| 2769 | - // Flag & 0x0008 = Ignore Marks - (unless already done with MarkAttachmentType) | |
| 2770 | - if ((($flag & 0x0008) == 0x0008 && ($flag & 0xFF00) == 0) && strpos($this->GlyphClassMarks,$glyph)) { $ignore = true; } | |
| 2771 | - if ((($flag & 0x0004) == 0x0004) && strpos($this->GlyphClassLigatures,$glyph)) { $ignore = true; } | |
| 2772 | - if ((($flag & 0x0002) == 0x0002) && strpos($this->GlyphClassBases,$glyph)) { $ignore = true; } | |
| 2773 | - // Flag & 0xFF?? = MarkAttachmentType | |
| 2774 | - if ($flag & 0xFF00) { | |
| 2775 | - // "a lookup must ignore any mark glyphs that are not in the specified mark attachment class" | |
| 2776 | - // $this->MarkAttachmentType is already adjusted for this i.e. contains all Marks except those in the MarkAttachmentClassDef table | |
| 2777 | - if (strpos($this->MarkAttachmentType[($flag >> 8)],$glyph)) { $ignore = true; } | |
| 2778 | - } | |
| 2779 | - // Flag & 0x0010 = UseMarkFilteringSet | |
| 2780 | - if (($flag & 0x0010) && strpos($this->MarkGlyphSets[$MarkFilteringSet],$glyph)) { $ignore = true; } | |
| 2781 | - return $ignore; | |
| 2782 | - } | |
| 2783 | - | |
| 2784 | - function _getGSUBignoreString($flag, $MarkFilteringSet) { | |
| 2785 | - // If ignoreFlag set, combine all ignore glyphs into -> "((?:(?: FBA1| FBA2| FBA3))*)" | |
| 2786 | - // else "()" | |
| 2787 | - // for Input - set on secondary Lookup table if in Context, and set Backtrack and Lookahead on Context Lookup | |
| 2788 | - $str = ""; | |
| 2789 | - $ignoreflag = 0; | |
| 2790 | - | |
| 2791 | - // Flag & 0xFF?? = MarkAttachmentType | |
| 2792 | - if ($flag & 0xFF00) { | |
| 2793 | - // "a lookup must ignore any mark glyphs that are not in the specified mark attachment class" | |
| 2794 | - // $this->MarkAttachmentType is already adjusted for this i.e. contains all Marks except those in the MarkAttachmentClassDef table | |
| 2795 | - $MarkAttachmentType = $flag >> 8; | |
| 2796 | - $ignoreflag = $flag; | |
| 2797 | - $str = $this->MarkAttachmentType[$MarkAttachmentType]; | |
| 2798 | - } | |
| 2799 | - | |
| 2800 | - // Flag & 0x0010 = UseMarkFilteringSet | |
| 2801 | - if ($flag & 0x0010) { | |
| 2802 | - die("This font ".$this->fontkey." contains MarkGlyphSets - Not tested yet"); | |
| 2803 | - $str = $this->MarkGlyphSets[$MarkFilteringSet]; | |
| 2804 | - } | |
| 2805 | - | |
| 2806 | - // If Ignore Marks set, supercedes any above | |
| 2807 | - // Flag & 0x0008 = Ignore Marks - (unless already done with MarkAttachmentType) | |
| 2808 | - if (($flag & 0x0008) == 0x0008 && ($flag & 0xFF00) == 0) { | |
| 2809 | - $ignoreflag = 8; | |
| 2810 | - $str = $this->GlyphClassMarks; | |
| 2811 | - } | |
| 2812 | - | |
| 2813 | - // Flag & 0x0004 = Ignore Ligatures | |
| 2814 | - if (($flag & 0x0004) == 0x0004) { | |
| 2815 | - $ignoreflag += 4; | |
| 2816 | - if ($str) { $str .= "|"; } | |
| 2817 | - $str .= $this->GlyphClassLigatures; | |
| 2818 | - } | |
| 2819 | - // Flag & 0x0002 = Ignore BaseGlyphs | |
| 2820 | - if (($flag & 0x0002) == 0x0002) { | |
| 2821 | - $ignoreflag += 2; | |
| 2822 | - if ($str) { $str .= "|"; } | |
| 2823 | - $str .= $this->GlyphClassBases; | |
| 2824 | - } | |
| 2825 | - if ($str) { | |
| 2826 | - // This originally returned e.g. ((?:(?:[IGNORE8]))*) when NOT specific to a Lookup e.g. rtlSub in | |
| 2827 | - // arabictypesetting.GSUB.arab.DFLT.php | |
| 2828 | - // This would save repeatedly saving long text strings if used multiple times | |
| 2829 | - // When writing e.g. arabictypesetting.GSUB.arab.DFLT.php to file, included as $ignore[8] | |
| 2830 | - // Would need to also write the $ignore array to that file | |
| 2831 | - // // If UseMarkFilteringSet (specific to the Lookup) return the string | |
| 2832 | - // if (($flag & 0x0010) && ($flag & 0x0008) != 0x0008) { | |
| 2833 | - // return "((?:(?:" . $str . "))*)"; | |
| 2834 | - // } | |
| 2835 | - // else { return "((?:(?:" . "[IGNORE".$ignoreflag."]" . "))*)"; } | |
| 2836 | - // // e.g. ((?:(?: 0031| 0032| 0033| 0034| 0045))*) | |
| 2837 | - | |
| 2838 | - // But never finished coding it to add the $ignore array to the file, and it doesn't seem to occur often enough to be worth | |
| 2839 | - // writing. So just output it as a string: | |
| 2840 | - return "((?:(?:" . $str . "))*)"; | |
| 2841 | - | |
| 2842 | - } | |
| 2843 | - else return "()"; | |
| 2844 | - } | |
| 2845 | - | |
| 2846 | - // GSUB Patterns | |
| 2847 | - | |
| 2848 | -/* | |
| 2849 | - BACKTRACK INPUT LOOKAHEAD | |
| 2850 | -================================== ================== ================================== | |
| 2851 | -(FEEB|FEEC)(ign) �(FD12|FD13)(ign) �(0612)�(ign) (0613)�(ign) (FD12|FD13)�(ign) (FEEB|FEEC) | |
| 2852 | - Backtrack 1 Backtrack 2 Input 1 Input 2 Lookahead 1 Lookahead 2 | |
| 2853 | - \${1} \${2} \${3} \${4} \${5+} \${6+} \${7+} \${8+} | |
| 2854 | - | |
| 2855 | - nBacktrack = 2 nInput = 2 nLookahead = 2 | |
| 2856 | - | |
| 2857 | - nBsubs = 2xnBack nIsubs = (nBsubs+) nLsubs = (nBsubs+nIsubs+) 2xnLookahead | |
| 2858 | - "\${1}\${2} " (nInput*2)-1 "\${5+} \${6+}" | |
| 2859 | - "REPL" | |
| 2860 | - | |
| 2861 | -�\${1}\${2} �\${3}\${4} �REPL�\${5+} \${6+}�\${7+} \${8+}� | |
| 2862 | - | |
| 2863 | - | |
| 2864 | - INPUT nInput = 5 | |
| 2865 | -============================================================ | |
| 2866 | -�(0612)�(ign) (0613)�(ign) (0614)�(ign) (0615)�(ign) (0615)� | |
| 2867 | -\${1} \${2} \${3} \${4} \${5} \${6} \${7} \${8} \${9} (All backreference numbers are + nBsubs) | |
| 2868 | -Input 1 Input 2 Input 3 Input 4 Input 5 | |
| 2869 | - | |
| 2870 | -A====== SequenceIndex=1 ; Lookup match nGlyphs=1 | |
| 2871 | -B=================== SequenceIndex=1 ; Lookup match nGlyphs=2 | |
| 2872 | -C=============================== SequenceIndex=1 ; Lookup match nGlyphs=3 | |
| 2873 | - D======================= SequenceIndex=2 ; Lookup match nGlyphs=2 | |
| 2874 | - E===================================== SequenceIndex=2 ; Lookup match nGlyphs=3 | |
| 2875 | - F====================== SequenceIndex=4 ; Lookup match nGlyphs=2 | |
| 2876 | - | |
| 2877 | -All backreference numbers are + nBsubs | |
| 2878 | -A - "REPL\${2} \${3}\${4} \${5}\${6} \${7}\${8} \${9}" | |
| 2879 | -B - "REPL\${2}\${4} \${5}\${6} \${7}\${8} \${9}" | |
| 2880 | -C - "REPL\${2}\${4}\${6} \${7}\${8} \${9}" | |
| 2881 | -D - "\${1} REPL\${2}\${4}\${6} \${7}\${8} \${9}" | |
| 2882 | -E - "\${1} REPL\${2}\${4}\${6}\${8} \${9}" | |
| 2883 | -F - "\${1}\${2} \${3}\${4} \${5} REPL\${6}\${8}" | |
| 2884 | -*/ | |
| 2885 | - | |
| 2886 | - function _makeGSUBcontextInputMatch($inputGlyphs, $ignore, $lookupGlyphs, $seqIndex) { | |
| 2887 | - // $ignore = "((?:(?: FBA1| FBA2| FBA3))*)" or "()" | |
| 2888 | - // Returns e.g. �(0612)�(ignore) (0613)�(ignore) (0614)� | |
| 2889 | - // $inputGlyphs = array of glyphs(glyphstrings) making up Input sequence in Context | |
| 2890 | - // $lookupGlyphs = array of glyphs (single Glyphs) making up Lookup Input sequence | |
| 2891 | - $mLen = count($lookupGlyphs); // nGlyphs in the secondary Lookup match | |
| 2892 | - $nInput = count($inputGlyphs); // nGlyphs in the Primary Input sequence | |
| 2893 | - $str = ""; | |
| 2894 | - for($i=0;$i<$nInput;$i++) { | |
| 2895 | - if ($i>0) { $str .= $ignore." "; } | |
| 2896 | - if ($i>=$seqIndex && $i<($seqIndex+$mLen)) { $str .= "(".$lookupGlyphs[($i-$seqIndex)].")"; } | |
| 2897 | - else { $str .= "(".$inputGlyphs[($i)].")"; } | |
| 2898 | - } | |
| 2899 | - return $str; | |
| 2900 | - } | |
| 2901 | - | |
| 2902 | - function _makeGSUBinputMatch($inputGlyphs, $ignore) { | |
| 2903 | - // $ignore = "((?:(?: FBA1| FBA2| FBA3))*)" or "()" | |
| 2904 | - // Returns e.g. �(0612)�(ignore) (0613)�(ignore) (0614)� | |
| 2905 | - // $inputGlyphs = array of glyphs(glyphstrings) making up Input sequence in Context | |
| 2906 | - // $lookupGlyphs = array of glyphs making up Lookup Input sequence - if applicable | |
| 2907 | - $str = ""; | |
| 2908 | - for($i=1;$i<=count($inputGlyphs);$i++) { | |
| 2909 | - if ($i>1) { $str .= $ignore." "; } | |
| 2910 | - $str .= "(".$inputGlyphs[($i-1)].")"; | |
| 2911 | - } | |
| 2912 | - return $str; | |
| 2913 | - } | |
| 2914 | - | |
| 2915 | - function _makeGSUBbacktrackMatch($backtrackGlyphs, $ignore) { | |
| 2916 | - // $ignore = "((?:(?: FBA1| FBA2| FBA3))*)" or "()" | |
| 2917 | - // Returns e.g. �(FEEB|FEEC)(ignore) �(FD12|FD13)(ignore) � | |
| 2918 | - // $backtrackGlyphs = array of glyphstrings making up Backtrack sequence | |
| 2919 | - // 3 2 1 0 | |
| 2920 | - // each item being e.g. E0AD|E0AF|F1FD | |
| 2921 | - $str = ""; | |
| 2922 | - for($i=(count($backtrackGlyphs)-1);$i>=0;$i--) { | |
| 2923 | - $str .= "(".$backtrackGlyphs[$i].")".$ignore." "; | |
| 2924 | - } | |
| 2925 | - return $str; | |
| 2926 | - } | |
| 2927 | - | |
| 2928 | - function _makeGSUBlookaheadMatch($lookaheadGlyphs, $ignore) { | |
| 2929 | - // $ignore = "((?:(?: FBA1| FBA2| FBA3))*)" or "()" | |
| 2930 | - // Returns e.g. �(ignore) (FD12|FD13)�(ignore) (FEEB|FEEC)� | |
| 2931 | - // $lookaheadGlyphs = array of glyphstrings making up Lookahead sequence | |
| 2932 | - // 0 1 2 3 | |
| 2933 | - // each item being e.g. E0AD|E0AF|F1FD | |
| 2934 | - $str = ""; | |
| 2935 | - for($i=0;$i<count($lookaheadGlyphs);$i++) { | |
| 2936 | - $str .= $ignore." (".$lookaheadGlyphs[$i].")"; | |
| 2937 | - } | |
| 2938 | - return $str; | |
| 2939 | - } | |
| 2940 | - | |
| 2941 | - | |
| 2942 | - | |
| 2943 | - function _makeGSUBinputReplacement($nInput, $REPL, $ignore, $nBsubs, $mLen, $seqIndex) { | |
| 2944 | - // Returns e.g. "REPL\${6}\${8}" or "\${1}\${2} \${3} REPL\${4}\${6}\${8} \${9}" | |
| 2945 | - // $nInput nGlyphs in the Primary Input sequence | |
| 2946 | - // $REPL replacement glyphs from secondary lookup | |
| 2947 | - // $ignore = "((?:(?: FBA1| FBA2| FBA3))*)" or "()" | |
| 2948 | - // $nBsubs Number of Backtrack substitutions (= 2x Number of Backtrack glyphs) | |
| 2949 | - // $mLen nGlyphs in the secondary Lookup match - if no secondary lookup, should=$nInput | |
| 2950 | - // $seqIndex Sequence Index to apply the secondary match | |
| 2951 | - if ($ignore=="()") { $ign = false; } | |
| 2952 | - else { $ign = true; } | |
| 2953 | - $str = ""; | |
| 2954 | - if ($nInput == 1) { $str = $REPL; } | |
| 2955 | - else if ($nInput>1) { | |
| 2956 | - if ($mLen==$nInput) { // whole string replaced | |
| 2957 | - $str = $REPL; | |
| 2958 | - if ($ign) { | |
| 2959 | - // for every nInput over 1, add another replacement backreference, to move IGNORES after replacement | |
| 2960 | - for($x=2;$x<=$nInput;$x++) { | |
| 2961 | - $str .= '\\'.($nBsubs+(2*($x-1))); | |
| 2962 | - } | |
| 2963 | - } | |
| 2964 | - } | |
| 2965 | - else { // if only part of string replaced: | |
| 2966 | - for($x=1;$x<($seqIndex+1);$x++) { | |
| 2967 | - if ($x==1) { $str .= '\\'.($nBsubs + 1); } | |
| 2968 | - else { | |
| 2969 | - if ($ign) { $str .= '\\'.($nBsubs+(2*($x-1))); } | |
| 2970 | - $str .= ' \\'.($nBsubs+1+(2*($x-1))); | |
| 2971 | - } | |
| 2972 | - } | |
| 2973 | - if ($seqIndex>0) { $str .= " "; } | |
| 2974 | - $str .= $REPL; | |
| 2975 | - if ($ign) { | |
| 2976 | - for($x=(max(($seqIndex+1),2));$x<($seqIndex+1+$mLen);$x++) { // move IGNORES after replacement | |
| 2977 | - $str .= '\\'.($nBsubs+(2*($x-1))); | |
| 2978 | - } | |
| 2979 | - } | |
| 2980 | - for($x=($seqIndex+1+$mLen);$x<=$nInput;$x++) { | |
| 2981 | - if ($ign) { $str .= '\\'.($nBsubs+(2*($x-1))); } | |
| 2982 | - $str .= ' \\'.($nBsubs+1+(2*($x-1))); | |
| 2983 | - } | |
| 2984 | - } | |
| 2985 | - } | |
| 2986 | - return $str; | |
| 2987 | - } | |
| 2988 | - | |
| 2989 | - | |
| 2990 | - | |
| 2991 | - ////////////////////////////////////////////////////////////////////////////////// | |
| 2992 | - function _getCoverage($convert2hex=true, $mode=1) { | |
| 2993 | - $g = array(); | |
| 2994 | - $ctr = 0; | |
| 2995 | - $CoverageFormat= $this->read_ushort(); | |
| 2996 | - if ($CoverageFormat == 1) { | |
| 2997 | - $CoverageGlyphCount= $this->read_ushort(); | |
| 2998 | - for ($gid=0;$gid<$CoverageGlyphCount;$gid++) { | |
| 2999 | - $glyphID = $this->read_ushort(); | |
| 3000 | - $uni = $this->glyphToChar[$glyphID][0]; | |
| 3001 | - if ($convert2hex) { $g[] = unicode_hex($uni); } | |
| 3002 | - else if ($mode==2) { $g[$uni] = $ctr; $ctr++; } | |
| 3003 | - else { $g[] = $glyphID; } | |
| 3004 | - } | |
| 3005 | - } | |
| 3006 | - if ($CoverageFormat == 2) { | |
| 3007 | - $RangeCount= $this->read_ushort(); | |
| 3008 | - for ($r=0;$r<$RangeCount;$r++) { | |
| 3009 | - $start = $this->read_ushort(); | |
| 3010 | - $end = $this->read_ushort(); | |
| 3011 | - $StartCoverageIndex = $this->read_ushort(); // n/a | |
| 3012 | - for ($glyphID=$start;$glyphID<=$end;$glyphID++) { | |
| 3013 | - $uni = $this->glyphToChar[$glyphID][0]; | |
| 3014 | - if ($convert2hex) { $g[] = unicode_hex($uni); } | |
| 3015 | - else if ($mode==2) { $uni = $g[$uni] = $ctr; $ctr++; } | |
| 3016 | - else { $g[] = $glyphID; } | |
| 3017 | - } | |
| 3018 | - } | |
| 3019 | - } | |
| 3020 | - return $g; | |
| 3021 | - } | |
| 3022 | - | |
| 3023 | - ////////////////////////////////////////////////////////////////////////////////// | |
| 3024 | - function _getClasses($offset) { | |
| 3025 | - $this->seek($offset); | |
| 3026 | - $ClassFormat = $this->read_ushort(); | |
| 3027 | - $GlyphByClass = array(); | |
| 3028 | - if ($ClassFormat == 1) { | |
| 3029 | - $StartGlyph = $this->read_ushort(); | |
| 3030 | - $GlyphCount = $this->read_ushort(); | |
| 3031 | - for ($i=0;$i<$GlyphCount;$i++) { | |
| 3032 | - $startGlyphID = $StartGlyph + $i; | |
| 3033 | - $endGlyphID = $StartGlyph + $i; | |
| 3034 | - $class = $this->read_ushort(); | |
| 3035 | - for($g=$startGlyphID;$g<=$endGlyphID;$g++) { | |
| 3036 | - if (isset($this->glyphToChar[$g][0])) { | |
| 3037 | - $GlyphByClass[$class][] = unicode_hex($this->glyphToChar[$g][0]); | |
| 3038 | - } | |
| 3039 | - } | |
| 3040 | - } | |
| 3041 | - } | |
| 3042 | - else if ($ClassFormat == 2) { | |
| 3043 | - $tableCount = $this->read_ushort(); | |
| 3044 | - for ($i=0;$i<$tableCount;$i++) { | |
| 3045 | - $startGlyphID = $this->read_ushort(); | |
| 3046 | - $endGlyphID = $this->read_ushort(); | |
| 3047 | - $class = $this->read_ushort(); | |
| 3048 | - for($g=$startGlyphID;$g<=$endGlyphID;$g++) { | |
| 3049 | - if ($this->glyphToChar[$g][0]) { | |
| 3050 | - $GlyphByClass[$class][] = unicode_hex($this->glyphToChar[$g][0]); | |
| 3051 | - } | |
| 3052 | - } | |
| 3053 | - } | |
| 3054 | - } | |
| 3055 | - $gbc = array(); | |
| 3056 | - foreach($GlyphByClass AS $class=>$garr) { $gbc[$class] = implode('|',$garr); } | |
| 3057 | - return $gbc; | |
| 3058 | - } | |
| 3059 | - ////////////////////////////////////////////////////////////////////////////////// | |
| 3060 | - ////////////////////////////////////////////////////////////////////////////////// | |
| 3061 | - ////////////////////////////////////////////////////////////////////////////////// | |
| 3062 | - ////////////////////////////////////////////////////////////////////////////////// | |
| 3063 | - ////////////////////////////////////////////////////////////////////////////////// | |
| 3064 | - function _getGPOStables() { | |
| 3065 | - /////////////////////////////////// | |
| 3066 | - // GPOS - Glyph Positioning | |
| 3067 | - /////////////////////////////////// | |
| 3068 | - if (isset($this->tables["GPOS"])) { | |
| 3069 | - $ffeats = array(); | |
| 3070 | - $gpos_offset = $this->seek_table("GPOS"); | |
| 3071 | - $this->skip(4); | |
| 3072 | - $ScriptList_offset = $gpos_offset + $this->read_ushort(); | |
| 3073 | - $FeatureList_offset = $gpos_offset + $this->read_ushort(); | |
| 3074 | - $LookupList_offset = $gpos_offset + $this->read_ushort(); | |
| 3075 | - | |
| 3076 | - // ScriptList | |
| 3077 | - $this->seek($ScriptList_offset ); | |
| 3078 | - $ScriptCount = $this->read_ushort(); | |
| 3079 | - for ($i=0;$i<$ScriptCount;$i++) { | |
| 3080 | - $ScriptTag = $this->read_tag(); // = "beng", "deva" etc. | |
| 3081 | - $ScriptTableOffset = $this->read_ushort(); | |
| 3082 | - $ffeats[$ScriptTag] = $ScriptList_offset + $ScriptTableOffset; | |
| 3083 | - } | |
| 3084 | - | |
| 3085 | - // Script Table | |
| 3086 | - foreach($ffeats AS $t=>$o) { | |
| 3087 | - $ls = array(); | |
| 3088 | - $this->seek($o); | |
| 3089 | - $DefLangSys_offset = $this->read_ushort(); | |
| 3090 | - if ($DefLangSys_offset > 0) { | |
| 3091 | - $ls['DFLT'] = $DefLangSys_offset + $o; | |
| 3092 | - } | |
| 3093 | - $LangSysCount = $this->read_ushort(); | |
| 3094 | - for ($i=0;$i<$LangSysCount;$i++) { | |
| 3095 | - $LangTag = $this->read_tag(); // = | |
| 3096 | - $LangTableOffset = $this->read_ushort(); | |
| 3097 | - $ls[$LangTag] = $o + $LangTableOffset; | |
| 3098 | - } | |
| 3099 | - $ffeats[$t] = $ls; | |
| 3100 | - } | |
| 3101 | - | |
| 3102 | - | |
| 3103 | - // Get FeatureIndexList | |
| 3104 | - // LangSys Table - from first listed langsys | |
| 3105 | - foreach($ffeats AS $st=>$scripts) { | |
| 3106 | - foreach($scripts AS $t=>$o) { | |
| 3107 | - $FeatureIndex = array(); | |
| 3108 | - $langsystable_offset = $o; | |
| 3109 | - $this->seek($langsystable_offset); | |
| 3110 | - $LookUpOrder = $this->read_ushort(); //==NULL | |
| 3111 | - $ReqFeatureIndex = $this->read_ushort(); | |
| 3112 | - if ($ReqFeatureIndex != 0xFFFF) { $FeatureIndex[] = $ReqFeatureIndex ; } | |
| 3113 | - $FeatureCount = $this->read_ushort(); | |
| 3114 | - for ($i=0;$i<$FeatureCount;$i++) { | |
| 3115 | - $FeatureIndex[] = $this->read_ushort(); // = index of feature | |
| 3116 | - } | |
| 3117 | - $ffeats[$st][$t] = $FeatureIndex; | |
| 3118 | - } | |
| 3119 | - } | |
| 3120 | -//print_r($ffeats); exit; | |
| 3121 | - | |
| 3122 | - | |
| 3123 | - // Feauture List => LookupListIndex es | |
| 3124 | - $this->seek($FeatureList_offset ); | |
| 3125 | - $FeatureCount = $this->read_ushort(); | |
| 3126 | - $Feature = array(); | |
| 3127 | - for ($i=0;$i<$FeatureCount;$i++) { | |
| 3128 | - $tag = $this->read_tag() ; | |
| 3129 | - if ($tag == 'kern') { $this->haskernGPOS = true; } | |
| 3130 | - $Feature[$i] = array('tag' => $tag); | |
| 3131 | - $Feature[$i]['offset'] = $FeatureList_offset + $this->read_ushort(); | |
| 3132 | - } | |
| 3133 | - for ($i=0;$i<$FeatureCount;$i++) { | |
| 3134 | - $this->seek($Feature[$i]['offset']); | |
| 3135 | - $this->read_ushort(); // null | |
| 3136 | - $Feature[$i]['LookupCount'] = $Lookupcount = $this->read_ushort(); | |
| 3137 | - $Feature[$i]['LookupListIndex'] = array(); | |
| 3138 | - for ($c=0;$c<$Lookupcount;$c++) { | |
| 3139 | - $Feature[$i]['LookupListIndex'][] = $this->read_ushort(); | |
| 3140 | - } | |
| 3141 | - } | |
| 3142 | - | |
| 3143 | - | |
| 3144 | - foreach($ffeats AS $st=>$scripts) { | |
| 3145 | - foreach($scripts AS $t=>$o) { | |
| 3146 | - $FeatureIndex = $ffeats[$st][$t]; | |
| 3147 | - foreach($FeatureIndex AS $k=>$fi) { | |
| 3148 | - $ffeats[$st][$t][$k] = $Feature[$fi]; | |
| 3149 | - } | |
| 3150 | - } | |
| 3151 | - } | |
| 3152 | -//print_r($ffeats); exit; | |
| 3153 | - //===================================================================================== | |
| 3154 | - $gpos = array(); | |
| 3155 | - $GPOSScriptLang = array(); | |
| 3156 | - foreach($ffeats AS $st=>$scripts) { | |
| 3157 | - foreach($scripts AS $t=>$langsys) { | |
| 3158 | - $lg = array(); | |
| 3159 | - foreach($langsys AS $ft) { | |
| 3160 | - $lg[$ft['LookupListIndex'][0]] = $ft; | |
| 3161 | - } | |
| 3162 | - // list of Lookups in order they need to be run i.e. order listed in Lookup table | |
| 3163 | - ksort($lg); | |
| 3164 | - foreach($lg AS $ft) { | |
| 3165 | - $gpos[$st][$t][$ft['tag']] = $ft['LookupListIndex']; | |
| 3166 | - } | |
| 3167 | - if (!isset($GPOSScriptLang[$st])) { $GPOSScriptLang[$st] = ''; } | |
| 3168 | - $GPOSScriptLang[$st] .= $t.' '; | |
| 3169 | - } | |
| 3170 | - } | |
| 3171 | - | |
| 3172 | - //===================================================================================== | |
| 3173 | - // Get metadata and offsets for whole Lookup List table | |
| 3174 | - $this->seek($LookupList_offset ); | |
| 3175 | - $LookupCount = $this->read_ushort(); | |
| 3176 | - $Lookup = array(); | |
| 3177 | - $Offsets = array(); | |
| 3178 | - $SubtableCount = array(); | |
| 3179 | - for ($i=0;$i<$LookupCount;$i++) { | |
| 3180 | - $Offsets[$i] = $LookupList_offset + $this->read_ushort(); | |
| 3181 | - } | |
| 3182 | - for ($i=0;$i<$LookupCount;$i++) { | |
| 3183 | - $this->seek($Offsets[$i]); | |
| 3184 | - $Lookup[$i]['Type'] = $this->read_ushort(); | |
| 3185 | - $Lookup[$i]['Flag'] = $flag = $this->read_ushort(); | |
| 3186 | - $Lookup[$i]['SubtableCount'] = $SubtableCount[$i] = $this->read_ushort(); | |
| 3187 | - for ($c=0;$c<$SubtableCount[$i] ;$c++) { | |
| 3188 | - $Lookup[$i]['Subtables'][$c] = $Offsets[$i] + $this->read_ushort(); | |
| 3189 | - | |
| 3190 | - } | |
| 3191 | - // MarkFilteringSet = Index (base 0) into GDEF mark glyph sets structure | |
| 3192 | - if (($flag & 0x0010) == 0x0010) { | |
| 3193 | - $Lookup[$i]['MarkFilteringSet'] = $this->read_ushort(); | |
| 3194 | - } | |
| 3195 | - else { $Lookup[$i]['MarkFilteringSet'] = ''; } | |
| 3196 | - | |
| 3197 | - // Lookup Type 9: Extension | |
| 3198 | - if ($Lookup[$i]['Type'] == 9) { | |
| 3199 | - // Overwrites new offset (32-bit) for each subtable, and a new lookup Type | |
| 3200 | - for ($c=0;$c<$SubtableCount[$i] ;$c++) { | |
| 3201 | - $this->seek($Lookup[$i]['Subtables'][$c]); | |
| 3202 | - $ExtensionPosFormat = $this->read_ushort(); | |
| 3203 | - $type = $this->read_ushort(); | |
| 3204 | - $Lookup[$i]['Subtables'][$c] = $Lookup[$i]['Subtables'][$c] + $this->read_ulong(); | |
| 3205 | - } | |
| 3206 | - $Lookup[$i]['Type'] = $type; | |
| 3207 | - } | |
| 3208 | - | |
| 3209 | - } | |
| 3210 | - | |
| 3211 | - | |
| 3212 | - //===================================================================================== | |
| 3213 | - // Process Whole LookupList - Get LuCoverage = Lookup coverage just for first glyph | |
| 3214 | - $this->LuCoverage = array(); | |
| 3215 | - for ($i=0;$i<$LookupCount;$i++) { | |
| 3216 | - for ($c=0;$c<$Lookup[$i]['SubtableCount'] ;$c++) { | |
| 3217 | - | |
| 3218 | - $this->seek($Lookup[$i]['Subtables'][$c]); | |
| 3219 | - $PosFormat= $this->read_ushort(); | |
| 3220 | - | |
| 3221 | - if ($Lookup[$i]['Type']==7 && $PosFormat==3) { $this->skip(4); } | |
| 3222 | - else if ($Lookup[$i]['Type']==8 && $PosFormat==3) { | |
| 3223 | - $BacktrackGlyphCount= $this->read_ushort(); | |
| 3224 | - $this->skip(2*$BacktrackGlyphCount + 2); | |
| 3225 | - } | |
| 3226 | - // NB Coverage only looks at glyphs for position 1 (i.e. 7.3 and 8.3) // NEEDS TO READ ALL ******************** | |
| 3227 | - // NB For e.g. Type 4, this may be the Coverage for the Mark | |
| 3228 | - $Coverage = $Lookup[$i]['Subtables'][$c] + $this->read_ushort(); | |
| 3229 | - $this->seek($Coverage); | |
| 3230 | - $glyphs = $this->_getCoverage(false,2); | |
| 3231 | - $this->LuCoverage[$i][$c] = $glyphs; | |
| 3232 | - } | |
| 3233 | - } | |
| 3234 | - | |
| 3235 | - | |
| 3236 | - | |
| 3237 | - //===================================================================================== | |
| 3238 | - | |
| 3239 | - | |
| 3240 | - | |
| 3241 | -//print_r($GPOSScriptLang); exit; | |
| 3242 | -//print_r($gpos); exit; | |
| 3243 | -//print_r($Lookup); exit; | |
| 3244 | - | |
| 3245 | - | |
| 3246 | - | |
| 3247 | - | |
| 3248 | - $s = '<?php | |
| 3249 | -$LuCoverage = '.var_export($this->LuCoverage , true).'; | |
| 3250 | -?>'; | |
| 3251 | - | |
| 3252 | - | |
| 3253 | - file_put_contents(_MPDF_TTFONTDATAPATH.$this->fontkey.'.GPOSdata.php', $s); | |
| 3254 | - | |
| 3255 | - | |
| 3256 | - | |
| 3257 | - return array($GPOSScriptLang, $gpos, $Lookup); | |
| 3258 | - | |
| 3259 | - } // end if GPOS | |
| 3260 | - } | |
| 3261 | - | |
| 3262 | - ////////////////////////////////////////////////////////////////////////////////// | |
| 3263 | - | |
| 3264 | - //===================================================================================== | |
| 3265 | - //===================================================================================== | |
| 3266 | - //===================================================================================== | |
| 3267 | - //===================================================================================== | |
| 3268 | - //===================================================================================== | |
| 3269 | - //===================================================================================== | |
| 3270 | - | |
| 3271 | - function makeSubset($file, &$subset, $TTCfontID=0, $debug=false, $useOTL=false) { // mPDF 5.7.1 | |
| 3272 | - $this->useOTL = $useOTL; // mPDF 5.7.1 | |
| 753 | + function makeSubset($file, &$subset, $TTCfontID=0, $debug=false, $unAGlyphs=false) { // mPDF 5.4.05 | |
| 754 | + $this->unAGlyphs = $unAGlyphs; // mPDF 5.4.05 | |
| 3273 | 755 | $this->filename = $file; |
| 3274 | 756 | $this->fh = fopen($file ,'rb') or die('Can\'t open file ' . $file); |
| 3275 | 757 | $this->_pos = 0; |
| 3276 | 758 | $this->charWidths = ''; |
| @@ -3282,10 +761,8 @@ | ||
| 3282 | 761 | $this->tables = array(); |
| 3283 | 762 | $this->otables = array(); |
| 3284 | 763 | $this->ascent = 0; |
| 3285 | 764 | $this->descent = 0; |
| 3286 | - $this->strikeoutSize = 0; | |
| 3287 | - $this->strikeoutPosition = 0; | |
| 3288 | 765 | $this->numTTCFonts = 0; |
| 3289 | 766 | $this->TTCFonts = array(); |
| 3290 | 767 | $this->skip(4); |
| 3291 | 768 | $this->maxUni = 0; |
| @@ -3355,29 +832,9 @@ | ||
| 3355 | 832 | $glyphToChar = array(); |
| 3356 | 833 | $charToGlyph = array(); |
| 3357 | 834 | $this->getCMAP4($unicode_cmap_offset, $glyphToChar, $charToGlyph ); |
| 3358 | 835 | |
| 3359 | - /////////////////////////////////// | |
| 3360 | - // mPDF 5.7.1 | |
| 3361 | - // Map Unmapped glyphs - from $numGlyphs | |
| 3362 | - if ($useOTL) { | |
| 3363 | - $bctr = 0xE000; | |
| 3364 | - for ($gid=1; $gid<$numGlyphs; $gid++) { | |
| 3365 | - if (!isset($glyphToChar[$gid])) { | |
| 3366 | - while(isset($charToGlyph[$bctr])) { $bctr++; } // Avoid overwriting a glyph already mapped in PUA | |
| 3367 | - if ($bctr > 0xF8FF) { | |
| 3368 | - die($file." : WARNING - Font cannot map all included glyphs into Private Use Area U+E000 - U+F8FF; cannot use useOTL on this font"); | |
| 3369 | - } | |
| 3370 | - $glyphToChar[$gid][] = $bctr; | |
| 3371 | - $charToGlyph[$bctr] = $gid; | |
| 3372 | - $bctr++; | |
| 3373 | - } | |
| 3374 | - } | |
| 3375 | - } | |
| 3376 | - /////////////////////////////////// | |
| 3377 | - | |
| 3378 | 836 | $this->charToGlyph = $charToGlyph; |
| 3379 | - $this->glyphToChar = $glyphToChar; | |
| 3380 | 837 | |
| 3381 | 838 | |
| 3382 | 839 | /////////////////////////////////// |
| 3383 | 840 | // hmtx - Horizontal metrics table |
| @@ -3428,12 +885,8 @@ | ||
| 3428 | 885 | |
| 3429 | 886 | /////////////////////////////////// |
| 3430 | 887 | // name - table copied from the original |
| 3431 | 888 | /////////////////////////////////// |
| 3432 | - // MS spec says that "Platform and encoding ID's in the name table should be consistent with those in the cmap table. | |
| 3433 | - // If they are not, the font will not load in Windows" | |
| 3434 | - // Doesn't seem to be a problem? | |
| 3435 | - /////////////////////////////////// | |
| 3436 | 889 | $this->add('name', $this->get_table('name')); |
| 3437 | 890 | |
| 3438 | 891 | /////////////////////////////////// |
| 3439 | 892 | //tables copied from the original |
| @@ -3775,13 +1228,13 @@ | ||
| 3775 | 1228 | |
| 3776 | 1229 | //================================================================================ |
| 3777 | 1230 | |
| 3778 | 1231 | // Also does SMP |
| 3779 | - function makeSubsetSIP($file, &$subset, $TTCfontID=0, $debug=false, $useOTL=0) { // mPDF 5.7.1 | |
| 1232 | + function makeSubsetSIP($file, &$subset, $TTCfontID=0, $debug=false) { | |
| 3780 | 1233 | $this->fh = fopen($file ,'rb') or die('Can\'t open file ' . $file); |
| 3781 | 1234 | $this->filename = $file; |
| 3782 | 1235 | $this->_pos = 0; |
| 3783 | - $this->useOTL = $useOTL; // mPDF 5.7.1 | |
| 1236 | + $this->unAGlyphs = false; // mPDF 5.4.05 | |
| 3784 | 1237 | $this->charWidths = ''; |
| 3785 | 1238 | $this->glyphPos = array(); |
| 3786 | 1239 | $this->charToGlyph = array(); |
| 3787 | 1240 | $this->tables = array(); |
| @@ -3787,10 +1240,8 @@ | ||
| 3787 | 1240 | $this->tables = array(); |
| 3788 | 1241 | $this->otables = array(); |
| 3789 | 1242 | $this->ascent = 0; |
| 3790 | 1243 | $this->descent = 0; |
| 3791 | - $this->strikeoutSize = 0; | |
| 3792 | - $this->strikeoutPosition = 0; | |
| 3793 | 1244 | $this->numTTCFonts = 0; |
| 3794 | 1245 | $this->TTCFonts = array(); |
| 3795 | 1246 | $this->skip(4); |
| 3796 | 1247 | if ($TTCfontID > 0) { |
| @@ -3806,8 +1257,9 @@ | ||
| 3806 | 1257 | } |
| 3807 | 1258 | $this->readTableDirectory($debug); |
| 3808 | 1259 | |
| 3809 | 1260 | |
| 1261 | + | |
| 3810 | 1262 | /////////////////////////////////// |
| 3811 | 1263 | // head - Font header table |
| 3812 | 1264 | /////////////////////////////////// |
| 3813 | 1265 | $this->seek_table("head"); |
| @@ -3850,22 +1302,13 @@ | ||
| 3850 | 1302 | $unicode_cmap_offset = $cmap_offset + $offset; |
| 3851 | 1303 | break; |
| 3852 | 1304 | } |
| 3853 | 1305 | } |
| 3854 | - // mPDF 5.7.1 | |
| 3855 | - if (($platformID == 3 && $encodingID == 1) || $platformID == 0) { // Microsoft, Unicode | |
| 3856 | - $format = $this->get_ushort($cmap_offset + $offset); | |
| 3857 | - if ($format == 4) { | |
| 3858 | - $unicode_cmap_offset = $cmap_offset + $offset; | |
| 3859 | - } | |
| 3860 | - } | |
| 3861 | 1306 | $this->seek($save_pos ); |
| 3862 | 1307 | } |
| 3863 | 1308 | |
| 3864 | 1309 | if (!$unicode_cmap_offset) |
| 3865 | 1310 | die('Font does not have cmap for Unicode (platform 3, encoding 1, format 4, or platform 0, any encoding, format 4)'); |
| 3866 | - | |
| 3867 | - | |
| 3868 | 1311 | // Format 12 CMAP does characters above Unicode BMP i.e. some HKCS characters U+20000 and above |
| 3869 | 1312 | if ($format == 12) { |
| 3870 | 1313 | $this->maxUniChar = 0; |
| 3871 | 1314 | $this->seek($unicode_cmap_offset + 4); |
| @@ -3884,45 +1327,17 @@ | ||
| 3884 | 1327 | $offset = 0; |
| 3885 | 1328 | for ($unichar=$startCharCode;$unichar<=$endCharCode;$unichar++) { |
| 3886 | 1329 | $glyph = $startGlyphCode + $offset ; |
| 3887 | 1330 | $offset++; |
| 3888 | - // ZZZ98 | |
| 3889 | - if ($unichar < 0x30000) { | |
| 3890 | - $charToGlyph[$unichar] = $glyph; | |
| 3891 | - $this->maxUniChar = max($unichar,$this->maxUniChar); | |
| 3892 | - $glyphToChar[$glyph][] = $unichar; | |
| 3893 | - } | |
| 1331 | + $charToGlyph[$unichar] = $glyph; | |
| 1332 | + if ($unichar < 196608) { $this->maxUniChar = max($unichar,$this->maxUniChar); } | |
| 1333 | + $glyphToChar[$glyph][] = $unichar; | |
| 3894 | 1334 | } |
| 3895 | 1335 | } |
| 3896 | 1336 | } |
| 3897 | - // mPDF 5.7.1 | |
| 3898 | - else { | |
| 3899 | - $glyphToChar = array(); | |
| 3900 | - $charToGlyph = array(); | |
| 3901 | - $this->getCMAP4($unicode_cmap_offset, $glyphToChar, $charToGlyph ); | |
| 3902 | - } | |
| 1337 | + else | |
| 1338 | + die('Font does not have cmap for Unicode (format 12)'); | |
| 3903 | 1339 | |
| 3904 | - /////////////////////////////////// | |
| 3905 | - // mPDF 5.7.1 | |
| 3906 | - // Map Unmapped glyphs - from $numGlyphs | |
| 3907 | - if ($useOTL) { | |
| 3908 | - $bctr = 0xE000; | |
| 3909 | - for ($gid=1; $gid<$numGlyphs; $gid++) { | |
| 3910 | - if (!isset($glyphToChar[$gid])) { | |
| 3911 | - while(isset($charToGlyph[$bctr])) { $bctr++; } // Avoid overwriting a glyph already mapped in PUA | |
| 3912 | - // ZZZ98 | |
| 3913 | - if ($bctr > 0xF8FF && $bctr < 0x2CEB0) { | |
| 3914 | - $bctr = 0x2CEB0; | |
| 3915 | - while(isset($charToGlyph[$bctr])) { $bctr++; } | |
| 3916 | - } | |
| 3917 | - $glyphToChar[$gid][] = $bctr; | |
| 3918 | - $charToGlyph[$bctr] = $gid; | |
| 3919 | - $this->maxUniChar = max($bctr,$this->maxUniChar); | |
| 3920 | - $bctr++; | |
| 3921 | - } | |
| 3922 | - } | |
| 3923 | - } | |
| 3924 | - /////////////////////////////////// | |
| 3925 | 1340 | |
| 3926 | 1341 | /////////////////////////////////// |
| 3927 | 1342 | // hmtx - Horizontal metrics table |
| 3928 | 1343 | /////////////////////////////////// |
| @@ -3996,12 +1411,8 @@ | ||
| 3996 | 1411 | |
| 3997 | 1412 | /////////////////////////////////// |
| 3998 | 1413 | // name |
| 3999 | 1414 | /////////////////////////////////// |
| 4000 | - // MS spec says that "Platform and encoding ID's in the name table should be consistent with those in the cmap table. | |
| 4001 | - // If they are not, the font will not load in Windows" | |
| 4002 | - // Doesn't seem to be a problem? | |
| 4003 | - /////////////////////////////////// | |
| 4004 | 1415 | // Needs to have a name entry in 3,0 (e.g. symbol) - original font will be 3,1 (i.e. Unicode) |
| 4005 | 1416 | $name = $this->get_table('name'); |
| 4006 | 1417 | $name_offset = $this->seek_table("name"); |
| 4007 | 1418 | $format = $this->read_ushort(); |
| @@ -4167,9 +1578,9 @@ | ||
| 4167 | 1578 | |
| 4168 | 1579 | $cmap = array(0, 2, // Index : version, number of subtables |
| 4169 | 1580 | 1, 0, // Subtable : platform, encoding |
| 4170 | 1581 | 0, 20, // offset (hi,lo) |
| 4171 | - 3, 0, // Subtable : platform, encoding // See note above for 'name' | |
| 1582 | + 3, 0, // Subtable : platform, encoding | |
| 4172 | 1583 | $hoff, $loff, // offset (hi,lo) |
| 4173 | 1584 | 6, $length, // Format 6 Mapping table: format, length |
| 4174 | 1585 | 0, 1, // language, First char code |
| 4175 | 1586 | $entryCount |
| @@ -4350,8 +1761,9 @@ | ||
| 4350 | 1761 | $aw = $this->read_ushort(); |
| 4351 | 1762 | $lsb = $this->read_ushort(); |
| 4352 | 1763 | } |
| 4353 | 1764 | if (isset($glyphToChar[$glyph]) || $glyph == 0) { |
| 1765 | + | |
| 4354 | 1766 | if ($aw >= (1 << 15) ) { $aw = 0; } // 1.03 Some (arabic) fonts have -ve values for width |
| 4355 | 1767 | // although should be unsigned value - comes out as e.g. 65108 (intended -50) |
| 4356 | 1768 | if ($glyph == 0) { |
| 4357 | 1769 | $this->defaultWidth = $scale*$aw; |
| @@ -4357,8 +1769,9 @@ | ||
| 4357 | 1769 | $this->defaultWidth = $scale*$aw; |
| 4358 | 1770 | continue; |
| 4359 | 1771 | } |
| 4360 | 1772 | foreach($glyphToChar[$glyph] AS $char) { |
| 1773 | + //$this->charWidths[$char] = intval(round($scale*$aw)); | |
| 4361 | 1774 | if ($char != 0 && $char != 65535) { |
| 4362 | 1775 | $w = intval(round($scale*$aw)); |
| 4363 | 1776 | if ($w == 0) { $w = 65535; } |
| 4364 | 1777 | if ($char < 196608) { |
| @@ -4364,15 +1777,13 @@ | ||
| 4364 | 1777 | if ($char < 196608) { |
| 4365 | 1778 | $this->charWidths[$char*2] = chr($w >> 8); |
| 4366 | 1779 | $this->charWidths[$char*2 + 1] = chr($w & 0xFF); |
| 4367 | 1780 | $nCharWidths++; |
| 4368 | - | |
| 4369 | 1781 | } |
| 4370 | 1782 | } |
| 4371 | 1783 | } |
| 4372 | 1784 | } |
| 4373 | 1785 | } |
| 4374 | - | |
| 4375 | 1786 | $data = $this->get_chunk(($start+$numberOfHMetrics*4),($numGlyphs*2)); |
| 4376 | 1787 | $arr = unpack("n*", $data); |
| 4377 | 1788 | $diff = $numGlyphs-$numberOfHMetrics; |
| 4378 | 1789 | $w = intval(round($scale*$aw)); |
| @@ -4396,12 +1807,8 @@ | ||
| 4396 | 1807 | $this->charWidths[0] = chr($nCharWidths >> 8); |
| 4397 | 1808 | $this->charWidths[1] = chr($nCharWidths & 0xFF); |
| 4398 | 1809 | } |
| 4399 | 1810 | |
| 4400 | - | |
| 4401 | - | |
| 4402 | - | |
| 4403 | - | |
| 4404 | 1811 | function getHMetric($numberOfHMetrics, $gid) { |
| 4405 | 1812 | $start = $this->seek_table("hmtx"); |
| 4406 | 1813 | if ($gid < $numberOfHMetrics) { |
| 4407 | 1814 | $this->seek($start+($gid*4)); |
| @@ -4480,8 +1887,70 @@ | ||
| 4480 | 1887 | $glyphToChar[$glyph][] = $unichar; |
| 4481 | 1888 | } |
| 4482 | 1889 | } |
| 4483 | 1890 | |
| 1891 | + // mPDF 5.4.05 | |
| 1892 | + if ($this->unAGlyphs) { | |
| 1893 | + if (isset($this->tables['post'])) { | |
| 1894 | + $this->seek_table("post"); | |
| 1895 | + $formata = $this->read_ushort(); | |
| 1896 | + $formatb = $this->read_ushort(); | |
| 1897 | + // Only works on Format 2.0 | |
| 1898 | + if ($formata != 2 || $formatb != 0) { die("Cannot set unAGlyphs for this font (".$file."). POST table must be in Format 2."); } | |
| 1899 | + $this->skip(28); | |
| 1900 | + $nGlyfs = $this->read_ushort(); | |
| 1901 | + $glyphNameIndex = array(); | |
| 1902 | + for ($i=0; $i<$nGlyfs; $i++) { | |
| 1903 | + $glyphNameIndex[($this->read_ushort())] = $i; | |
| 1904 | + } | |
| 1905 | + | |
| 1906 | + $opost = $this->get_table('post'); | |
| 1907 | + $ptr = 34+($nGlyfs*2); | |
| 1908 | + for ($i=0; $i<$nGlyfs; $i++) { | |
| 1909 | + $len = ord(substr($opost,$ptr,1)); | |
| 1910 | + $ptr++; | |
| 1911 | + $name = substr($opost,$ptr,$len); | |
| 1912 | + $gid = $glyphNameIndex[$i+258]; | |
| 1913 | + // Select uni0600.xxx(x) - uni06FF.xxx(x) | |
| 1914 | + if (preg_match('/^uni(06[0-9a-f]{2})\.(fina|medi|init|fin|med|ini)$/i',$name,$m)) { | |
| 1915 | + if (!isset($glyphToChar[$gid]) || (isset($glyphToChar[$gid]) && is_array($glyphToChar[$gid]) && count($glyphToChar[$gid])==1 && $glyphToChar[$gid][0]>57343 && $glyphToChar[$gid][0]<63489)) { // if set in PUA private use area E000-F8FF, or NOT Unicode mapped | |
| 1916 | + $uni = hexdec($m[1]); | |
| 1917 | + $form = strtoupper(substr($m[2],0,1)); | |
| 1918 | + // Assign new PUA Unicode between F500 - F7FF | |
| 1919 | + $bit = $uni & 0xFF; | |
| 1920 | + if ($form == 'I') { $bit += 0xF600; } | |
| 1921 | + else if ($form == 'M') { $bit += 0xF700; } | |
| 1922 | + else { $bit += 0xF500; } | |
| 1923 | + // ADD TO CMAP | |
| 1924 | + $glyphToChar[$gid][] = $bit; | |
| 1925 | + $charToGlyph[$bit] = $gid; | |
| 1926 | + } | |
| 1927 | + } | |
| 1928 | + // LAM with ALEF ligatures (Mandatory ligatures) | |
| 1929 | + else if (preg_match('/^uni064406(22|23|25|27)(\.fina|\.fin){0,1}$/i',$name,$m)) { | |
| 1930 | + if ($m[1]=='22') { | |
| 1931 | + if ($m[2]) { $uni = hexdec('FEF6'); } else { $uni = hexdec('FEF5'); } | |
| 1932 | + } | |
| 1933 | + else if ($m[1]=='23') { | |
| 1934 | + if ($m[2]) { $uni = hexdec('FEF8'); } else { $uni = hexdec('FEF7'); } | |
| 1935 | + } | |
| 1936 | + else if ($m[1]=='25') { | |
| 1937 | + if ($m[2]) { $uni = hexdec('FEFA'); } else { $uni = hexdec('FEF9'); } | |
| 1938 | + } | |
| 1939 | + else if ($m[1]=='27') { | |
| 1940 | + if ($m[2]) { $uni = hexdec('FEFC'); } else { $uni = hexdec('FEFB'); } | |
| 1941 | + } | |
| 1942 | + if (!isset($glyphToChar[$gid]) || (isset($glyphToChar[$gid]) && is_array($glyphToChar[$gid]) && count($glyphToChar[$gid])==1 && $glyphToChar[$gid][0]>57343 && $glyphToChar[$gid][0]<63489)) { // if set in PUA private use area E000-F8FF, or NOT Unicode mapped | |
| 1943 | + // ADD TO CMAP | |
| 1944 | + $glyphToChar[$gid][] = $uni; | |
| 1945 | + $charToGlyph[$uni] = $gid; | |
| 1946 | + } | |
| 1947 | + } | |
| 1948 | + $ptr += $len; | |
| 1949 | + } | |
| 1950 | + } | |
| 1951 | + } | |
| 1952 | + | |
| 4484 | 1953 | } |
| 4485 | 1954 | |
| 4486 | 1955 | |
| 4487 | 1956 | // Put the TTF file together |
| @@ -4532,11 +2001,10 @@ | ||
| 4532 | 2001 | return $stm ; |
| 4533 | 2002 | } |
| 4534 | 2003 | |
| 4535 | 2004 | |
| 4536 | - function repackageTTF($file, $TTCfontID=0, $debug=false, $useOTL=false) { // mPDF 5.7.1 | |
| 4537 | - // (Does not called for subsets) | |
| 4538 | - $this->useOTL = $useOTL; // mPDF 5.7.1 | |
| 2005 | + function repackageTTF($file, $TTCfontID=0, $debug=false, $unAGlyphs=false) { // mPDF 5.4.05 | |
| 2006 | + $this->unAGlyphs = $unAGlyphs; // mPDF 5.4.05 | |
| 4539 | 2007 | $this->filename = $file; |
| 4540 | 2008 | $this->fh = fopen($file ,'rb') or die('Can\'t open file ' . $file); |
| 4541 | 2009 | $this->_pos = 0; |
| 4542 | 2010 | $this->charWidths = ''; |
| @@ -4545,10 +2013,8 @@ | ||
| 4545 | 2013 | $this->tables = array(); |
| 4546 | 2014 | $this->otables = array(); |
| 4547 | 2015 | $this->ascent = 0; |
| 4548 | 2016 | $this->descent = 0; |
| 4549 | - $this->strikeoutSize = 0; | |
| 4550 | - $this->strikeoutPosition = 0; | |
| 4551 | 2017 | $this->numTTCFonts = 0; |
| 4552 | 2018 | $this->TTCFonts = array(); |
| 4553 | 2019 | $this->skip(4); |
| 4554 | 2020 | $this->maxUni = 0; |
| @@ -4563,163 +2029,30 @@ | ||
| 4563 | 2029 | $this->seek($this->TTCFonts[$TTCfontID]['offset']); |
| 4564 | 2030 | $this->version = $version = $this->read_ulong(); // TTFont version again now |
| 4565 | 2031 | } |
| 4566 | 2032 | $this->readTableDirectory($debug); |
| 4567 | - $tags = array ('OS/2', 'glyf', 'head', 'hhea', 'hmtx', 'loca', 'maxp', 'name', 'post', 'cvt ', 'fpgm', 'gasp', 'prep'); | |
| 2033 | + $tags = array ('OS/2', 'cmap', 'glyf', 'head', 'hhea', 'hmtx', 'loca', 'maxp', 'name', 'post', 'cvt ', 'fpgm', 'gasp', 'prep'); | |
| 2034 | +/* | |
| 2035 | +Tables which require glyphIndex | |
| 2036 | +hdmx | |
| 2037 | +kern | |
| 2038 | +LTSH | |
| 4568 | 2039 | |
| 4569 | - foreach($tags AS $tag) { | |
| 4570 | - if (isset($this->tables[$tag])) { $this->add($tag, $this->get_table($tag)); } | |
| 4571 | - } | |
| 2040 | +Tables which do NOT require glyphIndex | |
| 2041 | +VDMX | |
| 4572 | 2042 | |
| 4573 | - // mPDF 5.7.1 | |
| 4574 | - if ($useOTL) { | |
| 4575 | - /////////////////////////////////// | |
| 4576 | - // maxp - Maximum profile table | |
| 4577 | - /////////////////////////////////// | |
| 4578 | - $this->seek_table("maxp"); | |
| 4579 | - $this->skip(4); | |
| 4580 | - $numGlyphs = $this->read_ushort(); | |
| 2043 | +GDEF | |
| 2044 | +GPOS | |
| 2045 | +GSUB | |
| 2046 | +JSTF | |
| 4581 | 2047 | |
| 2048 | +DSIG | |
| 2049 | +PCLT - not recommended | |
| 2050 | +*/ | |
| 4582 | 2051 | |
| 4583 | - /////////////////////////////////// | |
| 4584 | - // cmap - Character to glyph index mapping table | |
| 4585 | - /////////////////////////////////// | |
| 4586 | - $cmap_offset = $this->seek_table("cmap"); | |
| 4587 | - $this->skip(2); | |
| 4588 | - $cmapTableCount = $this->read_ushort(); | |
| 4589 | - $unicode_cmap_offset = 0; | |
| 4590 | - for ($i=0;$i<$cmapTableCount;$i++) { | |
| 4591 | - $platformID = $this->read_ushort(); | |
| 4592 | - $encodingID = $this->read_ushort(); | |
| 4593 | - $offset = $this->read_ulong(); | |
| 4594 | - $save_pos = $this->_pos; | |
| 4595 | - if (($platformID == 3 && $encodingID == 1) || $platformID == 0) { // Microsoft, Unicode | |
| 4596 | - $format = $this->get_ushort($cmap_offset + $offset); | |
| 4597 | - if ($format == 4) { | |
| 4598 | - $unicode_cmap_offset = $cmap_offset + $offset; | |
| 4599 | - break; | |
| 4600 | - } | |
| 4601 | - } | |
| 4602 | - $this->seek($save_pos ); | |
| 4603 | - } | |
| 4604 | - | |
| 4605 | - if (!$unicode_cmap_offset) | |
| 4606 | - die('Font ('.$this->filename .') does not have cmap for Unicode (platform 3, encoding 1, format 4, or platform 0, any encoding, format 4)'); | |
| 4607 | - | |
| 4608 | - | |
| 4609 | - $glyphToChar = array(); | |
| 4610 | - $charToGlyph = array(); | |
| 4611 | - $this->getCMAP4($unicode_cmap_offset, $glyphToChar, $charToGlyph ); | |
| 4612 | - | |
| 4613 | - | |
| 4614 | - /////////////////////////////////// | |
| 4615 | - // Map Unmapped glyphs - from $numGlyphs | |
| 4616 | - $bctr = 0xE000; | |
| 4617 | - for ($gid=1; $gid<$numGlyphs; $gid++) { | |
| 4618 | - if (!isset($glyphToChar[$gid])) { | |
| 4619 | - while(isset($charToGlyph[$bctr])) { $bctr++; } // Avoid overwriting a glyph already mapped in PUA (6,400) | |
| 4620 | - if ($bctr > 0xF8FF) { | |
| 4621 | - die("Problem. Trying to repackage TF file; not enough space for unmapped glyphs"); | |
| 4622 | - } | |
| 4623 | - $glyphToChar[$gid][] = $bctr; | |
| 4624 | - $charToGlyph[$bctr] = $gid; | |
| 4625 | - $bctr++; | |
| 4626 | - } | |
| 4627 | - } | |
| 4628 | - /////////////////////////////////// | |
| 4629 | - | |
| 4630 | - /////////////////////////////////// | |
| 4631 | - // Sort CID2GID map into segments of contiguous codes | |
| 4632 | - /////////////////////////////////// | |
| 4633 | - unset($charToGlyph[65535]); | |
| 4634 | - unset($charToGlyph[0]); | |
| 4635 | - ksort($charToGlyph); | |
| 4636 | - $rangeid = 0; | |
| 4637 | - $range = array(); | |
| 4638 | - $prevcid = -2; | |
| 4639 | - $prevglidx = -1; | |
| 4640 | - // for each character | |
| 4641 | - foreach ($charToGlyph as $cid => $glidx) { | |
| 4642 | - if ($cid == ($prevcid + 1) && $glidx == ($prevglidx + 1)) { | |
| 4643 | - $range[$rangeid][] = $glidx; | |
| 4644 | - } else { | |
| 4645 | - // new range | |
| 4646 | - $rangeid = $cid; | |
| 4647 | - $range[$rangeid] = array(); | |
| 4648 | - $range[$rangeid][] = $glidx; | |
| 4649 | - } | |
| 4650 | - $prevcid = $cid; | |
| 4651 | - $prevglidx = $glidx; | |
| 4652 | - } | |
| 4653 | - | |
| 4654 | - | |
| 4655 | - /////////////////////////////////// | |
| 4656 | - // CMap table | |
| 4657 | - /////////////////////////////////// | |
| 4658 | - // cmap - Character to glyph mapping | |
| 4659 | - $segCount = count($range) + 1; // + 1 Last segment has missing character 0xFFFF | |
| 4660 | - $searchRange = 1; | |
| 4661 | - $entrySelector = 0; | |
| 4662 | - while ($searchRange * 2 <= $segCount ) { | |
| 4663 | - $searchRange = $searchRange * 2; | |
| 4664 | - $entrySelector = $entrySelector + 1; | |
| 4665 | - } | |
| 4666 | - $searchRange = $searchRange * 2; | |
| 4667 | - $rangeShift = $segCount * 2 - $searchRange; | |
| 4668 | - $length = 16 + (8*$segCount ) + ($numGlyphs+1); | |
| 4669 | - $cmap = array(0, 3, // Index : version, number of encoding subtables | |
| 4670 | - 0, 0, // Encoding Subtable : platform (UNI=0), encoding 0 | |
| 4671 | - 0, 28, // Encoding Subtable : offset (hi,lo) | |
| 4672 | - 0, 3, // Encoding Subtable : platform (UNI=0), encoding 3 | |
| 4673 | - 0, 28, // Encoding Subtable : offset (hi,lo) | |
| 4674 | - 3, 1, // Encoding Subtable : platform (MS=3), encoding 1 | |
| 4675 | - 0, 28, // Encoding Subtable : offset (hi,lo) | |
| 4676 | - 4, $length, 0, // Format 4 Mapping subtable: format, length, language | |
| 4677 | - $segCount*2, | |
| 4678 | - $searchRange, | |
| 4679 | - $entrySelector, | |
| 4680 | - $rangeShift); | |
| 4681 | - | |
| 4682 | - // endCode(s) | |
| 4683 | - foreach($range AS $start=>$subrange) { | |
| 4684 | - $endCode = $start + (count($subrange)-1); | |
| 4685 | - $cmap[] = $endCode; // endCode(s) | |
| 4686 | - } | |
| 4687 | - $cmap[] = 0xFFFF; // endCode of last Segment | |
| 4688 | - $cmap[] = 0; // reservedPad | |
| 4689 | - | |
| 4690 | - // startCode(s) | |
| 4691 | - foreach($range AS $start=>$subrange) { | |
| 4692 | - $cmap[] = $start; // startCode(s) | |
| 4693 | - } | |
| 4694 | - $cmap[] = 0xFFFF; // startCode of last Segment | |
| 4695 | - // idDelta(s) | |
| 4696 | - foreach($range AS $start=>$subrange) { | |
| 4697 | - $idDelta = -($start-$subrange[0]); | |
| 4698 | - //$n += count($subrange); // ?? Line not required | |
| 4699 | - $cmap[] = $idDelta; // idDelta(s) | |
| 4700 | - } | |
| 4701 | - $cmap[] = 1; // idDelta of last Segment | |
| 4702 | - // idRangeOffset(s) | |
| 4703 | - foreach($range AS $subrange) { | |
| 4704 | - $cmap[] = 0; // idRangeOffset[segCount] Offset in bytes to glyph indexArray, or 0 | |
| 4705 | - } | |
| 4706 | - $cmap[] = 0; // idRangeOffset of last Segment | |
| 4707 | - foreach($range AS $subrange) { | |
| 4708 | - foreach($subrange AS $glidx) { | |
| 4709 | - $cmap[] = $glidx; | |
| 4710 | - } | |
| 4711 | - } | |
| 4712 | - $cmap[] = 0; // Mapping for last character | |
| 4713 | - $cmapstr = ''; | |
| 4714 | - foreach($cmap AS $cm) { $cmapstr .= pack("n",$cm); } | |
| 4715 | - $this->add('cmap', $cmapstr); | |
| 4716 | - | |
| 4717 | - | |
| 2052 | + foreach($tags AS $tag) { | |
| 2053 | + if (isset($this->tables[$tag])) { $this->add($tag, $this->get_table($tag)); } | |
| 4718 | 2054 | } |
| 4719 | - else { $this->add('cmap', $this->get_table('cmap')); } | |
| 4720 | - | |
| 4721 | - | |
| 4722 | 2055 | fclose($this->fh); |
| 4723 | 2056 | $stm = ''; |
| 4724 | 2057 | $this->endTTFile($stm); |
| 4725 | 2058 | return $stm ; |