1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288 |
- <?php
- require_once __DIR__ . '/../MpdfException.php';
- if (!defined('_TTF_MAC_HEADER'))
- define("_TTF_MAC_HEADER", false);
- if (!defined('_RECALC_PROFILE'))
- define("_RECALC_PROFILE", false);
- define("GF_WORDS", (1 << 0));
- define("GF_SCALE", (1 << 3));
- define("GF_MORE", (1 << 5));
- define("GF_XYSCALE", (1 << 6));
- define("GF_TWOBYTWO", (1 << 7));
- if (!function_exists('unicode_hex')) {
- function unicode_hex($unicode_dec)
- {
- return (sprintf("%05s", strtoupper(dechex($unicode_dec))));
- }
- }
- class OTLdump
- {
- var $GPOSFeatures;
- var $GPOSLookups;
- var $GPOSScriptLang;
- var $ignoreStrings;
- var $MarkAttachmentType;
- var $MarkGlyphSets;
- var $GlyphClassMarks;
- var $GlyphClassLigatures;
- var $GlyphClassBases;
- var $GlyphClassComponents;
- var $GSUBScriptLang;
- var $rtlPUAstr;
- var $rtlPUAarr;
- var $fontkey;
- var $useOTL;
- var $panose;
- var $maxUni;
- var $sFamilyClass;
- var $sFamilySubClass;
- var $sipset;
- var $smpset;
- var $_pos;
- var $numTables;
- var $searchRange;
- var $entrySelector;
- var $rangeShift;
- var $tables;
- var $otables;
- var $filename;
- var $fh;
- var $glyphPos;
- var $charToGlyph;
- var $ascent;
- var $descent;
- var $name;
- var $familyName;
- var $styleName;
- var $fullName;
- var $uniqueFontID;
- var $unitsPerEm;
- var $bbox;
- var $capHeight;
- var $stemV;
- var $italicAngle;
- var $flags;
- var $underlinePosition;
- var $underlineThickness;
- var $charWidths;
- var $defaultWidth;
- var $maxStrLenRead;
- var $numTTCFonts;
- var $TTCFonts;
- var $maxUniChar;
- var $kerninfo;
- public function __construct(mPDF $mpdf)
- {
- $this->mpdf = $mpdf;
- $this->maxStrLenRead = 200000;
- }
- function getMetrics($file, $fontkey, $TTCfontID = 0, $debug = false, $BMPonly = false, $kerninfo = false, $useOTL = 0, $mode)
- {
-
- $this->mode = $mode;
- $this->useOTL = $useOTL;
- $this->fontkey = $fontkey;
- $this->filename = $file;
- $this->fh = fopen($file, 'rb');
- if (!$this->fh) {
- throw new MpdfException('Can\'t open file ' . $file);
- }
- $this->_pos = 0;
- $this->charWidths = '';
- $this->glyphPos = array();
- $this->charToGlyph = array();
- $this->tables = array();
- $this->otables = array();
- $this->kerninfo = array();
- $this->ascent = 0;
- $this->descent = 0;
- $this->numTTCFonts = 0;
- $this->TTCFonts = array();
- $this->version = $version = $this->read_ulong();
- $this->panose = array();
- if ($version == 0x4F54544F) {
- throw new MpdfException("Postscript outlines are not supported");
- }
- if ($version == 0x74746366 && !$TTCfontID) {
- throw new MpdfException("ERROR - You must define the TTCfontID for a TrueType Collection in config_fonts.php (" . $file . ")");
- }
- if (!in_array($version, array(0x00010000, 0x74727565)) && !$TTCfontID) {
- throw new MpdfException("Not a TrueType font: version=" . $version);
- }
- if ($TTCfontID > 0) {
- $this->version = $version = $this->read_ulong();
- if (!in_array($version, array(0x00010000, 0x00020000))) {
- throw new MpdfException("ERROR - Error parsing TrueType Collection: version=" . $version . " - " . $file);
- }
- $this->numTTCFonts = $this->read_ulong();
- for ($i = 1; $i <= $this->numTTCFonts; $i++) {
- $this->TTCFonts[$i]['offset'] = $this->read_ulong();
- }
- $this->seek($this->TTCFonts[$TTCfontID]['offset']);
- $this->version = $version = $this->read_ulong();
- }
- $this->readTableDirectory($debug);
- $this->extractInfo($debug, $BMPonly, $kerninfo, $useOTL);
- fclose($this->fh);
- }
- function readTableDirectory($debug = false)
- {
- $this->numTables = $this->read_ushort();
- $this->searchRange = $this->read_ushort();
- $this->entrySelector = $this->read_ushort();
- $this->rangeShift = $this->read_ushort();
- $this->tables = array();
- for ($i = 0; $i < $this->numTables; $i++) {
- $record = array();
- $record['tag'] = $this->read_tag();
- $record['checksum'] = array($this->read_ushort(), $this->read_ushort());
- $record['offset'] = $this->read_ulong();
- $record['length'] = $this->read_ulong();
- $this->tables[$record['tag']] = $record;
- }
- if ($debug)
- $this->checksumTables();
- }
- function checksumTables()
- {
-
- foreach ($this->tables AS $t) {
- if ($t['length'] > 0 && $t['length'] < $this->maxStrLenRead) {
- $table = $this->get_chunk($t['offset'], $t['length']);
- $checksum = $this->calcChecksum($table);
- if ($t['tag'] == 'head') {
- $up = unpack('n*', substr($table, 8, 4));
- $adjustment[0] = $up[1];
- $adjustment[1] = $up[2];
- $checksum = $this->sub32($checksum, $adjustment);
- }
- $xchecksum = $t['checksum'];
- if ($xchecksum != $checksum) {
- throw new MpdfException(sprintf('TTF file "%s": invalid checksum %s table: %s (expected %s)', $this->filename, dechex($checksum[0]) . dechex($checksum[1]), $t['tag'], dechex($xchecksum[0]) . dechex($xchecksum[1])));
- }
- }
- }
- }
- function sub32($x, $y)
- {
- $xlo = $x[1];
- $xhi = $x[0];
- $ylo = $y[1];
- $yhi = $y[0];
- if ($ylo > $xlo) {
- $xlo += 1 << 16;
- $yhi += 1;
- }
- $reslo = $xlo - $ylo;
- if ($yhi > $xhi) {
- $xhi += 1 << 16;
- }
- $reshi = $xhi - $yhi;
- $reshi = $reshi & 0xFFFF;
- return array($reshi, $reslo);
- }
- function calcChecksum($data)
- {
- if (strlen($data) % 4) {
- $data .= str_repeat("\0", (4 - (strlen($data) % 4)));
- }
- $len = strlen($data);
- $hi = 0x0000;
- $lo = 0x0000;
- for ($i = 0; $i < $len; $i+=4) {
- $hi += (ord($data[$i]) << 8) + ord($data[$i + 1]);
- $lo += (ord($data[$i + 2]) << 8) + ord($data[$i + 3]);
- $hi += ($lo >> 16) & 0xFFFF;
- $lo = $lo & 0xFFFF;
- }
- return array($hi, $lo);
- }
- function get_table_pos($tag)
- {
- $offset = $this->tables[$tag]['offset'];
- $length = $this->tables[$tag]['length'];
- return array($offset, $length);
- }
- function seek($pos)
- {
- $this->_pos = $pos;
- fseek($this->fh, $this->_pos);
- }
- function skip($delta)
- {
- $this->_pos = $this->_pos + $delta;
- fseek($this->fh, $delta, SEEK_CUR);
- }
- function seek_table($tag, $offset_in_table = 0)
- {
- $tpos = $this->get_table_pos($tag);
- $this->_pos = $tpos[0] + $offset_in_table;
- fseek($this->fh, $this->_pos);
- return $this->_pos;
- }
- function read_tag()
- {
- $this->_pos += 4;
- return fread($this->fh, 4);
- }
- function read_short()
- {
- $this->_pos += 2;
- $s = fread($this->fh, 2);
- $a = (ord($s[0]) << 8) + ord($s[1]);
- if ($a & (1 << 15)) {
- $a = ($a - (1 << 16));
- }
- return $a;
- }
- function unpack_short($s)
- {
- $a = (ord($s[0]) << 8) + ord($s[1]);
- if ($a & (1 << 15)) {
- $a = ($a - (1 << 16));
- }
- return $a;
- }
- function read_ushort()
- {
- $this->_pos += 2;
- $s = fread($this->fh, 2);
- return (ord($s[0]) << 8) + ord($s[1]);
- }
- function read_ulong()
- {
- $this->_pos += 4;
- $s = fread($this->fh, 4);
-
- return (ord($s[0]) * 16777216) + (ord($s[1]) << 16) + (ord($s[2]) << 8) + ord($s[3]);
- }
- function get_ushort($pos)
- {
- fseek($this->fh, $pos);
- $s = fread($this->fh, 2);
- return (ord($s[0]) << 8) + ord($s[1]);
- }
- function get_ulong($pos)
- {
- fseek($this->fh, $pos);
- $s = fread($this->fh, 4);
-
- return (ord($s[0]) * 16777216) + (ord($s[1]) << 16) + (ord($s[2]) << 8) + ord($s[3]);
- }
- function pack_short($val)
- {
- if ($val < 0) {
- $val = abs($val);
- $val = ~$val;
- $val += 1;
- }
- return pack("n", $val);
- }
- function splice($stream, $offset, $value)
- {
- return substr($stream, 0, $offset) . $value . substr($stream, $offset + strlen($value));
- }
- function _set_ushort($stream, $offset, $value)
- {
- $up = pack("n", $value);
- return $this->splice($stream, $offset, $up);
- }
- function _set_short($stream, $offset, $val)
- {
- if ($val < 0) {
- $val = abs($val);
- $val = ~$val;
- $val += 1;
- }
- $up = pack("n", $val);
- return $this->splice($stream, $offset, $up);
- }
- function get_chunk($pos, $length)
- {
- fseek($this->fh, $pos);
- if ($length < 1) {
- return '';
- }
- return (fread($this->fh, $length));
- }
- function get_table($tag)
- {
- list($pos, $length) = $this->get_table_pos($tag);
- if ($length == 0) {
- return '';
- }
- fseek($this->fh, $pos);
- return (fread($this->fh, $length));
- }
- function add($tag, $data)
- {
- if ($tag == 'head') {
- $data = $this->splice($data, 8, "\0\0\0\0");
- }
- $this->otables[$tag] = $data;
- }
-
-
- function extractInfo($debug = false, $BMPonly = false, $kerninfo = false, $useOTL = 0)
- {
- $this->panose = array();
- $this->sFamilyClass = 0;
- $this->sFamilySubClass = 0;
-
-
-
- $name_offset = $this->seek_table("name");
- $format = $this->read_ushort();
- if ($format != 0 && $format != 1) {
- throw new MpdfException("Unknown name table format " . $format);
- }
- $numRecords = $this->read_ushort();
- $string_data_offset = $name_offset + $this->read_ushort();
- $names = array(1 => '', 2 => '', 3 => '', 4 => '', 6 => '');
- $K = array_keys($names);
- $nameCount = count($names);
- for ($i = 0; $i < $numRecords; $i++) {
- $platformId = $this->read_ushort();
- $encodingId = $this->read_ushort();
- $languageId = $this->read_ushort();
- $nameId = $this->read_ushort();
- $length = $this->read_ushort();
- $offset = $this->read_ushort();
- if (!in_array($nameId, $K))
- continue;
- $N = '';
- if ($platformId == 3 && $encodingId == 1 && $languageId == 0x409) {
- $opos = $this->_pos;
- $this->seek($string_data_offset + $offset);
- if ($length % 2 != 0) {
- throw new MpdfException("PostScript name is UTF-16BE string of odd length");
- }
- $length /= 2;
- $N = '';
- while ($length > 0) {
- $char = $this->read_ushort();
- $N .= (chr($char));
- $length -= 1;
- }
- $this->_pos = $opos;
- $this->seek($opos);
- } else if ($platformId == 1 && $encodingId == 0 && $languageId == 0) {
- $opos = $this->_pos;
- $N = $this->get_chunk($string_data_offset + $offset, $length);
- $this->_pos = $opos;
- $this->seek($opos);
- }
- if ($N && $names[$nameId] == '') {
- $names[$nameId] = $N;
- $nameCount -= 1;
- if ($nameCount == 0)
- break;
- }
- }
- if ($names[6])
- $psName = $names[6];
- else if ($names[4])
- $psName = preg_replace('/ /', '-', $names[4]);
- else if ($names[1])
- $psName = preg_replace('/ /', '-', $names[1]);
- else
- $psName = '';
- if (!$psName) {
- throw new MpdfException("Could not find PostScript font name: " . $this->filename);
- }
- if ($debug) {
- for ($i = 0; $i < count($psName); $i++) {
- $c = $psName[$i];
- $oc = ord($c);
- if ($oc > 126 || strpos(' [](){}<>/%', $c) !== false) {
- throw new MpdfException("psName=" . $psName . " contains invalid character " . $c . " ie U+" . ord(c));
- }
- }
- }
- $this->name = $psName;
- if ($names[1]) {
- $this->familyName = $names[1];
- } else {
- $this->familyName = $psName;
- }
- if ($names[2]) {
- $this->styleName = $names[2];
- } else {
- $this->styleName = 'Regular';
- }
- if ($names[4]) {
- $this->fullName = $names[4];
- } else {
- $this->fullName = $psName;
- }
- if ($names[3]) {
- $this->uniqueFontID = $names[3];
- } else {
- $this->uniqueFontID = $psName;
- }
- if ($names[6]) {
- $this->fullName = $names[6];
- }
-
-
-
- $this->seek_table("head");
- if ($debug) {
- $ver_maj = $this->read_ushort();
- $ver_min = $this->read_ushort();
- if ($ver_maj != 1) {
- throw new MpdfException('Unknown head table version ' . $ver_maj . '.' . $ver_min);
- }
- $this->fontRevision = $this->read_ushort() . $this->read_ushort();
- $this->skip(4);
- $magic = $this->read_ulong();
- if ($magic != 0x5F0F3CF5) {
- throw new MpdfException('Invalid head table magic ' . $magic);
- }
- $this->skip(2);
- }
- else {
- $this->skip(18);
- }
- $this->unitsPerEm = $unitsPerEm = $this->read_ushort();
- $scale = 1000 / $unitsPerEm;
- $this->skip(16);
- $xMin = $this->read_short();
- $yMin = $this->read_short();
- $xMax = $this->read_short();
- $yMax = $this->read_short();
- $this->bbox = array(($xMin * $scale), ($yMin * $scale), ($xMax * $scale), ($yMax * $scale));
- $this->skip(3 * 2);
- $indexToLocFormat = $this->read_ushort();
- $glyphDataFormat = $this->read_ushort();
- if ($glyphDataFormat != 0) {
- throw new MpdfException('Unknown glyph data format ' . $glyphDataFormat);
- }
-
-
-
-
- if (isset($this->tables["hhea"])) {
- $this->seek_table("hhea");
- $this->skip(4);
- $hheaAscender = $this->read_short();
- $hheaDescender = $this->read_short();
- $this->ascent = ($hheaAscender * $scale);
- $this->descent = ($hheaDescender * $scale);
- }
-
-
-
- if (isset($this->tables["OS/2"])) {
- $this->seek_table("OS/2");
- $version = $this->read_ushort();
- $this->skip(2);
- $usWeightClass = $this->read_ushort();
- $this->skip(2);
- $fsType = $this->read_ushort();
- if ($fsType == 0x0002 || ($fsType & 0x0300) != 0) {
- global $overrideTTFFontRestriction;
- if (!$overrideTTFFontRestriction) {
- throw new MpdfException('ERROR - Font file ' . $this->filename . ' cannot be embedded due to copyright restrictions.');
- }
- $this->restrictedUse = true;
- }
- $this->skip(20);
- $sF = $this->read_short();
- $this->sFamilyClass = ($sF >> 8);
- $this->sFamilySubClass = ($sF & 0xFF);
- $this->_pos += 10;
- $panose = fread($this->fh, 10);
- $this->panose = array();
- for ($p = 0; $p < strlen($panose); $p++) {
- $this->panose[] = ord($panose[$p]);
- }
- $this->skip(26);
- $sTypoAscender = $this->read_short();
- $sTypoDescender = $this->read_short();
- if (!$this->ascent)
- $this->ascent = ($sTypoAscender * $scale);
- if (!$this->descent)
- $this->descent = ($sTypoDescender * $scale);
- if ($version > 1) {
- $this->skip(16);
- $sCapHeight = $this->read_short();
- $this->capHeight = ($sCapHeight * $scale);
- } else {
- $this->capHeight = $this->ascent;
- }
- } else {
- $usWeightClass = 500;
- if (!$this->ascent)
- $this->ascent = ($yMax * $scale);
- if (!$this->descent)
- $this->descent = ($yMin * $scale);
- $this->capHeight = $this->ascent;
- }
- $this->stemV = 50 + intval(pow(($usWeightClass / 65.0), 2));
-
-
-
- $this->seek_table("post");
- if ($debug) {
- $ver_maj = $this->read_ushort();
- $ver_min = $this->read_ushort();
- if ($ver_maj < 1 || $ver_maj > 4) {
- throw new MpdfException('Unknown post table version ' . $ver_maj);
- }
- }
- else {
- $this->skip(4);
- }
- $this->italicAngle = $this->read_short() + $this->read_ushort() / 65536.0;
- $this->underlinePosition = $this->read_short() * $scale;
- $this->underlineThickness = $this->read_short() * $scale;
- $isFixedPitch = $this->read_ulong();
- $this->flags = 4;
- if ($this->italicAngle != 0)
- $this->flags = $this->flags | 64;
- if ($usWeightClass >= 600)
- $this->flags = $this->flags | 262144;
- if ($isFixedPitch)
- $this->flags = $this->flags | 1;
-
-
-
- $this->seek_table("hhea");
- if ($debug) {
- $ver_maj = $this->read_ushort();
- $ver_min = $this->read_ushort();
- if ($ver_maj != 1) {
- throw new MpdfException('Unknown hhea table version ' . $ver_maj);
- }
- $this->skip(28);
- }
- else {
- $this->skip(32);
- }
- $metricDataFormat = $this->read_ushort();
- if ($metricDataFormat != 0) {
- throw new MpdfException('Unknown horizontal metric data format ' . $metricDataFormat);
- }
- $numberOfHMetrics = $this->read_ushort();
- if ($numberOfHMetrics == 0) {
- throw new MpdfException('Number of horizontal metrics is 0');
- }
-
-
-
- $this->seek_table("maxp");
- if ($debug) {
- $ver_maj = $this->read_ushort();
- $ver_min = $this->read_ushort();
- if ($ver_maj != 1) {
- throw new MpdfException('Unknown maxp table version ' . $ver_maj);
- }
- }
- else {
- $this->skip(4);
- }
- $numGlyphs = $this->read_ushort();
-
-
-
- $cmap_offset = $this->seek_table("cmap");
- $this->skip(2);
- $cmapTableCount = $this->read_ushort();
- $unicode_cmap_offset = 0;
- for ($i = 0; $i < $cmapTableCount; $i++) {
- $platformID = $this->read_ushort();
- $encodingID = $this->read_ushort();
- $offset = $this->read_ulong();
- $save_pos = $this->_pos;
- if (($platformID == 3 && $encodingID == 1) || $platformID == 0) {
- $format = $this->get_ushort($cmap_offset + $offset);
- if ($format == 4) {
- if (!$unicode_cmap_offset)
- $unicode_cmap_offset = $cmap_offset + $offset;
- if ($BMPonly)
- break;
- }
- }
-
- else if ((($platformID == 3 && $encodingID == 10) || $platformID == 0) && !$BMPonly) {
- $format = $this->get_ushort($cmap_offset + $offset);
- if ($format == 12) {
- $unicode_cmap_offset = $cmap_offset + $offset;
- break;
- }
- }
- $this->seek($save_pos);
- }
- if (!$unicode_cmap_offset) {
- throw new MpdfException('Font (' . $this->filename . ') does not have cmap for Unicode (platform 3, encoding 1, format 4, or platform 0, any encoding, format 4)');
- }
- $sipset = false;
- $smpset = false;
-
- $this->GSUBScriptLang = array();
- $this->rtlPUAstr = '';
- $this->rtlPUAarr = array();
- $this->GSUBFeatures = array();
- $this->GSUBLookups = array();
- $this->GPOSScriptLang = array();
- $this->GPOSFeatures = array();
- $this->GPOSLookups = array();
- $this->glyphIDtoUni = '';
-
- if ($format == 12 && !$BMPonly) {
- $this->maxUniChar = 0;
- $this->seek($unicode_cmap_offset + 4);
- $length = $this->read_ulong();
- $limit = $unicode_cmap_offset + $length;
- $this->skip(4);
- $nGroups = $this->read_ulong();
- $glyphToChar = array();
- $charToGlyph = array();
- for ($i = 0; $i < $nGroups; $i++) {
- $startCharCode = $this->read_ulong();
- $endCharCode = $this->read_ulong();
- $startGlyphCode = $this->read_ulong();
- if ($endCharCode > 0x20000 && $endCharCode < 0x2FFFF) {
- $sipset = true;
- } else if ($endCharCode > 0x10000 && $endCharCode < 0x1FFFF) {
- $smpset = true;
- }
- $offset = 0;
- for ($unichar = $startCharCode; $unichar <= $endCharCode; $unichar++) {
- $glyph = $startGlyphCode + $offset;
- $offset++;
- if ($unichar < 0x30000) {
- $charToGlyph[$unichar] = $glyph;
- $this->maxUniChar = max($unichar, $this->maxUniChar);
- $glyphToChar[$glyph][] = $unichar;
- }
- }
- }
- } else {
- $glyphToChar = array();
- $charToGlyph = array();
- $this->getCMAP4($unicode_cmap_offset, $glyphToChar, $charToGlyph);
- }
- $this->sipset = $sipset;
- $this->smpset = $smpset;
-
-
-
- if ($this->useOTL) {
- $bctr = 0xE000;
- for ($gid = 1; $gid < $numGlyphs; $gid++) {
- if (!isset($glyphToChar[$gid])) {
- while (isset($charToGlyph[$bctr])) {
- $bctr++;
- }
- if (($bctr > 0xF8FF) && ($bctr < 0x2CEB0)) {
- if (!$BMPonly) {
- $bctr = 0x2CEB0;
- $this->sipset = $sipset = true;
- while (isset($charToGlyph[$bctr])) {
- $bctr++;
- }
- } else {
- throw new MpdfException($names[1] . " : WARNING - The font does not have enough space to map all (unmapped) included glyphs into Private Use Area U+E000 - U+F8FF");
- }
- }
- $glyphToChar[$gid][] = $bctr;
- $charToGlyph[$bctr] = $gid;
- $this->maxUniChar = max($bctr, $this->maxUniChar);
- $bctr++;
- }
- }
- }
- $this->glyphToChar = $glyphToChar;
- $this->charToGlyph = $charToGlyph;
-
-
- $this->GSUBScriptLang = array();
- $this->rtlPUAstr = '';
- $this->rtlPUAarr = array();
- if ($useOTL) {
- $this->_getGDEFtables();
- list($this->GSUBScriptLang, $this->GSUBFeatures, $this->GSUBLookups, $this->rtlPUAstr, $this->rtlPUAarr) = $this->_getGSUBtables();
- list($this->GPOSScriptLang, $this->GPOSFeatures, $this->GPOSLookups) = $this->_getGPOStables();
- $this->glyphIDtoUni = str_pad('', 256 * 256 * 3, "\x00");
- foreach ($glyphToChar AS $gid => $arr) {
- if (isset($glyphToChar[$gid][0])) {
- $char = $glyphToChar[$gid][0];
- if ($char != 0 && $char != 65535) {
- $this->glyphIDtoUni[$gid * 3] = chr($char >> 16);
- $this->glyphIDtoUni[$gid * 3 + 1] = chr(($char >> 8) & 0xFF);
- $this->glyphIDtoUni[$gid * 3 + 2] = chr($char & 0xFF);
- }
- }
- }
- }
-
-
-
-
- $this->getHMTX($numberOfHMetrics, $numGlyphs, $glyphToChar, $scale);
-
-
-
- if ($kerninfo) {
-
- $kern_offset = $this->seek_table("kern");
- $version = $this->read_ushort();
- $nTables = $this->read_ushort();
-
- $sversion = $this->read_ushort();
- $slength = $this->read_ushort();
- $scoverage = $this->read_ushort();
- $format = $scoverage >> 8;
- if ($kern_offset && $version == 0 && $format == 0) {
-
- $nPairs = $this->read_ushort();
- $this->skip(6);
- for ($i = 0; $i < $nPairs; $i++) {
- $left = $this->read_ushort();
- $right = $this->read_ushort();
- $val = $this->read_short();
- if (count($glyphToChar[$left]) == 1 && count($glyphToChar[$right]) == 1) {
- if ($left != 32 && $right != 32) {
- $this->kerninfo[$glyphToChar[$left][0]][$glyphToChar[$right][0]] = intval($val * $scale);
- }
- }
- }
- }
- }
- }
-
- function _getGDEFtables()
- {
-
-
-
-
- if (isset($this->tables["GDEF"])) {
- if ($this->mode == 'summary') {
- $this->mpdf->WriteHTML('<h1>GDEF table</h1>');
- }
- $gdef_offset = $this->seek_table("GDEF");
-
- $ver_maj = $this->read_ushort();
- $ver_min = $this->read_ushort();
-
- $GlyphClassDef_offset = $this->read_ushort();
- $AttachList_offset = $this->read_ushort();
- $LigCaretList_offset = $this->read_ushort();
- $MarkAttachClassDef_offset = $this->read_ushort();
- if ($ver_min == 2) {
- $MarkGlyphSetsDef_offset = $this->read_ushort();
- }
-
- $this->seek($gdef_offset + $GlyphClassDef_offset);
-
- $GlyphByClass = $this->_getClassDefinitionTable();
- if ($this->mode == 'summary') {
- $this->mpdf->WriteHTML('<h2>Glyph classes</h2>');
- }
- if (isset($GlyphByClass[1]) && count($GlyphByClass[1]) > 0) {
- $this->GlyphClassBases = $this->formatClassArr($GlyphByClass[1]);
- if ($this->mode == 'summary') {
- $this->mpdf->WriteHTML('<h3>Glyph class 1</h3>');
- $this->mpdf->WriteHTML('<h5>Base glyph (single character, spacing glyph)</h5>');
- $html = '';
- $html .= '<div class="glyphs">';
- foreach ($GlyphByClass[1] AS $g) {
- $html .= '&#x' . $g . '; ';
- }
- $html .= '</div>';
- $this->mpdf->WriteHTML($html);
- }
- } else {
- $this->GlyphClassBases = '';
- }
- if (isset($GlyphByClass[2]) && count($GlyphByClass[2]) > 0) {
- $this->GlyphClassLigatures = $this->formatClassArr($GlyphByClass[2]);
- if ($this->mode == 'summary') {
- $this->mpdf->WriteHTML('<h3>Glyph class 2</h3>');
- $this->mpdf->WriteHTML('<h5>Ligature glyph (multiple character, spacing glyph)</h5>');
- $html = '';
- $html .= '<div class="glyphs">';
- foreach ($GlyphByClass[2] AS $g) {
- $html .= '&#x' . $g . '; ';
- }
- $html .= '</div>';
- $this->mpdf->WriteHTML($html);
- }
- } else {
- $this->GlyphClassLigatures = '';
- }
- if (isset($GlyphByClass[3]) && count($GlyphByClass[3]) > 0) {
- $this->GlyphClassMarks = $this->formatClassArr($GlyphByClass[3]);
- if ($this->mode == 'summary') {
- $this->mpdf->WriteHTML('<h3>Glyph class 3</h3>');
- $this->mpdf->WriteHTML('<h5>Mark glyph (non-spacing combining glyph)</h5>');
- $html = '';
- $html .= '<div class="glyphs">';
- foreach ($GlyphByClass[3] AS $g) {
- $html .= '◌&#x' . $g . '; ';
- }
- $html .= '</div>';
- $this->mpdf->WriteHTML($html);
- }
- } else {
- $this->GlyphClassMarks = '';
- }
- if (isset($GlyphByClass[4]) && count($GlyphByClass[4]) > 0) {
- $this->GlyphClassComponents = $this->formatClassArr($GlyphByClass[4]);
- if ($this->mode == 'summary') {
- $this->mpdf->WriteHTML('<h3>Glyph class 4</h3>');
- $this->mpdf->WriteHTML('<h5>Component glyph (part of single character, spacing glyph)</h5>');
- $html = '';
- $html .= '<div class="glyphs">';
- foreach ($GlyphByClass[4] AS $g) {
- $html .= '&#x' . $g . '; ';
- }
- $html .= '</div>';
- $this->mpdf->WriteHTML($html);
- }
- } else {
- $this->GlyphClassComponents = '';
- }
- $Marks = $GlyphByClass[3];
-
-
-
-
-
- if ($MarkAttachClassDef_offset) {
- if ($this->mode == 'summary') {
- $this->mpdf->WriteHTML('<h1>Mark Attachment Types</h1>');
- }
- $this->seek($gdef_offset + $MarkAttachClassDef_offset);
- $MarkAttachmentTypes = $this->_getClassDefinitionTable();
- foreach ($MarkAttachmentTypes AS $class => $glyphs) {
- if (is_array($Marks) && count($Marks)) {
- $mat = array_diff($Marks, $MarkAttachmentTypes[$class]);
- sort($mat, SORT_STRING);
- } else {
- $mat = array();
- }
- $this->MarkAttachmentType[$class] = $this->formatClassArr($mat);
- if ($this->mode == 'summary') {
- $this->mpdf->WriteHTML('<h3>Mark Attachment Type: ' . $class . '</h3>');
- $html = '';
- $html .= '<div class="glyphs">';
- foreach ($glyphs AS $g) {
- $html .= '◌&#x' . $g . '; ';
- }
- $html .= '</div>';
- $this->mpdf->WriteHTML($html);
- }
- }
- } else {
- $this->MarkAttachmentType = array();
- }
-
- if ($ver_min == 2 && $MarkGlyphSetsDef_offset) {
- if ($this->mode == 'summary') {
- $this->mpdf->WriteHTML('<h1>Mark Glyph Sets</h1>');
- }
- $this->seek($gdef_offset + $MarkGlyphSetsDef_offset);
- $MarkSetTableFormat = $this->read_ushort();
- $MarkSetCount = $this->read_ushort();
- $MarkSetOffset = array();
- for ($i = 0; $i < $MarkSetCount; $i++) {
- $MarkSetOffset[] = $this->read_ulong();
- }
- for ($i = 0; $i < $MarkSetCount; $i++) {
- $this->seek($MarkSetOffset[$i]);
- $glyphs = $this->_getCoverage();
- $this->MarkGlyphSets[$i] = $this->formatClassArr($glyphs);
- if ($this->mode == 'summary') {
- $this->mpdf->WriteHTML('<h3>Mark Glyph Set class: ' . $i . '</h3>');
- $html = '';
- $html .= '<div class="glyphs">';
- foreach ($glyphs AS $g) {
- $html .= '◌&#x' . $g . '; ';
- }
- $html .= '</div>';
- $this->mpdf->WriteHTML($html);
- }
- }
- } else {
- $this->MarkGlyphSets = array();
- }
- } else {
- $this->mpdf->WriteHTML('<div>GDEF table not defined</div>');
- }
- }
- function _getClassDefinitionTable($offset = 0)
- {
- if ($offset > 0) {
- $this->seek($offset);
- }
-
- $ClassFormat = $this->read_ushort();
- $GlyphByClass = array();
- if ($ClassFormat == 1) {
- $StartGlyph = $this->read_ushort();
- $GlyphCount = $this->read_ushort();
- for ($i = 0; $i < $GlyphCount; $i++) {
- $gid = $StartGlyph + $i;
- $class = $this->read_ushort();
- $GlyphByClass[$class][] = unicode_hex($this->glyphToChar[$gid][0]);
- }
- } else if ($ClassFormat == 2) {
- $tableCount = $this->read_ushort();
- for ($i = 0; $i < $tableCount; $i++) {
- $startGlyphID = $this->read_ushort();
- $endGlyphID = $this->read_ushort();
- $class = $this->read_ushort();
- for ($gid = $startGlyphID; $gid <= $endGlyphID; $gid++) {
- $GlyphByClass[$class][] = unicode_hex($this->glyphToChar[$gid][0]);
- }
- }
- }
- ksort($GlyphByClass);
- return $GlyphByClass;
- }
- function _getGSUBtables()
- {
-
-
-
- if (isset($this->tables["GSUB"])) {
- $this->mpdf->WriteHTML('<h1>GSUB Tables</h1>');
- $ffeats = array();
- $gsub_offset = $this->seek_table("GSUB");
- $this->skip(4);
- $ScriptList_offset = $gsub_offset + $this->read_ushort();
- $FeatureList_offset = $gsub_offset + $this->read_ushort();
- $LookupList_offset = $gsub_offset + $this->read_ushort();
-
- $this->seek($ScriptList_offset);
- $ScriptCount = $this->read_ushort();
- for ($i = 0; $i < $ScriptCount; $i++) {
- $ScriptTag = $this->read_tag();
- $ScriptTableOffset = $this->read_ushort();
- $ffeats[$ScriptTag] = $ScriptList_offset + $ScriptTableOffset;
- }
-
- foreach ($ffeats AS $t => $o) {
- $ls = array();
- $this->seek($o);
- $DefLangSys_offset = $this->read_ushort();
- if ($DefLangSys_offset > 0) {
- $ls['DFLT'] = $DefLangSys_offset + $o;
- }
- $LangSysCount = $this->read_ushort();
- for ($i = 0; $i < $LangSysCount; $i++) {
- $LangTag = $this->read_tag();
- $LangTableOffset = $this->read_ushort();
- $ls[$LangTag] = $o + $LangTableOffset;
- }
- $ffeats[$t] = $ls;
- }
-
-
- foreach ($ffeats AS $st => $scripts) {
- foreach ($scripts AS $t => $o) {
- $FeatureIndex = array();
- $langsystable_offset = $o;
- $this->seek($langsystable_offset);
- $LookUpOrder = $this->read_ushort();
- $ReqFeatureIndex = $this->read_ushort();
- if ($ReqFeatureIndex != 0xFFFF) {
- $FeatureIndex[] = $ReqFeatureIndex;
- }
- $FeatureCount = $this->read_ushort();
- for ($i = 0; $i < $FeatureCount; $i++) {
- $FeatureIndex[] = $this->read_ushort();
- }
- $ffeats[$st][$t] = $FeatureIndex;
- }
- }
-
- $this->seek($FeatureList_offset);
- $FeatureCount = $this->read_ushort();
- $Feature = array();
- for ($i = 0; $i < $FeatureCount; $i++) {
- $Feature[$i] = array('tag' => $this->read_tag());
- $Feature[$i]['offset'] = $FeatureList_offset + $this->read_ushort();
- }
- for ($i = 0; $i < $FeatureCount; $i++) {
- $this->seek($Feature[$i]['offset']);
- $this->read_ushort();
- $Feature[$i]['LookupCount'] = $Lookupcount = $this->read_ushort();
- $Feature[$i]['LookupListIndex'] = array();
- for ($c = 0; $c < $Lookupcount; $c++) {
- $Feature[$i]['LookupListIndex'][] = $this->read_ushort();
- }
- }
- foreach ($ffeats AS $st => $scripts) {
- foreach ($scripts AS $t => $o) {
- $FeatureIndex = $ffeats[$st][$t];
- foreach ($FeatureIndex AS $k => $fi) {
- $ffeats[$st][$t][$k] = $Feature[$fi];
- }
- }
- }
-
- $gsub = array();
- $GSUBScriptLang = array();
- foreach ($ffeats AS $st => $scripts) {
- foreach ($scripts AS $t => $langsys) {
- $lg = array();
- foreach ($langsys AS $ft) {
- $lg[$ft['LookupListIndex'][0]] = $ft;
- }
-
- ksort($lg);
- foreach ($lg AS $ft) {
- $gsub[$st][$t][$ft['tag']] = $ft['LookupListIndex'];
- }
- if (!isset($GSUBScriptLang[$st])) {
- $GSUBScriptLang[$st] = '';
- }
- $GSUBScriptLang[$st] .= $t . ' ';
- }
- }
- if ($this->mode == 'summary') {
- $this->mpdf->WriteHTML('<h3>GSUB Scripts & Languages</h3>');
- $this->mpdf->WriteHTML('<div class="glyphs">');
- $html = '';
- if (count($gsub)) {
- foreach ($gsub AS $st => $g) {
- $html .= '<h5>' . $st . '</h5>';
- foreach ($g AS $l => $t) {
- $html .= '<div><a href="font_dump_OTL.php?script=' . $st . '&lang=' . $l . '">' . $l . '</a></b>: ';
- foreach ($t AS $tag => $o) {
- $html .= $tag . ' ';
- }
- $html .= '</div>';
- }
- }
- } else {
- $html .= '<div>No entries in GSUB table.</div>';
- }
- $this->mpdf->WriteHTML($html);
- $this->mpdf->WriteHTML('</div>');
- return 0;
- }
-
-
- $this->seek($LookupList_offset);
- $LookupCount = $this->read_ushort();
- $GSLookup = array();
- $Offsets = array();
- $SubtableCount = array();
- for ($i = 0; $i < $LookupCount; $i++) {
- $Offsets[$i] = $LookupList_offset + $this->read_ushort();
- }
- for ($i = 0; $i < $LookupCount; $i++) {
- $this->seek($Offsets[$i]);
- $GSLookup[$i]['Type'] = $this->read_ushort();
- $GSLookup[$i]['Flag'] = $flag = $this->read_ushort();
- $GSLookup[$i]['SubtableCount'] = $SubtableCount[$i] = $this->read_ushort();
- for ($c = 0; $c < $SubtableCount[$i]; $c++) {
- $GSLookup[$i]['Subtables'][$c] = $Offsets[$i] + $this->read_ushort();
- }
-
- if (($flag & 0x0010) == 0x0010) {
- $GSLookup[$i]['MarkFilteringSet'] = $this->read_ushort();
- }
-
-
- if ($GSLookup[$i]['Type'] == 7) {
-
- for ($c = 0; $c < $SubtableCount[$i]; $c++) {
- $this->seek($GSLookup[$i]['Subtables'][$c]);
- $ExtensionPosFormat = $this->read_ushort();
- $type = $this->read_ushort();
- $GSLookup[$i]['Subtables'][$c] = $GSLookup[$i]['Subtables'][$c] + $this->read_ulong();
- }
- $GSLookup[$i]['Type'] = $type;
- }
- }
-
-
- $this->GSLuCoverage = array();
- for ($i = 0; $i < $LookupCount; $i++) {
- for ($c = 0; $c < $GSLookup[$i]['SubtableCount']; $c++) {
- $this->seek($GSLookup[$i]['Subtables'][$c]);
- $PosFormat = $this->read_ushort();
- if ($GSLookup[$i]['Type'] == 5 && $PosFormat == 3) {
- $this->skip(4);
- } else if ($GSLookup[$i]['Type'] == 6 && $PosFormat == 3) {
- $BacktrackGlyphCount = $this->read_ushort();
- $this->skip(2 * $BacktrackGlyphCount + 2);
- }
-
- $Coverage = $GSLookup[$i]['Subtables'][$c] + $this->read_ushort();
- $this->seek($Coverage);
- $glyphs = $this->_getCoverage();
- $this->GSLuCoverage[$i][$c] = implode('|', $glyphs);
- }
- }
-
- $s = '<?php
- $GSLuCoverage = ' . var_export($this->GSLuCoverage, true) . ';
- ?>';
-
- $s = '<?php
- $GlyphClassBases = \'' . $this->GlyphClassBases . '\';
- $GlyphClassMarks = \'' . $this->GlyphClassMarks . '\';
- $GlyphClassLigatures = \'' . $this->GlyphClassLigatures . '\';
- $GlyphClassComponents = \'' . $this->GlyphClassComponents . '\';
- $MarkGlyphSets = ' . var_export($this->MarkGlyphSets, true) . ';
- $MarkAttachmentType = ' . var_export($this->MarkAttachmentType, true) . ';
- ?>';
-
-
-
-
-
-
-
- $this->seek($LookupList_offset);
- $LookupCount = $this->read_ushort();
- $Lookup = array();
- for ($i = 0; $i < $LookupCount; $i++) {
- $Lookup[$i]['offset'] = $LookupList_offset + $this->read_ushort();
- }
- for ($i = 0; $i < $LookupCount; $i++) {
- $this->seek($Lookup[$i]['offset']);
- $Lookup[$i]['Type'] = $this->read_ushort();
- $Lookup[$i]['Flag'] = $flag = $this->read_ushort();
- $Lookup[$i]['SubtableCount'] = $this->read_ushort();
- for ($c = 0; $c < $Lookup[$i]['SubtableCount']; $c++) {
- $Lookup[$i]['Subtable'][$c]['Offset'] = $Lookup[$i]['offset'] + $this->read_ushort();
- }
-
- if (($flag & 0x0010) == 0x0010) {
- $Lookup[$i]['MarkFilteringSet'] = $this->read_ushort();
- } else {
- $Lookup[$i]['MarkFilteringSet'] = '';
- }
-
- if ($Lookup[$i]['Type'] == 7) {
-
- for ($c = 0; $c < $Lookup[$i]['SubtableCount']; $c++) {
- $this->seek($Lookup[$i]['Subtable'][$c]['Offset']);
- $ExtensionPosFormat = $this->read_ushort();
- $type = $this->read_ushort();
- $Lookup[$i]['Subtable'][$c]['Offset'] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->read_ulong();
- }
- $Lookup[$i]['Type'] = $type;
- }
- }
-
-
- for ($i = 0; $i < $LookupCount; $i++) {
- for ($c = 0; $c < $Lookup[$i]['SubtableCount']; $c++) {
- $this->seek($Lookup[$i]['Subtable'][$c]['Offset']);
- $SubstFormat = $this->read_ushort();
- $Lookup[$i]['Subtable'][$c]['Format'] = $SubstFormat;
-
-
- if ($Lookup[$i]['Type'] == 1) {
- $Lookup[$i]['Subtable'][$c]['CoverageTableOffset'] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->read_ushort();
- if ($SubstFormat == 1) {
- $Lookup[$i]['Subtable'][$c]['DeltaGlyphID'] = $this->read_short();
- } else if ($SubstFormat == 2) {
- $GlyphCount = $this->read_ushort();
- for ($g = 0; $g < $GlyphCount; $g++) {
- $Lookup[$i]['Subtable'][$c]['Glyphs'][] = $this->read_ushort();
- }
- }
- }
-
- else if ($Lookup[$i]['Type'] == 2) {
- $Lookup[$i]['Subtable'][$c]['CoverageTableOffset'] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->read_ushort();
- $Lookup[$i]['Subtable'][$c]['SequenceCount'] = $SequenceCount = $this->read_short();
- for ($s = 0; $s < $SequenceCount; $s++) {
- $Lookup[$i]['Subtable'][$c]['Sequences'][$s]['Offset'] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->read_short();
- }
- for ($s = 0; $s < $SequenceCount; $s++) {
-
- $this->seek($Lookup[$i]['Subtable'][$c]['Sequences'][$s]['Offset']);
- $Lookup[$i]['Subtable'][$c]['Sequences'][$s]['GlyphCount'] = $this->read_short();
- for ($g = 0; $g < $Lookup[$i]['Subtable'][$c]['Sequences'][$s]['GlyphCount']; $g++) {
- $Lookup[$i]['Subtable'][$c]['Sequences'][$s]['SubstituteGlyphID'][] = $this->read_ushort();
- }
- }
- }
-
- else if ($Lookup[$i]['Type'] == 3) {
- $Lookup[$i]['Subtable'][$c]['CoverageTableOffset'] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->read_ushort();
- $Lookup[$i]['Subtable'][$c]['AlternateSetCount'] = $AlternateSetCount = $this->read_short();
- for ($s = 0; $s < $AlternateSetCount; $s++) {
- $Lookup[$i]['Subtable'][$c]['AlternateSets'][$s]['Offset'] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->read_short();
- }
- for ($s = 0; $s < $AlternateSetCount; $s++) {
-
- $this->seek($Lookup[$i]['Subtable'][$c]['AlternateSets'][$s]['Offset']);
- $Lookup[$i]['Subtable'][$c]['AlternateSets'][$s]['GlyphCount'] = $this->read_short();
- for ($g = 0; $g < $Lookup[$i]['Subtable'][$c]['AlternateSets'][$s]['GlyphCount']; $g++) {
- $Lookup[$i]['Subtable'][$c]['AlternateSets'][$s]['SubstituteGlyphID'][] = $this->read_ushort();
- }
- }
- }
-
- else if ($Lookup[$i]['Type'] == 4) {
- $Lookup[$i]['Subtable'][$c]['CoverageTableOffset'] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->read_ushort();
- $Lookup[$i]['Subtable'][$c]['LigSetCount'] = $LigSetCount = $this->read_short();
- for ($s = 0; $s < $LigSetCount; $s++) {
- $Lookup[$i]['Subtable'][$c]['LigSet'][$s]['Offset'] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->read_short();
- }
- for ($s = 0; $s < $LigSetCount; $s++) {
-
- $this->seek($Lookup[$i]['Subtable'][$c]['LigSet'][$s]['Offset']);
- $Lookup[$i]['Subtable'][$c]['LigSet'][$s]['LigCount'] = $this->read_short();
- for ($g = 0; $g < $Lookup[$i]['Subtable'][$c]['LigSet'][$s]['LigCount']; $g++) {
- $Lookup[$i]['Subtable'][$c]['LigSet'][$s]['LigatureOffset'][$g] = $Lookup[$i]['Subtable'][$c]['LigSet'][$s]['Offset'] + $this->read_ushort();
- }
- }
- for ($s = 0; $s < $LigSetCount; $s++) {
- for ($g = 0; $g < $Lookup[$i]['Subtable'][$c]['LigSet'][$s]['LigCount']; $g++) {
-
- $this->seek($Lookup[$i]['Subtable'][$c]['LigSet'][$s]['LigatureOffset'][$g]);
- $Lookup[$i]['Subtable'][$c]['LigSet'][$s]['Ligature'][$g]['LigGlyph'] = $this->read_ushort();
- $Lookup[$i]['Subtable'][$c]['LigSet'][$s]['Ligature'][$g]['CompCount'] = $this->read_ushort();
- for ($l = 1; $l < $Lookup[$i]['Subtable'][$c]['LigSet'][$s]['Ligature'][$g]['CompCount']; $l++) {
- $Lookup[$i]['Subtable'][$c]['LigSet'][$s]['Ligature'][$g]['GlyphID'][$l] = $this->read_ushort();
- }
- }
- }
- }
-
- else if ($Lookup[$i]['Type'] == 5) {
-
- if ($SubstFormat == 1) {
- $Lookup[$i]['Subtable'][$c]['CoverageTableOffset'] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->read_ushort();
- $Lookup[$i]['Subtable'][$c]['SubRuleSetCount'] = $SubRuleSetCount = $this->read_short();
- for ($s = 0; $s < $SubRuleSetCount; $s++) {
- $Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['Offset'] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->read_short();
- }
- for ($s = 0; $s < $SubRuleSetCount; $s++) {
-
- $this->seek($Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['Offset']);
- $Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['SubRuleCount'] = $this->read_short();
- for ($g = 0; $g < $Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['SubRuleCount']; $g++) {
- $Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['SubRuleOffset'][$g] = $Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['Offset'] + $this->read_ushort();
- }
- }
- for ($s = 0; $s < $SubRuleSetCount; $s++) {
-
- for ($g = 0; $g < $Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['SubRuleCount']; $g++) {
-
- $this->seek($Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['SubRuleOffset'][$g]);
- $Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['SubRule'][$g]['GlyphCount'] = $this->read_ushort();
- $Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['SubRule'][$g]['SubstCount'] = $this->read_ushort();
-
- for ($l = 1; $l < $Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['SubRule'][$g]['GlyphCount']; $l++) {
- $Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['SubRule'][$g]['Input'][$l] = $this->read_ushort();
- }
-
- for ($l = 0; $l < $Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['SubRule'][$g]['SubstCount']; $l++) {
- $Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['SubRule'][$g]['SubstLookupRecord'][$l]['SequenceIndex'] = $this->read_ushort();
- $Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['SubRule'][$g]['SubstLookupRecord'][$l]['LookupListIndex'] = $this->read_ushort();
- }
- }
- }
- }
-
- else if ($SubstFormat == 2) {
- $Lookup[$i]['Subtable'][$c]['CoverageTableOffset'] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->read_ushort();
- $Lookup[$i]['Subtable'][$c]['ClassDefOffset'] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->read_ushort();
- $Lookup[$i]['Subtable'][$c]['SubClassSetCnt'] = $this->read_ushort();
- for ($b = 0; $b < $Lookup[$i]['Subtable'][$c]['SubClassSetCnt']; $b++) {
- $offset = $this->read_ushort();
- if ($offset == 0x0000) {
- $Lookup[$i]['Subtable'][$c]['SubClassSetOffset'][] = 0;
- } else {
- $Lookup[$i]['Subtable'][$c]['SubClassSetOffset'][] = $Lookup[$i]['Subtable'][$c]['Offset'] + $offset;
- }
- }
- } else {
- throw new MpdfException("GPOS Lookup Type " . $Lookup[$i]['Type'] . ", Format " . $SubstFormat . " not supported (ttfontsuni.php).");
- }
- }
-
- else if ($Lookup[$i]['Type'] == 6) {
-
- if ($SubstFormat == 1) {
- $Lookup[$i]['Subtable'][$c]['CoverageTableOffset'] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->read_ushort();
- $Lookup[$i]['Subtable'][$c]['ChainSubRuleSetCount'] = $this->read_ushort();
- for ($b = 0; $b < $Lookup[$i]['Subtable'][$c]['ChainSubRuleSetCount']; $b++) {
- $Lookup[$i]['Subtable'][$c]['ChainSubRuleSetOffset'][] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->read_ushort();
- }
- }
-
- else if ($SubstFormat == 2) {
- $Lookup[$i]['Subtable'][$c]['CoverageTableOffset'] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->read_ushort();
- $Lookup[$i]['Subtable'][$c]['BacktrackClassDefOffset'] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->read_ushort();
- $Lookup[$i]['Subtable'][$c]['InputClassDefOffset'] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->read_ushort();
- $Lookup[$i]['Subtable'][$c]['LookaheadClassDefOffset'] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->read_ushort();
- $Lookup[$i]['Subtable'][$c]['ChainSubClassSetCnt'] = $this->read_ushort();
- for ($b = 0; $b < $Lookup[$i]['Subtable'][$c]['ChainSubClassSetCnt']; $b++) {
- $offset = $this->read_ushort();
- if ($offset == 0x0000) {
- $Lookup[$i]['Subtable'][$c]['ChainSubClassSetOffset'][] = $offset;
- } else {
- $Lookup[$i]['Subtable'][$c]['ChainSubClassSetOffset'][] = $Lookup[$i]['Subtable'][$c]['Offset'] + $offset;
- }
- }
- }
-
- else if ($SubstFormat == 3) {
- $Lookup[$i]['Subtable'][$c]['BacktrackGlyphCount'] = $this->read_ushort();
- for ($b = 0; $b < $Lookup[$i]['Subtable'][$c]['BacktrackGlyphCount']; $b++) {
- $Lookup[$i]['Subtable'][$c]['CoverageBacktrack'][] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->read_ushort();
- }
- $Lookup[$i]['Subtable'][$c]['InputGlyphCount'] = $this->read_ushort();
- for ($b = 0; $b < $Lookup[$i]['Subtable'][$c]['InputGlyphCount']; $b++) {
- $Lookup[$i]['Subtable'][$c]['CoverageInput'][] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->read_ushort();
- }
- $Lookup[$i]['Subtable'][$c]['LookaheadGlyphCount'] = $this->read_ushort();
- for ($b = 0; $b < $Lookup[$i]['Subtable'][$c]['LookaheadGlyphCount']; $b++) {
- $Lookup[$i]['Subtable'][$c]['CoverageLookahead'][] = $Lookup[$i]['Subtable'][$c]['Offset'] + $this->read_ushort();
- }
- $Lookup[$i]['Subtable'][$c]['SubstCount'] = $this->read_ushort();
- for ($b = 0; $b < $Lookup[$i]['Subtable'][$c]['SubstCount']; $b++) {
- $Lookup[$i]['Subtable'][$c]['SubstLookupRecord'][$b]['SequenceIndex'] = $this->read_ushort();
- $Lookup[$i]['Subtable'][$c]['SubstLookupRecord'][$b]['LookupListIndex'] = $this->read_ushort();
-
- }
- }
- } else {
- throw new MpdfException("Lookup Type " . $Lookup[$i]['Type'] . " not supported.");
- }
- }
- }
-
-
-
- for ($i = 0; $i < $LookupCount; $i++) {
- for ($c = 0; $c < $Lookup[$i]['SubtableCount']; $c++) {
- $SubstFormat = $Lookup[$i]['Subtable'][$c]['Format'];
-
- if ($Lookup[$i]['Type'] == 1) {
- $this->seek($Lookup[$i]['Subtable'][$c]['CoverageTableOffset']);
- $glyphs = $this->_getCoverage(false);
- for ($g = 0; $g < count($glyphs); $g++) {
- $replace = array();
- $substitute = array();
- $replace[] = unicode_hex($this->glyphToChar[$glyphs[$g]][0]);
-
- if ($this->_checkGSUBignore($Lookup[$i]['Flag'], $replace[0], $Lookup[$i]['MarkFilteringSet'])) {
- continue;
- }
- if (isset($Lookup[$i]['Subtable'][$c]['DeltaGlyphID'])) {
- $substitute[] = unicode_hex($this->glyphToChar[($glyphs[$g] + $Lookup[$i]['Subtable'][$c]['DeltaGlyphID'])][0]);
- } else {
- $substitute[] = unicode_hex($this->glyphToChar[($Lookup[$i]['Subtable'][$c]['Glyphs'][$g])][0]);
- }
- $Lookup[$i]['Subtable'][$c]['subs'][] = array('Replace' => $replace, 'substitute' => $substitute);
- }
- }
-
- else if ($Lookup[$i]['Type'] == 2) {
- $this->seek($Lookup[$i]['Subtable'][$c]['CoverageTableOffset']);
- $glyphs = $this->_getCoverage();
- for ($g = 0; $g < count($glyphs); $g++) {
- $replace = array();
- $substitute = array();
- $replace[] = $glyphs[$g];
-
- if ($this->_checkGSUBignore($Lookup[$i]['Flag'], $replace[0], $Lookup[$i]['MarkFilteringSet'])) {
- continue;
- }
- if (!isset($Lookup[$i]['Subtable'][$c]['Sequences'][$g]['SubstituteGlyphID']) || count($Lookup[$i]['Subtable'][$c]['Sequences'][$g]['SubstituteGlyphID']) == 0) {
- continue;
- }
- foreach ($Lookup[$i]['Subtable'][$c]['Sequences'][$g]['SubstituteGlyphID'] AS $sub) {
- $substitute[] = unicode_hex($this->glyphToChar[$sub][0]);
- }
- $Lookup[$i]['Subtable'][$c]['subs'][] = array('Replace' => $replace, 'substitute' => $substitute);
- }
- }
-
- else if ($Lookup[$i]['Type'] == 3) {
- $this->seek($Lookup[$i]['Subtable'][$c]['CoverageTableOffset']);
- $glyphs = $this->_getCoverage();
- for ($g = 0; $g < count($glyphs); $g++) {
- $replace = array();
- $substitute = array();
- $replace[] = $glyphs[$g];
-
- if ($this->_checkGSUBignore($Lookup[$i]['Flag'], $replace[0], $Lookup[$i]['MarkFilteringSet'])) {
- continue;
- }
- for ($gl = 0; $gl < $Lookup[$i]['Subtable'][$c]['AlternateSets'][$g]['GlyphCount']; $gl++) {
- $gid = $Lookup[$i]['Subtable'][$c]['AlternateSets'][$g]['SubstituteGlyphID'][$gl];
- $substitute[] = unicode_hex($this->glyphToChar[$gid][0]);
- }
-
-
- $Lookup[$i]['Subtable'][$c]['subs'][] = array('Replace' => $replace, 'substitute' => $substitute);
- }
- if ($i == 166) {
- print_r($Lookup[$i]['Subtable']);
- exit;
- }
- }
-
- else if ($Lookup[$i]['Type'] == 4) {
- $this->seek($Lookup[$i]['Subtable'][$c]['CoverageTableOffset']);
- $glyphs = $this->_getCoverage();
- $LigSetCount = $Lookup[$i]['Subtable'][$c]['LigSetCount'];
- for ($s = 0; $s < $LigSetCount; $s++) {
- for ($g = 0; $g < $Lookup[$i]['Subtable'][$c]['LigSet'][$s]['LigCount']; $g++) {
- $replace = array();
- $substitute = array();
- $replace[] = $glyphs[$s];
-
- if ($this->_checkGSUBignore($Lookup[$i]['Flag'], $replace[0], $Lookup[$i]['MarkFilteringSet'])) {
- continue;
- }
- for ($l = 1; $l < $Lookup[$i]['Subtable'][$c]['LigSet'][$s]['Ligature'][$g]['CompCount']; $l++) {
- $gid = $Lookup[$i]['Subtable'][$c]['LigSet'][$s]['Ligature'][$g]['GlyphID'][$l];
- $rpl = unicode_hex($this->glyphToChar[$gid][0]);
-
- if ($this->_checkGSUBignore($Lookup[$i]['Flag'], $rpl, $Lookup[$i]['MarkFilteringSet'])) {
- continue 2;
- }
- $replace[] = $rpl;
- }
- $gid = $Lookup[$i]['Subtable'][$c]['LigSet'][$s]['Ligature'][$g]['LigGlyph'];
- $substitute[] = unicode_hex($this->glyphToChar[$gid][0]);
- $Lookup[$i]['Subtable'][$c]['subs'][] = array('Replace' => $replace, 'substitute' => $substitute, 'CompCount' => $Lookup[$i]['Subtable'][$c]['LigSet'][$s]['Ligature'][$g]['CompCount']);
- }
- }
- }
-
- else if ($Lookup[$i]['Type'] == 5) {
-
- if ($SubstFormat == 1) {
- $this->seek($Lookup[$i]['Subtable'][$c]['CoverageTableOffset']);
- $Lookup[$i]['Subtable'][$c]['CoverageGlyphs'] = $CoverageGlyphs = $this->_getCoverage();
- for ($s = 0; $s < $Lookup[$i]['Subtable'][$c]['SubRuleSetCount']; $s++) {
- $SubRuleSet = $Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s];
- $Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['FirstGlyph'] = $CoverageGlyphs[$s];
- for ($r = 0; $r < $Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['SubRuleCount']; $r++) {
- $GlyphCount = $Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['SubRule'][$r]['GlyphCount'];
- for ($g = 1; $g < $GlyphCount; $g++) {
- $glyphID = $Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['SubRule'][$r]['Input'][$g];
- $Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['SubRule'][$r]['InputGlyphs'][$g] = unicode_hex($this->glyphToChar[$glyphID][0]);
- }
- }
- }
- }
-
- else if ($SubstFormat == 2) {
- $this->seek($Lookup[$i]['Subtable'][$c]['CoverageTableOffset']);
- $Lookup[$i]['Subtable'][$c]['CoverageGlyphs'] = $CoverageGlyphs = $this->_getCoverage();
- $InputClasses = $this->_getClasses($Lookup[$i]['Subtable'][$c]['ClassDefOffset']);
- $Lookup[$i]['Subtable'][$c]['InputClasses'] = $InputClasses;
- for ($s = 0; $s < $Lookup[$i]['Subtable'][$c]['SubClassSetCnt']; $s++) {
- if ($Lookup[$i]['Subtable'][$c]['SubClassSetOffset'][$s] > 0) {
- $this->seek($Lookup[$i]['Subtable'][$c]['SubClassSetOffset'][$s]);
- $Lookup[$i]['Subtable'][$c]['SubClassSet'][$s]['SubClassRuleCnt'] = $SubClassRuleCnt = $this->read_ushort();
- $SubClassRule = array();
- for ($b = 0; $b < $SubClassRuleCnt; $b++) {
- $SubClassRule[$b] = $Lookup[$i]['Subtable'][$c]['SubClassSetOffset'][$s] + $this->read_ushort();
- $Lookup[$i]['Subtable'][$c]['SubClassSet'][$s]['SubClassRule'][$b] = $SubClassRule[$b];
- }
- }
- }
- for ($s = 0; $s < $Lookup[$i]['Subtable'][$c]['SubClassSetCnt']; $s++) {
- $SubClassRuleCnt = $Lookup[$i]['Subtable'][$c]['SubClassSet'][$s]['SubClassRuleCnt'];
- for ($b = 0; $b < $SubClassRuleCnt; $b++) {
- if ($Lookup[$i]['Subtable'][$c]['SubClassSetOffset'][$s] > 0) {
- $this->seek($Lookup[$i]['Subtable'][$c]['SubClassSet'][$s]['SubClassRule'][$b]);
- $Rule = array();
- $Rule['InputGlyphCount'] = $this->read_ushort();
- $Rule['SubstCount'] = $this->read_ushort();
- for ($r = 1; $r < $Rule['InputGlyphCount']; $r++) {
- $Rule['Input'][$r] = $this->read_ushort();
- }
- for ($r = 0; $r < $Rule['SubstCount']; $r++) {
- $Rule['SequenceIndex'][$r] = $this->read_ushort();
- $Rule['LookupListIndex'][$r] = $this->read_ushort();
- }
- $Lookup[$i]['Subtable'][$c]['SubClassSet'][$s]['SubClassRule'][$b] = $Rule;
- }
- }
- }
- }
-
- else if ($SubstFormat == 3) {
- for ($b = 0; $b < $Lookup[$i]['Subtable'][$c]['InputGlyphCount']; $b++) {
- $this->seek($Lookup[$i]['Subtable'][$c]['CoverageInput'][$b]);
- $glyphs = $this->_getCoverage();
- $Lookup[$i]['Subtable'][$c]['CoverageInputGlyphs'][] = implode("|", $glyphs);
- }
- throw new MpdfException("Lookup Type 5, SubstFormat 3 not tested. Please report this with the name of font used - " . $this->fontkey);
- }
- }
-
- else if ($Lookup[$i]['Type'] == 6) {
-
- if ($SubstFormat == 1) {
- $this->seek($Lookup[$i]['Subtable'][$c]['CoverageTableOffset']);
- $Lookup[$i]['Subtable'][$c]['CoverageGlyphs'] = $CoverageGlyphs = $this->_getCoverage();
- $ChainSubRuleSetCnt = $Lookup[$i]['Subtable'][$c]['ChainSubRuleSetCount'];
- for ($s = 0; $s < $ChainSubRuleSetCnt; $s++) {
- $this->seek($Lookup[$i]['Subtable'][$c]['ChainSubRuleSetOffset'][$s]);
- $ChainSubRuleCnt = $Lookup[$i]['Subtable'][$c]['ChainSubRuleSet'][$s]['ChainSubRuleCount'] = $this->read_ushort();
- for ($r = 0; $r < $ChainSubRuleCnt; $r++) {
- $Lookup[$i]['Subtable'][$c]['ChainSubRuleSet'][$s]['ChainSubRuleOffset'][$r] = $Lookup[$i]['Subtable'][$c]['ChainSubRuleSetOffset'][$s] + $this->read_ushort();
- }
- }
- for ($s = 0; $s < $ChainSubRuleSetCnt; $s++) {
- $ChainSubRuleCnt = $Lookup[$i]['Subtable'][$c]['ChainSubRuleSet'][$s]['ChainSubRuleCount'];
- for ($r = 0; $r < $ChainSubRuleCnt; $r++) {
-
- $this->seek($Lookup[$i]['Subtable'][$c]['ChainSubRuleSet'][$s]['ChainSubRuleOffset'][$r]);
- $BacktrackGlyphCount = $Lookup[$i]['Subtable'][$c]['ChainSubRuleSet'][$s]['ChainSubRule'][$r]['BacktrackGlyphCount'] = $this->read_ushort();
- for ($g = 0; $g < $BacktrackGlyphCount; $g++) {
- $glyphID = $this->read_ushort();
- $Lookup[$i]['Subtable'][$c]['ChainSubRuleSet'][$s]['ChainSubRule'][$r]['BacktrackGlyphs'][$g] = unicode_hex($this->glyphToChar[$glyphID][0]);
- }
- $InputGlyphCount = $Lookup[$i]['Subtable'][$c]['ChainSubRuleSet'][$s]['ChainSubRule'][$r]['InputGlyphCount'] = $this->read_ushort();
- for ($g = 1; $g < $InputGlyphCount; $g++) {
- $glyphID = $this->read_ushort();
- $Lookup[$i]['Subtable'][$c]['ChainSubRuleSet'][$s]['ChainSubRule'][$r]['InputGlyphs'][$g] = unicode_hex($this->glyphToChar[$glyphID][0]);
- }
- $LookaheadGlyphCount = $Lookup[$i]['Subtable'][$c]['ChainSubRuleSet'][$s]['ChainSubRule'][$r]['LookaheadGlyphCount'] = $this->read_ushort();
- for ($g = 0; $g < $LookaheadGlyphCount; $g++) {
- $glyphID = $this->read_ushort();
- $Lookup[$i]['Subtable'][$c]['ChainSubRuleSet'][$s]['ChainSubRule'][$r]['LookaheadGlyphs'][$g] = unicode_hex($this->glyphToChar[$glyphID][0]);
- }
- $SubstCount = $Lookup[$i]['Subtable'][$c]['ChainSubRuleSet'][$s]['ChainSubRule'][$r]['SubstCount'] = $this->read_ushort();
- for ($lu = 0; $lu < $SubstCount; $lu++) {
- $Lookup[$i]['Subtable'][$c]['ChainSubRuleSet'][$s]['ChainSubRule'][$r]['SequenceIndex'][$lu] = $this->read_ushort();
- $Lookup[$i]['Subtable'][$c]['ChainSubRuleSet'][$s]['ChainSubRule'][$r]['LookupListIndex'][$lu] = $this->read_ushort();
- }
- }
- }
- }
-
- else if ($SubstFormat == 2) {
- $this->seek($Lookup[$i]['Subtable'][$c]['CoverageTableOffset']);
- $Lookup[$i]['Subtable'][$c]['CoverageGlyphs'] = $CoverageGlyphs = $this->_getCoverage();
- $BacktrackClasses = $this->_getClasses($Lookup[$i]['Subtable'][$c]['BacktrackClassDefOffset']);
- $Lookup[$i]['Subtable'][$c]['BacktrackClasses'] = $BacktrackClasses;
- $InputClasses = $this->_getClasses($Lookup[$i]['Subtable'][$c]['InputClassDefOffset']);
- $Lookup[$i]['Subtable'][$c]['InputClasses'] = $InputClasses;
- $LookaheadClasses = $this->_getClasses($Lookup[$i]['Subtable'][$c]['LookaheadClassDefOffset']);
- $Lookup[$i]['Subtable'][$c]['LookaheadClasses'] = $LookaheadClasses;
- for ($s = 0; $s < $Lookup[$i]['Subtable'][$c]['ChainSubClassSetCnt']; $s++) {
- if ($Lookup[$i]['Subtable'][$c]['ChainSubClassSetOffset'][$s] > 0) {
- $this->seek($Lookup[$i]['Subtable'][$c]['ChainSubClassSetOffset'][$s]);
- $Lookup[$i]['Subtable'][$c]['ChainSubClassSet'][$s]['ChainSubClassRuleCnt'] = $ChainSubClassRuleCnt = $this->read_ushort();
- $ChainSubClassRule = array();
- for ($b = 0; $b < $ChainSubClassRuleCnt; $b++) {
- $ChainSubClassRule[$b] = $Lookup[$i]['Subtable'][$c]['ChainSubClassSetOffset'][$s] + $this->read_ushort();
- $Lookup[$i]['Subtable'][$c]['ChainSubClassSet'][$s]['ChainSubClassRule'][$b] = $ChainSubClassRule[$b];
- }
- }
- }
- for ($s = 0; $s < $Lookup[$i]['Subtable'][$c]['ChainSubClassSetCnt']; $s++) {
- $ChainSubClassRuleCnt = $Lookup[$i]['Subtable'][$c]['ChainSubClassSet'][$s]['ChainSubClassRuleCnt'];
- for ($b = 0; $b < $ChainSubClassRuleCnt; $b++) {
- if ($Lookup[$i]['Subtable'][$c]['ChainSubClassSetOffset'][$s] > 0) {
- $this->seek($Lookup[$i]['Subtable'][$c]['ChainSubClassSet'][$s]['ChainSubClassRule'][$b]);
- $Rule = array();
- $Rule['BacktrackGlyphCount'] = $this->read_ushort();
- for ($r = 0; $r < $Rule['BacktrackGlyphCount']; $r++) {
- $Rule['Backtrack'][$r] = $this->read_ushort();
- }
- $Rule['InputGlyphCount'] = $this->read_ushort();
- for ($r = 1; $r < $Rule['InputGlyphCount']; $r++) {
- $Rule['Input'][$r] = $this->read_ushort();
- }
- $Rule['LookaheadGlyphCount'] = $this->read_ushort();
- for ($r = 0; $r < $Rule['LookaheadGlyphCount']; $r++) {
- $Rule['Lookahead'][$r] = $this->read_ushort();
- }
- $Rule['SubstCount'] = $this->read_ushort();
- for ($r = 0; $r < $Rule['SubstCount']; $r++) {
- $Rule['SequenceIndex'][$r] = $this->read_ushort();
- $Rule['LookupListIndex'][$r] = $this->read_ushort();
- }
- $Lookup[$i]['Subtable'][$c]['ChainSubClassSet'][$s]['ChainSubClassRule'][$b] = $Rule;
- }
- }
- }
- }
-
- else if ($SubstFormat == 3) {
- for ($b = 0; $b < $Lookup[$i]['Subtable'][$c]['BacktrackGlyphCount']; $b++) {
- $this->seek($Lookup[$i]['Subtable'][$c]['CoverageBacktrack'][$b]);
- $glyphs = $this->_getCoverage();
- $Lookup[$i]['Subtable'][$c]['CoverageBacktrackGlyphs'][] = implode("|", $glyphs);
- }
- for ($b = 0; $b < $Lookup[$i]['Subtable'][$c]['InputGlyphCount']; $b++) {
- $this->seek($Lookup[$i]['Subtable'][$c]['CoverageInput'][$b]);
- $glyphs = $this->_getCoverage();
- $Lookup[$i]['Subtable'][$c]['CoverageInputGlyphs'][] = implode("|", $glyphs);
-
- }
- for ($b = 0; $b < $Lookup[$i]['Subtable'][$c]['LookaheadGlyphCount']; $b++) {
- $this->seek($Lookup[$i]['Subtable'][$c]['CoverageLookahead'][$b]);
- $glyphs = $this->_getCoverage();
- $Lookup[$i]['Subtable'][$c]['CoverageLookaheadGlyphs'][] = implode("|", $glyphs);
- }
- }
- }
- }
- }
-
-
-
- $st = $this->mpdf->OTLscript;
- $t = $this->mpdf->OTLlang;
- $langsys = $gsub[$st][$t];
- $lul = array();
- $tags = array();
- foreach ($langsys AS $tag => $ft) {
- foreach ($ft AS $ll) {
- $lul[$ll] = $tag;
- }
- }
- ksort($lul);
- $this->_getGSUBarray($Lookup, $lul, $st);
- }
- return array($GSUBScriptLang, $gsub, $GSLookup, $rtlPUAstr, $rtlPUAarr);
- }
-
- function _getGSUBarray(&$Lookup, &$lul, $scripttag, $level = 1, $coverage = '', $exB = '', $exL = '')
- {
-
-
- $html = '';
- if ($level == 1) {
- $html .= '<bookmark level="0" content="GSUB features">';
- }
- foreach ($lul AS $i => $tag) {
- $html .= '<div class="level' . $level . '">';
- $html .= '<h5 class="level' . $level . '">';
- if ($level == 1) {
- $html .= '<bookmark level="1" content="' . $tag . ' [#' . $i . ']">';
- }
- $html .= 'Lookup #' . $i . ' [tag: <span style="color:#000066;">' . $tag . '</span>]</h5>';
- $ignore = $this->_getGSUBignoreString($Lookup[$i]['Flag'], $Lookup[$i]['MarkFilteringSet']);
- if ($ignore) {
- $html .= '<div class="ignore">Ignoring: ' . $ignore . '</div> ';
- }
- $Type = $Lookup[$i]['Type'];
- $Flag = $Lookup[$i]['Flag'];
- if (($Flag & 0x0001) == 1) {
- $dir = 'RTL';
- } else {
- $dir = 'LTR';
- }
- for ($c = 0; $c < $Lookup[$i]['SubtableCount']; $c++) {
- $html .= '<div class="subtable">Subtable #' . $c;
- if ($level == 1) {
- $html .= '<bookmark level="2" content="Subtable #' . $c . '">';
- }
- $html .= '</div>';
- $SubstFormat = $Lookup[$i]['Subtable'][$c]['Format'];
-
- if ($Lookup[$i]['Type'] == 1) {
- $html .= '<div class="lookuptype">LookupType 1: Single Substitution Subtable</div>';
- for ($s = 0; $s < count($Lookup[$i]['Subtable'][$c]['subs']); $s++) {
- $inputGlyphs = $Lookup[$i]['Subtable'][$c]['subs'][$s]['Replace'];
- $substitute = $Lookup[$i]['Subtable'][$c]['subs'][$s]['substitute'][0];
- if ($level == 2 && strpos($coverage, $inputGlyphs[0]) === false) {
- continue;
- }
- $html .= '<div class="substitution">';
- $html .= '<span class="unicode">' . $this->formatUni($inputGlyphs[0]) . ' </span> ';
- if ($level == 2 && $exB) {
- $html .= $exB;
- }
- $html .= '<span class="unchanged"> ' . $this->formatEntity($inputGlyphs[0]) . '</span>';
- if ($level == 2 && $exL) {
- $html .= $exL;
- }
- $html .= ' » » ';
- if ($level == 2 && $exB) {
- $html .= $exB;
- }
- $html .= '<span class="changed"> ' . $this->formatEntity($substitute) . '</span>';
- if ($level == 2 && $exL) {
- $html .= $exL;
- }
- $html .= ' <span class="unicode">' . $this->formatUni($substitute) . '</span> ';
- $html .= '</div>';
- }
- }
-
- else if ($Lookup[$i]['Type'] == 2) {
- $html .= '<div class="lookuptype">LookupType 2: Multiple Substitution Subtable</div>';
- for ($s = 0; $s < count($Lookup[$i]['Subtable'][$c]['subs']); $s++) {
- $inputGlyphs = $Lookup[$i]['Subtable'][$c]['subs'][$s]['Replace'];
- $substitute = $Lookup[$i]['Subtable'][$c]['subs'][$s]['substitute'];
- if ($level == 2 && strpos($coverage, $inputGlyphs[0]) === false) {
- continue;
- }
- $html .= '<div class="substitution">';
- $html .= '<span class="unicode">' . $this->formatUni($inputGlyphs[0]) . ' </span> ';
- if ($level == 2 && $exB) {
- $html .= $exB;
- }
- $html .= '<span class="unchanged"> ' . $this->formatEntity($inputGlyphs[0]) . '</span>';
- if ($level == 2 && $exL) {
- $html .= $exL;
- }
- $html .= ' » » ';
- if ($level == 2 && $exB) {
- $html .= $exB;
- }
- $html .= '<span class="changed"> ' . $this->formatEntityArr($substitute) . '</span>';
- if ($level == 2 && $exL) {
- $html .= $exL;
- }
- $html .= ' <span class="unicode">' . $this->formatUniArr($substitute) . '</span> ';
- $html .= '</div>';
- }
- }
-
- else if ($Lookup[$i]['Type'] == 3) {
- $html .= '<div class="lookuptype">LookupType 3: Alternate Forms</div>';
- for ($s = 0; $s < count($Lookup[$i]['Subtable'][$c]['subs']); $s++) {
- $inputGlyphs = $Lookup[$i]['Subtable'][$c]['subs'][$s]['Replace'];
- $substitute = $Lookup[$i]['Subtable'][$c]['subs'][$s]['substitute'][0];
- if ($level == 2 && strpos($coverage, $inputGlyphs[0]) === false) {
- continue;
- }
- $html .= '<div class="substitution">';
- $html .= '<span class="unicode">' . $this->formatUni($inputGlyphs[0]) . ' </span> ';
- if ($level == 2 && $exB) {
- $html .= $exB;
- }
- $html .= '<span class="unchanged"> ' . $this->formatEntity($inputGlyphs[0]) . '</span>';
- if ($level == 2 && $exL) {
- $html .= $exL;
- }
- $html .= ' » » ';
- if ($level == 2 && $exB) {
- $html .= $exB;
- }
- $html .= '<span class="changed"> ' . $this->formatEntity($substitute) . '</span>';
- if ($level == 2 && $exL) {
- $html .= $exL;
- }
- $html .= ' <span class="unicode">' . $this->formatUni($substitute) . '</span> ';
- if (count($Lookup[$i]['Subtable'][$c]['subs'][$s]['substitute']) > 1) {
- for ($alt = 1; $alt < count($Lookup[$i]['Subtable'][$c]['subs'][$s]['substitute']); $alt++) {
- $substitute = $Lookup[$i]['Subtable'][$c]['subs'][$s]['substitute'][$alt];
- $html .= ' | ALT #' . $alt . ' ';
- $html .= '<span class="changed"> ' . $this->formatEntity($substitute) . '</span>';
- $html .= ' <span class="unicode">' . $this->formatUni($substitute) . '</span> ';
- }
- }
- $html .= '</div>';
- }
- }
-
- else if ($Lookup[$i]['Type'] == 4) {
- $html .= '<div class="lookuptype">LookupType 4: Ligature Substitution Subtable</div>';
- for ($s = 0; $s < count($Lookup[$i]['Subtable'][$c]['subs']); $s++) {
- $inputGlyphs = $Lookup[$i]['Subtable'][$c]['subs'][$s]['Replace'];
- $substitute = $Lookup[$i]['Subtable'][$c]['subs'][$s]['substitute'][0];
- if ($level == 2 && strpos($coverage, $inputGlyphs[0]) === false) {
- continue;
- }
- $html .= '<div class="substitution">';
- $html .= '<span class="unicode">' . $this->formatUniArr($inputGlyphs) . ' </span> ';
- if ($level == 2 && $exB) {
- $html .= $exB;
- }
- $html .= '<span class="unchanged"> ' . $this->formatEntityArr($inputGlyphs) . '</span>';
- if ($level == 2 && $exL) {
- $html .= $exL;
- }
- $html .= ' » » ';
- if ($level == 2 && $exB) {
- $html .= $exB;
- }
- $html .= '<span class="changed"> ' . $this->formatEntity($substitute) . '</span>';
- if ($level == 2 && $exL) {
- $html .= $exL;
- }
- $html .= ' <span class="unicode">' . $this->formatUni($substitute) . '</span> ';
- $html .= '</div>';
- }
- }
-
- else if ($Lookup[$i]['Type'] == 5) {
- $html .= '<div class="lookuptype">LookupType 5: Contextual Substitution Subtable</div>';
-
- if ($SubstFormat == 1) {
- $html .= '<div class="lookuptypesub">Format 1: Context Substitution</div>';
- for ($s = 0; $s < $Lookup[$i]['Subtable'][$c]['SubRuleSetCount']; $s++) {
-
- $subRule = array();
- $html .= '<div class="rule">Subrule Set: ' . $s . '</div>';
- foreach ($Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['SubRule'] AS $rctr => $rule) {
-
- $html .= '<div class="rule">SubRule: ' . $rctr . '</div>';
- $inputGlyphs = array();
- if ($rule['GlyphCount'] > 1) {
- $inputGlyphs = $rule['InputGlyphs'];
- }
- $inputGlyphs[0] = $Lookup[$i]['Subtable'][$c]['SubRuleSet'][$s]['FirstGlyph'];
- ksort($inputGlyphs);
- $nInput = count($inputGlyphs);
- $exampleI = array();
- $html .= '<div class="context">CONTEXT: ';
- for ($ff = 0; $ff < count($inputGlyphs); $ff++) {
- $html .= '<div>Input #' . $ff . ': <span class="unchanged"> ' . $this->formatEntityStr($inputGlyphs[$ff]) . ' </span></div>';
- $exampleI[] = $this->formatEntityFirst($inputGlyphs[$ff]);
- }
- $html .= '</div>';
- for ($b = 0; $b < $rule['SubstCount']; $b++) {
- $lup = $rule['SubstLookupRecord'][$b]['LookupListIndex'];
- $seqIndex = $rule['SubstLookupRecord'][$b]['SequenceIndex'];
-
- $exB = '';
- $exL = '';
- if ($seqIndex > 0) {
- $exB .= '<span class="inputother">';
- for ($ip = 0; $ip < $seqIndex; $ip++) {
- $exB .= $this->formatEntity($inputGlyphs[$ip]) . '‍';
- }
- $exB .= '</span>';
- }
- if (count($inputGlyphs) > ($seqIndex + 1)) {
- $exL .= '<span class="inputother">';
- for ($ip = $seqIndex + 1; $ip < count($inputGlyphs); $ip++) {
- $exL .= $this->formatEntity($inputGlyphs[$ip]) . '‍';
- }
- $exL .= '</span>';
- }
- $html .= '<div class="sequenceIndex">Substitution Position: ' . $seqIndex . '</div>';
- $lul2 = array($lup => $tag);
-
-
-
-
- $html .= $this->_getGSUBarray($Lookup, $lul2, $scripttag, 2, $inputGlyphs[$seqIndex], $exB, $exL);
- }
- if (count($subRule['rules']))
- $volt[] = $subRule;
- }
- }
- }
-
- else if ($SubstFormat == 2) {
- $html .= '<div class="lookuptypesub">Format 2: Class-based Context Glyph Substitution</div>';
- foreach ($Lookup[$i]['Subtable'][$c]['SubClassSet'] AS $inputClass => $cscs) {
- $html .= '<div class="rule">Input Class: ' . $inputClass . '</div>';
- for ($cscrule = 0; $cscrule < $cscs['SubClassRuleCnt']; $cscrule++) {
- $html .= '<div class="rule">Rule: ' . $cscrule . '</div>';
- $rule = $cscs['SubClassRule'][$cscrule];
- $inputGlyphs = array();
- $inputGlyphs[0] = $Lookup[$i]['Subtable'][$c]['InputClasses'][$inputClass];
- if ($rule['InputGlyphCount'] > 1) {
-
- for ($gcl = 1; $gcl < $rule['InputGlyphCount']; $gcl++) {
- $classindex = $rule['Input'][$gcl];
- $inputGlyphs[$gcl] = $Lookup[$i]['Subtable'][$c]['InputClasses'][$classindex];
- }
- }
-
- $class0excl = implode('|', $Lookup[$i]['Subtable'][$c]['InputClasses']);
- $exampleI = array();
- $html .= '<div class="context">CONTEXT: ';
- for ($ff = 0; $ff < count($inputGlyphs); $ff++) {
- if (!$inputGlyphs[$ff]) {
- $html .= '<div>Input #' . $ff . ': <span class="unchanged"> [NOT ' . $this->formatEntityStr($class0excl) . '] </span></div>';
- $exampleI[] = '[NOT ' . $this->formatEntityFirst($class0excl) . ']';
- } else {
- $html .= '<div>Input #' . $ff . ': <span class="unchanged"> ' . $this->formatEntityStr($inputGlyphs[$ff]) . ' </span></div>';
- $exampleI[] = $this->formatEntityFirst($inputGlyphs[$ff]);
- }
- }
- $html .= '</div>';
- for ($b = 0; $b < $rule['SubstCount']; $b++) {
- $lup = $rule['LookupListIndex'][$b];
- $seqIndex = $rule['SequenceIndex'][$b];
-
- $exB = '';
- $exL = '';
- if ($seqIndex > 0) {
- $exB .= '<span class="inputother">';
- for ($ip = 0; $ip < $seqIndex; $ip++) {
- if (!$inputGlyphs[$ip]) {
- $exB .= '[*]';
- } else {
- $exB .= $this->formatEntityFirst($inputGlyphs[$ip]) . '‍';
- }
- }
- $exB .= '</span>';
- }
- if (count($inputGlyphs) > ($seqIndex + 1)) {
- $exL .= '<span class="inputother">';
- for ($ip = $seqIndex + 1; $ip < count($inputGlyphs); $ip++) {
- if (!$inputGlyphs[$ip]) {
- $exL .= '[*]';
- } else {
- $exL .= $this->formatEntityFirst($inputGlyphs[$ip]) . '‍';
- }
- }
- $exL .= '</span>';
- }
- $html .= '<div class="sequenceIndex">Substitution Position: ' . $seqIndex . '</div>';
- $lul2 = array($lup => $tag);
-
-
-
-
- $html .= $this->_getGSUBarray($Lookup, $lul2, $scripttag, 2, $inputGlyphs[$seqIndex], $exB, $exL);
- }
- if (count($subRule['rules']))
- $volt[] = $subRule;
- }
- }
- }
-
- else if ($SubstFormat == 3) {
- $html .= '<div class="lookuptypesub">Format 3: Coverage-based Context Glyph Substitution </div>';
-
- $inputGlyphs = $Lookup[$i]['Subtable'][$c]['CoverageInputGlyphs'];
- $CoverageInputGlyphs = implode('|', $inputGlyphs);
- $nInput = $Lookup[$i]['Subtable'][$c]['InputGlyphCount'];
- $exampleI = array();
- $html .= '<div class="context">CONTEXT: ';
- for ($ff = 0; $ff < count($inputGlyphs); $ff++) {
- $html .= '<div>Input #' . $ff . ': <span class="unchanged"> ' . $this->formatEntityStr($inputGlyphs[$ff]) . ' </span></div>';
- $exampleI[] = $this->formatEntityFirst($inputGlyphs[$ff]);
- }
- $html .= '</div>';
- for ($b = 0; $b < $Lookup[$i]['Subtable'][$c]['SubstCount']; $b++) {
- $lup = $Lookup[$i]['Subtable'][$c]['SubstLookupRecord'][$b]['LookupListIndex'];
- $seqIndex = $Lookup[$i]['Subtable'][$c]['SubstLookupRecord'][$b]['SequenceIndex'];
-
- $exB = '';
- $exL = '';
- if ($seqIndex > 0) {
- $exB .= '<span class="inputother">';
- for ($ip = 0; $ip < $seqIndex; $ip++) {
- $exB .= $exampleI[$ip] . '‍';
- }
- $exB .= '</span>';
- }
- if (count($inputGlyphs) > ($seqIndex + 1)) {
- $exL .= '<span class="inputother">';
- for ($ip = $seqIndex + 1; $ip < count($inputGlyphs); $ip++) {
- $exL .= $exampleI[$ip] . '‍';
- }
- $exL .= '</span>';
- }
- $html .= '<div class="sequenceIndex">Substitution Position: ' . $seqIndex . '</div>';
- $lul2 = array($lup => $tag);
-
-
-
-
- $html .= $this->_getGSUBarray($Lookup, $lul2, $scripttag, 2, $inputGlyphs[$seqIndex], $exB, $exL);
- }
- if (count($subRule['rules']))
- $volt[] = $subRule;
- }
- }
-
- else if ($Lookup[$i]['Type'] == 6) {
- $html .= '<div class="lookuptype">LookupType 6: Chaining Contextual Substitution Subtable</div>';
-
- if ($SubstFormat == 1) {
- $html .= '<div class="lookuptypesub">Format 1: Simple Chaining Context Glyph Substitution </div>';
- for ($s = 0; $s < $Lookup[$i]['Subtable'][$c]['ChainSubRuleSetCount']; $s++) {
-
- $subRule = array();
- $html .= '<div class="rule">Subrule Set: ' . $s . '</div>';
- $firstInputGlyph = $Lookup[$i]['Subtable'][$c]['CoverageGlyphs'][$s];
- foreach ($Lookup[$i]['Subtable'][$c]['ChainSubRuleSet'][$s]['ChainSubRule'] AS $rctr => $rule) {
- $html .= '<div class="rule">SubRule: ' . $rctr . '</div>';
-
- $inputGlyphs = array();
- if ($rule['InputGlyphCount'] > 1) {
- $inputGlyphs = $rule['InputGlyphs'];
- }
- $inputGlyphs[0] = $firstInputGlyph;
- ksort($inputGlyphs);
- $nInput = count($inputGlyphs);
- if ($rule['BacktrackGlyphCount']) {
- $backtrackGlyphs = $rule['BacktrackGlyphs'];
- } else {
- $backtrackGlyphs = array();
- }
- if ($rule['LookaheadGlyphCount']) {
- $lookaheadGlyphs = $rule['LookaheadGlyphs'];
- } else {
- $lookaheadGlyphs = array();
- }
- $exampleB = array();
- $exampleI = array();
- $exampleL = array();
- $html .= '<div class="context">CONTEXT: ';
- for ($ff = count($backtrackGlyphs) - 1; $ff >= 0; $ff--) {
- $html .= '<div>Backtrack #' . $ff . ': <span class="unicode">' . $this->formatUniStr($backtrackGlyphs[$ff]) . '</span></div>';
- $exampleB[] = $this->formatEntityFirst($backtrackGlyphs[$ff]);
- }
- for ($ff = 0; $ff < count($inputGlyphs); $ff++) {
- $html .= '<div>Input #' . $ff . ': <span class="unchanged"> ' . $this->formatEntityStr($inputGlyphs[$ff]) . ' </span></div>';
- $exampleI[] = $this->formatEntityFirst($inputGlyphs[$ff]);
- }
- for ($ff = 0; $ff < count($lookaheadGlyphs); $ff++) {
- $html .= '<div>Lookahead #' . $ff . ': <span class="unicode">' . $this->formatUniStr($lookaheadGlyphs[$ff]) . '</span></div>';
- $exampleL[] = $this->formatEntityFirst($lookaheadGlyphs[$ff]);
- }
- $html .= '</div>';
- for ($b = 0; $b < $rule['SubstCount']; $b++) {
- $lup = $rule['LookupListIndex'][$b];
- $seqIndex = $rule['SequenceIndex'][$b];
-
- $exB = '';
- $exL = '';
- if (count($exampleB)) {
- $exB .= '<span class="backtrack">' . implode('‍', $exampleB) . '</span>';
- }
- if ($seqIndex > 0) {
- $exB .= '<span class="inputother">';
- for ($ip = 0; $ip < $seqIndex; $ip++) {
- $exB .= $this->formatEntity($inputGlyphs[$ip]) . '‍';
- }
- $exB .= '</span>';
- }
- if (count($inputGlyphs) > ($seqIndex + 1)) {
- $exL .= '<span class="inputother">';
- for ($ip = $seqIndex + 1; $ip < count($inputGlyphs); $ip++) {
- $exL .= $this->formatEntity($inputGlyphs[$ip]) . '‍';
- }
- $exL .= '</span>';
- }
- if (count($exampleL)) {
- $exL .= '<span class="lookahead">' . implode('‍', $exampleL) . '</span>';
- }
- $html .= '<div class="sequenceIndex">Substitution Position: ' . $seqIndex . '</div>';
- $lul2 = array($lup => $tag);
-
-
-
-
- $html .= $this->_getGSUBarray($Lookup, $lul2, $scripttag, 2, $inputGlyphs[$seqIndex], $exB, $exL);
- }
- if (count($subRule['rules']))
- $volt[] = $subRule;
- }
- }
- }
-
- else if ($SubstFormat == 2) {
- $html .= '<div class="lookuptypesub">Format 2: Class-based Chaining Context Glyph Substitution </div>';
- foreach ($Lookup[$i]['Subtable'][$c]['ChainSubClassSet'] AS $inputClass => $cscs) {
- $html .= '<div class="rule">Input Class: ' . $inputClass . '</div>';
- for ($cscrule = 0; $cscrule < $cscs['ChainSubClassRuleCnt']; $cscrule++) {
- $html .= '<div class="rule">Rule: ' . $cscrule . '</div>';
- $rule = $cscs['ChainSubClassRule'][$cscrule];
-
-
-
-
-
-
- $inputGlyphs = array();
- $inputGlyphs[0] = $Lookup[$i]['Subtable'][$c]['InputClasses'][$inputClass];
- if ($rule['InputGlyphCount'] > 1) {
-
- for ($gcl = 1; $gcl < $rule['InputGlyphCount']; $gcl++) {
- $classindex = $rule['Input'][$gcl];
- $inputGlyphs[$gcl] = $Lookup[$i]['Subtable'][$c]['InputClasses'][$classindex];
- }
- }
-
- $class0excl = implode('|', $Lookup[$i]['Subtable'][$c]['InputClasses']);
- $nInput = $rule['InputGlyphCount'];
- if ($rule['BacktrackGlyphCount']) {
- for ($gcl = 0; $gcl < $rule['BacktrackGlyphCount']; $gcl++) {
- $classindex = $rule['Backtrack'][$gcl];
- $backtrackGlyphs[$gcl] = $Lookup[$i]['Subtable'][$c]['BacktrackClasses'][$classindex];
- }
- } else {
- $backtrackGlyphs = array();
- }
- if ($rule['LookaheadGlyphCount']) {
- for ($gcl = 0; $gcl < $rule['LookaheadGlyphCount']; $gcl++) {
- $classindex = $rule['Lookahead'][$gcl];
- $lookaheadGlyphs[$gcl] = $Lookup[$i]['Subtable'][$c]['LookaheadClasses'][$classindex];
- }
- } else {
- $lookaheadGlyphs = array();
- }
- $exampleB = array();
- $exampleI = array();
- $exampleL = array();
- $html .= '<div class="context">CONTEXT: ';
- for ($ff = count($backtrackGlyphs) - 1; $ff >= 0; $ff--) {
- if (!$backtrackGlyphs[$ff]) {
- $html .= '<div>Backtrack #' . $ff . ': <span class="unchanged"> [NOT ' . $this->formatEntityStr($class0excl) . '] </span></div>';
- $exampleB[] = '[NOT ' . $this->formatEntityFirst($class0excl) . ']';
- } else {
- $html .= '<div>Backtrack #' . $ff . ': <span class="unicode">' . $this->formatUniStr($backtrackGlyphs[$ff]) . '</span></div>';
- $exampleB[] = $this->formatEntityFirst($backtrackGlyphs[$ff]);
- }
- }
- for ($ff = 0; $ff < count($inputGlyphs); $ff++) {
- if (!$inputGlyphs[$ff]) {
- $html .= '<div>Input #' . $ff . ': <span class="unchanged"> [NOT ' . $this->formatEntityStr($class0excl) . '] </span></div>';
- $exampleI[] = '[NOT ' . $this->formatEntityFirst($class0excl) . ']';
- } else {
- $html .= '<div>Input #' . $ff . ': <span class="unchanged"> ' . $this->formatEntityStr($inputGlyphs[$ff]) . ' </span></div>';
- $exampleI[] = $this->formatEntityFirst($inputGlyphs[$ff]);
- }
- }
- for ($ff = 0; $ff < count($lookaheadGlyphs); $ff++) {
- if (!$lookaheadGlyphs[$ff]) {
- $html .= '<div>Lookahead #' . $ff . ': <span class="unchanged"> [NOT ' . $this->formatEntityStr($class0excl) . '] </span></div>';
- $exampleL[] = '[NOT ' . $this->formatEntityFirst($class0excl) . ']';
- } else {
- $html .= '<div>Lookahead #' . $ff . ': <span class="unicode">' . $this->formatUniStr($lookaheadGlyphs[$ff]) . '</span></div>';
- $exampleL[] = $this->formatEntityFirst($lookaheadGlyphs[$ff]);
- }
- }
- $html .= '</div>';
- for ($b = 0; $b < $rule['SubstCount']; $b++) {
- $lup = $rule['LookupListIndex'][$b];
- $seqIndex = $rule['SequenceIndex'][$b];
-
- $exB = '';
- $exL = '';
- if (count($exampleB)) {
- $exB .= '<span class="backtrack">' . implode('‍', $exampleB) . '</span>';
- }
- if ($seqIndex > 0) {
- $exB .= '<span class="inputother">';
- for ($ip = 0; $ip < $seqIndex; $ip++) {
- if (!$inputGlyphs[$ip]) {
- $exB .= '[*]';
- } else {
- $exB .= $this->formatEntityFirst($inputGlyphs[$ip]) . '‍';
- }
- }
- $exB .= '</span>';
- }
- if (count($inputGlyphs) > ($seqIndex + 1)) {
- $exL .= '<span class="inputother">';
- for ($ip = $seqIndex + 1; $ip < count($inputGlyphs); $ip++) {
- if (!$inputGlyphs[$ip]) {
- $exL .= '[*]';
- } else {
- $exL .= $this->formatEntityFirst($inputGlyphs[$ip]) . '‍';
- }
- }
- $exL .= '</span>';
- }
- if (count($exampleL)) {
- $exL .= '<span class="lookahead">' . implode('‍', $exampleL) . '</span>';
- }
- $html .= '<div class="sequenceIndex">Substitution Position: ' . $seqIndex . '</div>';
- $lul2 = array($lup => $tag);
-
-
-
-
- $html .= $this->_getGSUBarray($Lookup, $lul2, $scripttag, 2, $inputGlyphs[$seqIndex], $exB, $exL);
- }
- }
- }
- }
-
- else if ($SubstFormat == 3) {
- $html .= '<div class="lookuptypesub">Format 3: Coverage-based Chaining Context Glyph Substitution </div>';
-
- $inputGlyphs = $Lookup[$i]['Subtable'][$c]['CoverageInputGlyphs'];
- $CoverageInputGlyphs = implode('|', $inputGlyphs);
- $nInput = $Lookup[$i]['Subtable'][$c]['InputGlyphCount'];
- if ($Lookup[$i]['Subtable'][$c]['BacktrackGlyphCount']) {
- $backtrackGlyphs = $Lookup[$i]['Subtable'][$c]['CoverageBacktrackGlyphs'];
- } else {
- $backtrackGlyphs = array();
- }
- if ($Lookup[$i]['Subtable'][$c]['LookaheadGlyphCount']) {
- $lookaheadGlyphs = $Lookup[$i]['Subtable'][$c]['CoverageLookaheadGlyphs'];
- } else {
- $lookaheadGlyphs = array();
- }
- $exampleB = array();
- $exampleI = array();
- $exampleL = array();
- $html .= '<div class="context">CONTEXT: ';
- for ($ff = count($backtrackGlyphs) - 1; $ff >= 0; $ff--) {
- $html .= '<div>Backtrack #' . $ff . ': <span class="unicode">' . $this->formatUniStr($backtrackGlyphs[$ff]) . '</span></div>';
- $exampleB[] = $this->formatEntityFirst($backtrackGlyphs[$ff]);
- }
- for ($ff = 0; $ff < count($inputGlyphs); $ff++) {
- $html .= '<div>Input #' . $ff . ': <span class="unchanged"> ' . $this->formatEntityStr($inputGlyphs[$ff]) . ' </span></div>';
- $exampleI[] = $this->formatEntityFirst($inputGlyphs[$ff]);
- }
- for ($ff = 0; $ff < count($lookaheadGlyphs); $ff++) {
- $html .= '<div>Lookahead #' . $ff . ': <span class="unicode">' . $this->formatUniStr($lookaheadGlyphs[$ff]) . '</span></div>';
- $exampleL[] = $this->formatEntityFirst($lookaheadGlyphs[$ff]);
- }
- $html .= '</div>';
- for ($b = 0; $b < $Lookup[$i]['Subtable'][$c]['SubstCount']; $b++) {
- $lup = $Lookup[$i]['Subtable'][$c]['SubstLookupRecord'][$b]['LookupListIndex'];
- $seqIndex = $Lookup[$i]['Subtable'][$c]['SubstLookupRecord'][$b]['SequenceIndex'];
-
- $exB = '';
- $exL = '';
- if (count($exampleB)) {
- $exB .= '<span class="backtrack">' . implode('‍', $exampleB) . '</span>';
- }
- if ($seqIndex > 0) {
- $exB .= '<span class="inputother">';
- for ($ip = 0; $ip < $seqIndex; $ip++) {
- $exB .= $exampleI[$ip] . '‍';
- }
- $exB .= '</span>';
- }
- if (count($inputGlyphs) > ($seqIndex + 1)) {
- $exL .= '<span class="inputother">';
- for ($ip = $seqIndex + 1; $ip < count($inputGlyphs); $ip++) {
- $exL .= $exampleI[$ip] . '‍';
- }
- $exL .= '</span>';
- }
- if (count($exampleL)) {
- $exL .= '<span class="lookahead">' . implode('‍', $exampleL) . '</span>';
- }
- $html .= '<div class="sequenceIndex">Substitution Position: ' . $seqIndex . '</div>';
- $lul2 = array($lup => $tag);
-
-
-
-
- $html .= $this->_getGSUBarray($Lookup, $lul2, $scripttag, 2, $inputGlyphs[$seqIndex], $exB, $exL);
- }
- }
- }
- }
- $html .= '</div>';
- }
- if ($level == 1) {
- $this->mpdf->WriteHTML($html);
- } else {
- return $html;
- }
- }
-
-
-
- function _checkGSUBignore($flag, $glyph, $MarkFilteringSet)
- {
- $ignore = false;
-
- if ((($flag & 0x0008) == 0x0008) && strpos($this->GlyphClassMarks, $glyph)) {
- $ignore = true;
- }
- if ((($flag & 0x0004) == 0x0004) && strpos($this->GlyphClassLigatures, $glyph)) {
- $ignore = true;
- }
- if ((($flag & 0x0002) == 0x0002) && strpos($this->GlyphClassBases, $glyph)) {
- $ignore = true;
- }
-
- if (($flag & 0xFF00) && strpos($this->MarkAttachmentType[($flag >> 8)], $glyph)) {
- $ignore = true;
- }
-
- if (($flag & 0x0010) && strpos($this->MarkGlyphSets[$MarkFilteringSet], $glyph)) {
- $ignore = true;
- }
- return $ignore;
- }
- function _getGSUBignoreString($flag, $MarkFilteringSet)
- {
-
-
-
- $str = "";
- $ignoreflag = 0;
-
- if ($flag & 0xFF00) {
- $MarkAttachmentType = $flag >> 8;
- $ignoreflag = $flag;
-
- $str = "MarkAttachmentType[" . $MarkAttachmentType . "] ";
- }
-
- if ($flag & 0x0010) {
- throw new MpdfException("This font " . $this->fontkey . " contains MarkGlyphSets");
- $str = "Mark Glyph Set: ";
- $str .= $this->MarkGlyphSets[$MarkFilteringSet];
- }
-
-
- if (($flag & 0x0008) == 0x0008) {
- $ignoreflag = 8;
-
- $str = "Mark Glyphs ";
- }
-
- if (($flag & 0x0004) == 0x0004) {
- $ignoreflag += 4;
- if ($str) {
- $str .= "|";
- }
-
- $str .= "Ligature Glyphs ";
- }
-
- if (($flag & 0x0002) == 0x0002) {
- $ignoreflag += 2;
- if ($str) {
- $str .= "|";
- }
-
- $str .= "Base Glyphs ";
- }
- if ($str) {
- return $str;
- } else
- return "";
- }
-
-
- function _makeGSUBcontextInputMatch($inputGlyphs, $ignore, $lookupGlyphs, $seqIndex)
- {
-
-
-
-
- $mLen = count($lookupGlyphs);
- $nInput = count($inputGlyphs);
- $str = "";
- for ($i = 0; $i < $nInput; $i++) {
- if ($i > 0) {
- $str .= $ignore . " ";
- }
- if ($i >= $seqIndex && $i < ($seqIndex + $mLen)) {
- $str .= "" . $lookupGlyphs[($i - $seqIndex)] . "";
- } else {
- $str .= "" . $inputGlyphs[($i)] . "";
- }
- }
- return $str;
- }
- function _makeGSUBinputMatch($inputGlyphs, $ignore)
- {
-
-
-
-
- $str = "";
- for ($i = 1; $i <= count($inputGlyphs); $i++) {
- if ($i > 1) {
- $str .= $ignore . " ";
- }
- $str .= "" . $inputGlyphs[($i - 1)] . "";
- }
- return $str;
- }
- function _makeGSUBbacktrackMatch($backtrackGlyphs, $ignore)
- {
-
-
-
-
-
- $str = "";
- for ($i = (count($backtrackGlyphs) - 1); $i >= 0; $i--) {
- $str .= "" . $backtrackGlyphs[$i] . " " . $ignore . " ";
- }
- return $str;
- }
- function _makeGSUBlookaheadMatch($lookaheadGlyphs, $ignore)
- {
-
-
-
-
-
- $str = "";
- for ($i = 0; $i < count($lookaheadGlyphs); $i++) {
- $str .= $ignore . " " . $lookaheadGlyphs[$i] . "";
- }
- return $str;
- }
- function _makeGSUBinputReplacement($nInput, $REPL, $ignore, $nBsubs, $mLen, $seqIndex)
- {
-
-
-
-
-
-
-
- if ($ignore == "()") {
- $ign = false;
- } else {
- $ign = true;
- }
- $str = "";
- if ($nInput == 1) {
- $str = $REPL;
- } else if ($nInput > 1) {
- if ($mLen == $nInput) {
- $str = $REPL;
- if ($ign) {
-
- for ($x = 2; $x <= $nInput; $x++) {
- $str .= '\\' . ($nBsubs + (2 * ($x - 1)));
- }
- }
- } else {
- for ($x = 1; $x < ($seqIndex + 1); $x++) {
- if ($x == 1) {
- $str .= '\\' . ($nBsubs + 1);
- } else {
- if ($ign) {
- $str .= '\\' . ($nBsubs + (2 * ($x - 1)));
- }
- $str .= ' \\' . ($nBsubs + 1 + (2 * ($x - 1)));
- }
- }
- if ($seqIndex > 0) {
- $str .= " ";
- }
- $str .= $REPL;
- if ($ign) {
- for ($x = (max(($seqIndex + 1), 2)); $x < ($seqIndex + 1 + $mLen); $x++) {
- $str .= '\\' . ($nBsubs + (2 * ($x - 1)));
- }
- }
- for ($x = ($seqIndex + 1 + $mLen); $x <= $nInput; $x++) {
- if ($ign) {
- $str .= '\\' . ($nBsubs + (2 * ($x - 1)));
- }
- $str .= ' \\' . ($nBsubs + 1 + (2 * ($x - 1)));
- }
- }
- }
- return $str;
- }
-
- function _getCoverage($convert2hex = true)
- {
- $g = array();
- $CoverageFormat = $this->read_ushort();
- if ($CoverageFormat == 1) {
- $CoverageGlyphCount = $this->read_ushort();
- for ($gid = 0; $gid < $CoverageGlyphCount; $gid++) {
- $glyphID = $this->read_ushort();
- if ($convert2hex) {
- $g[] = unicode_hex($this->glyphToChar[$glyphID][0]);
- } else {
- $g[] = $glyphID;
- }
- }
- }
- if ($CoverageFormat == 2) {
- $RangeCount = $this->read_ushort();
- for ($r = 0; $r < $RangeCount; $r++) {
- $start = $this->read_ushort();
- $end = $this->read_ushort();
- $StartCoverageIndex = $this->read_ushort();
- for ($gid = $start; $gid <= $end; $gid++) {
- $glyphID = $gid;
- if ($convert2hex) {
- $g[] = unicode_hex($this->glyphToChar[$glyphID][0]);
- } else {
- $g[] = $glyphID;
- }
- }
- }
- }
- return $g;
- }
-
- function _getClasses($offset)
- {
- $this->seek($offset);
- $ClassFormat = $this->read_ushort();
- $GlyphByClass = array();
- if ($ClassFormat == 1) {
- $StartGlyph = $this->read_ushort();
- $GlyphCount = $this->read_ushort();
- for ($i = 0; $i < $GlyphCount; $i++) {
- $startGlyphID = $StartGlyph + $i;
- $endGlyphID = $StartGlyph + $i;
- $class = $this->read_ushort();
- for ($g = $startGlyphID; $g <= $endGlyphID; $g++) {
- if ($this->glyphToChar[$g][0]) {
- $GlyphByClass[$class][] = unicode_hex($this->glyphToChar[$g][0]);
- }
- }
- }
- } else if ($ClassFormat == 2) {
- $tableCount = $this->read_ushort();
- for ($i = 0; $i < $tableCount; $i++) {
- $startGlyphID = $this->read_ushort();
- $endGlyphID = $this->read_ushort();
- $class = $this->read_ushort();
- for ($g = $startGlyphID; $g <= $endGlyphID; $g++) {
- if ($this->glyphToChar[$g][0]) {
- $GlyphByClass[$class][] = unicode_hex($this->glyphToChar[$g][0]);
- }
- }
- }
- }
- $gbc = array();
- foreach ($GlyphByClass AS $class => $garr) {
- $gbc[$class] = implode('|', $garr);
- }
- return $gbc;
- }
-
-
-
-
-
- function _getGPOStables()
- {
-
-
-
- if (isset($this->tables["GPOS"])) {
- $this->mpdf->WriteHTML('<h1>GPOS Tables</h1>');
- $ffeats = array();
- $gpos_offset = $this->seek_table("GPOS");
- $this->skip(4);
- $ScriptList_offset = $gpos_offset + $this->read_ushort();
- $FeatureList_offset = $gpos_offset + $this->read_ushort();
- $LookupList_offset = $gpos_offset + $this->read_ushort();
-
- $this->seek($ScriptList_offset);
- $ScriptCount = $this->read_ushort();
- for ($i = 0; $i < $ScriptCount; $i++) {
- $ScriptTag = $this->read_tag();
- $ScriptTableOffset = $this->read_ushort();
- $ffeats[$ScriptTag] = $ScriptList_offset + $ScriptTableOffset;
- }
-
- foreach ($ffeats AS $t => $o) {
- $ls = array();
- $this->seek($o);
- $DefLangSys_offset = $this->read_ushort();
- if ($DefLangSys_offset > 0) {
- $ls['DFLT'] = $DefLangSys_offset + $o;
- }
- $LangSysCount = $this->read_ushort();
- for ($i = 0; $i < $LangSysCount; $i++) {
- $LangTag = $this->read_tag();
- $LangTableOffset = $this->read_ushort();
- $ls[$LangTag] = $o + $LangTableOffset;
- }
- $ffeats[$t] = $ls;
- }
-
-
- foreach ($ffeats AS $st => $scripts) {
- foreach ($scripts AS $t => $o) {
- $FeatureIndex = array();
- $langsystable_offset = $o;
- $this->seek($langsystable_offset);
- $LookUpOrder = $this->read_ushort();
- $ReqFeatureIndex = $this->read_ushort();
- if ($ReqFeatureIndex != 0xFFFF) {
- $FeatureIndex[] = $ReqFeatureIndex;
- }
- $FeatureCount = $this->read_ushort();
- for ($i = 0; $i < $FeatureCount; $i++) {
- $FeatureIndex[] = $this->read_ushort();
- }
- $ffeats[$st][$t] = $FeatureIndex;
- }
- }
-
- $this->seek($FeatureList_offset);
- $FeatureCount = $this->read_ushort();
- $Feature = array();
- for ($i = 0; $i < $FeatureCount; $i++) {
- $Feature[$i] = array('tag' => $this->read_tag());
- $Feature[$i]['offset'] = $FeatureList_offset + $this->read_ushort();
- }
- for ($i = 0; $i < $FeatureCount; $i++) {
- $this->seek($Feature[$i]['offset']);
- $this->read_ushort();
- $Feature[$i]['LookupCount'] = $Lookupcount = $this->read_ushort();
- $Feature[$i]['LookupListIndex'] = array();
- for ($c = 0; $c < $Lookupcount; $c++) {
- $Feature[$i]['LookupListIndex'][] = $this->read_ushort();
- }
- }
- foreach ($ffeats AS $st => $scripts) {
- foreach ($scripts AS $t => $o) {
- $FeatureIndex = $ffeats[$st][$t];
- foreach ($FeatureIndex AS $k => $fi) {
- $ffeats[$st][$t][$k] = $Feature[$fi];
- }
- }
- }
-
- $gpos = array();
- $GPOSScriptLang = array();
- foreach ($ffeats AS $st => $scripts) {
- foreach ($scripts AS $t => $langsys) {
- $lg = array();
- foreach ($langsys AS $ft) {
- $lg[$ft['LookupListIndex'][0]] = $ft;
- }
-
- ksort($lg);
- foreach ($lg AS $ft) {
- $gpos[$st][$t][$ft['tag']] = $ft['LookupListIndex'];
- }
- if (!isset($GPOSScriptLang[$st])) {
- $GPOSScriptLang[$st] = '';
- }
- $GPOSScriptLang[$st] .= $t . ' ';
- }
- }
- if ($this->mode == 'summary') {
- $this->mpdf->WriteHTML('<h3>GPOS Scripts & Languages</h3>');
- $html = '';
- if (count($gpos)) {
- foreach ($gpos AS $st => $g) {
- $html .= '<h5>' . $st . '</h5>';
- foreach ($g AS $l => $t) {
- $html .= '<div><a href="font_dump_OTL.php?script=' . $st . '&lang=' . $l . '">' . $l . '</a></b>: ';
- foreach ($t AS $tag => $o) {
- $html .= $tag . ' ';
- }
- $html .= '</div>';
- }
- }
- } else {
- $html .= '<div>No entries in GPOS table.</div>';
- }
- $this->mpdf->WriteHTML($html);
- $this->mpdf->WriteHTML('</div>');
- return 0;
- }
-
-
- $this->seek($LookupList_offset);
- $LookupCount = $this->read_ushort();
- $Lookup = array();
- $Offsets = array();
- $SubtableCount = array();
- for ($i = 0; $i < $LookupCount; $i++) {
- $Offsets[$i] = $LookupList_offset + $this->read_ushort();
- }
- for ($i = 0; $i < $LookupCount; $i++) {
- $this->seek($Offsets[$i]);
- $Lookup[$i]['Type'] = $this->read_ushort();
- $Lookup[$i]['Flag'] = $flag = $this->read_ushort();
- $Lookup[$i]['SubtableCount'] = $SubtableCount[$i] = $this->read_ushort();
- for ($c = 0; $c < $SubtableCount[$i]; $c++) {
- $Lookup[$i]['Subtables'][$c] = $Offsets[$i] + $this->read_ushort();
- }
-
- if (($flag & 0x0010) == 0x0010) {
- $Lookup[$i]['MarkFilteringSet'] = $this->read_ushort();
- }
-
-
- if ($Lookup[$i]['Type'] == 9) {
-
- for ($c = 0; $c < $SubtableCount[$i]; $c++) {
- $this->seek($Lookup[$i]['Subtables'][$c]);
- $ExtensionPosFormat = $this->read_ushort();
- $type = $this->read_ushort();
- $Lookup[$i]['Subtables'][$c] = $Lookup[$i]['Subtables'][$c] + $this->read_ulong();
- }
- $Lookup[$i]['Type'] = $type;
- }
- }
-
- $st = $this->mpdf->OTLscript;
- $t = $this->mpdf->OTLlang;
- $langsys = $gpos[$st][$t];
- $lul = array();
- $tags = array();
- if (count($langsys)) {
- foreach ($langsys AS $tag => $ft) {
- foreach ($ft AS $ll) {
- $lul[$ll] = $tag;
- }
- }
- }
- ksort($lul);
- $this->_getGPOSarray($Lookup, $lul, $st);
- return array($GPOSScriptLang, $gpos, $Lookup);
- }
- }
-
-
-
-
-
- function _getGPOSarray(&$Lookup, $lul, $scripttag, $level = 1, $lcoverage = '', $exB = '', $exL = '')
- {
-
- $html = '';
- if ($level == 1) {
- $html .= '<bookmark level="0" content="GPOS features">';
- }
- foreach ($lul AS $luli => $tag) {
- $html .= '<div class="level' . $level . '">';
- $html .= '<h5 class="level' . $level . '">';
- if ($level == 1) {
- $html .= '<bookmark level="1" content="' . $tag . ' [#' . $luli . ']">';
- }
- $html .= 'Lookup #' . $luli . ' [tag: <span style="color:#000066;">' . $tag . '</span>]</h5>';
- $ignore = $this->_getGSUBignoreString($Lookup[$luli]['Flag'], $Lookup[$luli]['MarkFilteringSet']);
- if ($ignore) {
- $html .= '<div class="ignore">Ignoring: ' . $ignore . '</div> ';
- }
- $Type = $Lookup[$luli]['Type'];
- $Flag = $Lookup[$luli]['Flag'];
- if (($Flag & 0x0001) == 1) {
- $dir = 'RTL';
- } else {
- $dir = 'LTR';
- }
- for ($c = 0; $c < $Lookup[$luli]['SubtableCount']; $c++) {
- $html .= '<div class="subtable">Subtable #' . $c;
- if ($level == 1) {
- $html .= '<bookmark level="2" content="Subtable #' . $c . '">';
- }
- $html .= '</div>';
-
- $subtable_offset = $Lookup[$luli]['Subtables'][$c];
- $this->seek($subtable_offset);
- $PosFormat = $this->read_ushort();
-
-
-
- if ($Lookup[$luli]['Type'] == 1) {
- $html .= '<div class="lookuptype">LookupType 1: Single adjustment [Format ' . $PosFormat . ']</div>';
-
-
-
- if ($PosFormat == 1) {
- $Coverage = $subtable_offset + $this->read_ushort();
- $ValueFormat = $this->read_ushort();
- $Value = $this->_getValueRecord($ValueFormat);
- $this->seek($Coverage);
- $glyphs = $this->_getCoverage();
- for ($g = 0; $g < count($glyphs); $g++) {
- if ($level == 2 && strpos($lcoverage, $glyphs[$g]) === false) {
- continue;
- }
- $html .= '<div class="substitution">';
- $html .= '<span class="unicode">' . $this->formatUni($glyphs[$g]) . ' </span> ';
- if ($level == 2 && $exB) {
- $html .= $exB;
- }
- $html .= '<span class="unchanged"> ' . $this->formatEntity($glyphs[$g]) . '</span>';
- if ($level == 2 && $exL) {
- $html .= $exL;
- }
- $html .= ' » » ';
- if ($level == 2 && $exB) {
- $html .= $exB;
- }
- $html .= '<span class="changed" style="font-feature-settings:\'' . $tag . '\' 1;"> ' . $this->formatEntity($glyphs[$g]) . '</span>';
- if ($level == 2 && $exL) {
- $html .= $exL;
- }
- $html .= ' <span class="unicode">';
- if ($Value['XPlacement']) {
- $html .= ' Xpl: ' . $Value['XPlacement'] . ';';
- }
- if ($Value['YPlacement']) {
- $html .= ' YPl: ' . $Value['YPlacement'] . ';';
- }
- if ($Value['XAdvance']) {
- $html .= ' Xadv: ' . $Value['XAdvance'];
- }
- $html .= '</span>';
- $html .= '</div>';
- }
- }
-
-
-
- else if ($PosFormat == 2) {
- $Coverage = $subtable_offset + $this->read_ushort();
- $ValueFormat = $this->read_ushort();
- $ValueCount = $this->read_ushort();
- $Values = array();
- for ($v = 0; $v < $ValueCount; $v++) {
- $Values[] = $this->_getValueRecord($ValueFormat);
- }
- $this->seek($Coverage);
- $glyphs = $this->_getCoverage();
- for ($g = 0; $g < count($glyphs); $g++) {
- if ($level == 2 && strpos($lcoverage, $glyphs[$g]) === false) {
- continue;
- }
- $Value = $Values[$g];
- $html .= '<div class="substitution">';
- $html .= '<span class="unicode">' . $this->formatUni($glyphs[$g]) . ' </span> ';
- if ($level == 2 && $exB) {
- $html .= $exB;
- }
- $html .= '<span class="unchanged"> ' . $this->formatEntity($glyphs[$g]) . '</span>';
- if ($level == 2 && $exL) {
- $html .= $exL;
- }
- $html .= ' » » ';
- if ($level == 2 && $exB) {
- $html .= $exB;
- }
- $html .= '<span class="changed" style="font-feature-settings:\'' . $tag . '\' 1;"> ' . $this->formatEntity($glyphs[$g]) . '</span>';
- if ($level == 2 && $exL) {
- $html .= $exL;
- }
- $html .= ' <span class="unicode">';
- if ($Value['XPlacement']) {
- $html .= ' Xpl: ' . $Value['XPlacement'] . ';';
- }
- if ($Value['YPlacement']) {
- $html .= ' YPl: ' . $Value['YPlacement'] . ';';
- }
- if ($Value['XAdvance']) {
- $html .= ' Xadv: ' . $Value['XAdvance'];
- }
- $html .= '</span>';
- $html .= '</div>';
- }
- }
- }
-
-
-
- else if ($Lookup[$luli]['Type'] == 2) {
- $html .= '<div class="lookuptype">LookupType 2: Pair adjustment e.g. Kerning [Format ' . $PosFormat . ']</div>';
- $Coverage = $subtable_offset + $this->read_ushort();
- $ValueFormat1 = $this->read_ushort();
- $ValueFormat2 = $this->read_ushort();
-
-
-
- if ($PosFormat == 1) {
- $PairSetCount = $this->read_ushort();
- $PairSetOffset = array();
- for ($p = 0; $p < $PairSetCount; $p++) {
- $PairSetOffset[] = $subtable_offset + $this->read_ushort();
- }
- $this->seek($Coverage);
- $glyphs = $this->_getCoverage();
- for ($p = 0; $p < $PairSetCount; $p++) {
- if ($level == 2 && strpos($lcoverage, $glyphs[$p]) === false) {
- continue;
- }
- $this->seek($PairSetOffset[$p]);
-
- $html .= '<div class="glyphs">';
- $html .= '<span class="unchanged"> ' . $this->formatEntity($glyphs[$p]) . ' </span>';
-
- $PairValueCount = $this->read_ushort();
- for ($pv = 0; $pv < $PairValueCount; $pv++) {
-
- $gid = $this->read_ushort();
- $SecondGlyph = unicode_hex($this->glyphToChar[$gid][0]);
- $Value1 = $this->_getValueRecord($ValueFormat1);
- $Value2 = $this->_getValueRecord($ValueFormat2);
-
-
- if ($dir == 'RTL' && $Value1['XPlacement']) {
- $Value1['XPlacement'] -= $Value1['XAdvance'];
- }
- if ($ValueFormat2) {
-
-
- if ($dir == 'RTL' && $Value2['XPlacement'] && $Value2['XAdvance']) {
- $Value2['XPlacement'] -= $Value2['XAdvance'];
- }
- }
- $html .= ' ' . $this->formatEntity($SecondGlyph) . ' ';
-
- }
- $html .= '</div>';
- }
- }
-
-
-
- else if ($PosFormat == 2) {
- $ClassDef1 = $subtable_offset + $this->read_ushort();
- $ClassDef2 = $subtable_offset + $this->read_ushort();
- $Class1Count = $this->read_ushort();
- $Class2Count = $this->read_ushort();
- $sizeOfPair = ( 2 * $this->count_bits($ValueFormat1) ) + ( 2 * $this->count_bits($ValueFormat2) );
- $sizeOfValueRecords = $Class1Count * $Class2Count * $sizeOfPair;
-
-
- $Class1 = $this->_getClassDefinitionTable($ClassDef1);
- $Class2 = $this->_getClassDefinitionTable($ClassDef2);
- $this->seek($subtable_offset + 16);
- for ($i = 0; $i < $Class1Count; $i++) {
- for ($j = 0; $j < $Class2Count; $j++) {
- $Value1 = $this->_getValueRecord($ValueFormat1);
- $Value2 = $this->_getValueRecord($ValueFormat2);
-
-
- if ($dir == 'RTL' && $Value1['XPlacement'] && $Value1['XAdvance']) {
- $Value1['XPlacement'] -= $Value1['XAdvance'];
- }
- if ($ValueFormat2) {
- if ($dir == 'RTL' && $Value2['XPlacement'] && $Value2['XAdvance']) {
- $Value2['XPlacement'] -= $Value2['XAdvance'];
- }
- }
- for ($c1 = 0; $c1 < count($Class1[$i]); $c1++) {
- $FirstGlyph = $Class1[$i][$c1];
- if ($level == 2 && strpos($lcoverage, $FirstGlyph) === false) {
- continue;
- }
- for ($c2 = 0; $c2 < count($Class2[$j]); $c2++) {
- $SecondGlyph = $Class2[$j][$c2];
- if (!$Value1['XPlacement'] && !$Value1['YPlacement'] && !$Value1['XAdvance'] && !$Value2['XPlacement'] && !$Value2['YPlacement'] && !$Value2['XAdvance']) {
- continue;
- }
- $html .= '<div class="substitution">';
- $html .= '<span class="unicode">' . $this->formatUni($FirstGlyph) . ' </span> ';
- if ($level == 2 && $exB) {
- $html .= $exB;
- }
- $html .= '<span class="unchanged"> ' . $this->formatEntity($FirstGlyph) . $this->formatEntity($SecondGlyph) . '</span>';
- if ($level == 2 && $exL) {
- $html .= $exL;
- }
- $html .= ' » » ';
- if ($level == 2 && $exB) {
- $html .= $exB;
- }
- $html .= '<span class="changed" style="font-feature-settings:\'' . $tag . '\' 1;"> ' . $this->formatEntity($FirstGlyph) . $this->formatEntity($SecondGlyph) . '</span>';
- if ($level == 2 && $exL) {
- $html .= $exL;
- }
- $html .= ' <span class="unicode">';
- if ($Value1['XPlacement']) {
- $html .= ' Xpl[1]: ' . $Value1['XPlacement'] . ';';
- }
- if ($Value1['YPlacement']) {
- $html .= ' YPl[1]: ' . $Value1['YPlacement'] . ';';
- }
- if ($Value1['XAdvance']) {
- $html .= ' Xadv[1]: ' . $Value1['XAdvance'];
- }
- if ($Value2['XPlacement']) {
- $html .= ' Xpl[2]: ' . $Value2['XPlacement'] . ';';
- }
- if ($Value2['YPlacement']) {
- $html .= ' YPl[2]: ' . $Value2['YPlacement'] . ';';
- }
- if ($Value2['XAdvance']) {
- $html .= ' Xadv[2]: ' . $Value2['XAdvance'];
- }
- $html .= '</span>';
- $html .= '</div>';
- }
- }
- }
- }
- }
- }
-
-
-
- else if ($Lookup[$luli]['Type'] == 3) {
- $html .= '<div class="lookuptype">LookupType 3: Cursive attachment </div>';
- $Coverage = $subtable_offset + $this->read_ushort();
- $EntryExitCount = $this->read_ushort();
- $EntryAnchors = array();
- $ExitAnchors = array();
- for ($i = 0; $i < $EntryExitCount; $i++) {
- $EntryAnchors[$i] = $this->read_ushort();
- $ExitAnchors[$i] = $this->read_ushort();
- }
- $this->seek($Coverage);
- $Glyphs = $this->_getCoverage();
- for ($i = 0; $i < $EntryExitCount; $i++) {
-
- $pdfWidth = $this->mpdf->_getCharWidth($this->mpdf->fonts[$this->fontkey]['cw'], hexdec($Glyphs[$i]));
- $EntryAnchor = $EntryAnchors[$i];
- $ExitAnchor = $ExitAnchors[$i];
- $html .= '<div class="glyphs">';
- $html .= '<span class="unchanged">' . $this->formatEntity($Glyphs[$i]) . ' </span> ';
- $html .= '<span class="unicode"> ' . $this->formatUni($Glyphs[$i]) . ' => ';
- if ($EntryAnchor != 0) {
- $EntryAnchor += $subtable_offset;
- list($x, $y) = $this->_getAnchorTable($EntryAnchor);
- if ($dir == 'RTL') {
- if (round($pdfWidth) == round($x * 1000 / $this->mpdf->fonts[$this->fontkey]['desc']['unitsPerEm'])) {
- $x = 0;
- } else {
- $x = $x - ($pdfWidth * $this->mpdf->fonts[$this->fontkey]['desc']['unitsPerEm'] / 1000);
- }
- }
- $html .= " Entry X: " . $x . " Y: " . $y . "; ";
- }
- if ($ExitAnchor != 0) {
- $ExitAnchor += $subtable_offset;
- list($x, $y) = $this->_getAnchorTable($ExitAnchor);
- if ($dir == 'LTR') {
- if (round($pdfWidth) == round($x * 1000 / $this->mpdf->fonts[$this->fontkey]['desc']['unitsPerEm'])) {
- $x = 0;
- } else {
- $x = $x - ($pdfWidth * $this->mpdf->fonts[$this->fontkey]['desc']['unitsPerEm'] / 1000);
- }
- }
- $html .= " Exit X: " . $x . " Y: " . $y . "; ";
- }
- $html .= '</span></div>';
- }
- }
-
-
-
- else if ($Lookup[$luli]['Type'] == 4) {
- $html .= '<div class="lookuptype">LookupType 4: MarkToBase attachment </div>';
- $MarkCoverage = $subtable_offset + $this->read_ushort();
- $BaseCoverage = $subtable_offset + $this->read_ushort();
- $this->seek($MarkCoverage);
- $MarkGlyphs = $this->_getCoverage();
- $this->seek($BaseCoverage);
- $BaseGlyphs = $this->_getCoverage();
- $firstMark = '';
- $html .= '<div class="glyphs">Marks: ';
- for ($i = 0; $i < count($MarkGlyphs); $i++) {
- if ($level == 2 && strpos($lcoverage, $MarkGlyphs[$i]) === false) {
- continue;
- } else {
- if (!$firstMark) {
- $firstMark = $MarkGlyphs[$i];
- }
- }
- $html .= ' ' . $this->formatEntity($MarkGlyphs[$i]) . ' ';
- }
- $html .= '</div>';
- if (!$firstMark) {
- return;
- }
- $html .= '<div class="glyphs">Bases: ';
- for ($j = 0; $j < count($BaseGlyphs); $j++) {
- $html .= ' ' . $this->formatEntity($BaseGlyphs[$j]) . ' ';
- }
- $html .= '</div>';
-
- $html .= '<div class="glyphs" style="font-feature-settings:\'' . $tag . '\' 1;">Example(s): ';
- for ($j = 0; $j < min(count($BaseGlyphs), 20); $j++) {
- $html .= ' ' . $this->formatEntity($BaseGlyphs[$j]) . $this->formatEntity($firstMark, true) . ' ';
- }
- $html .= '</div>';
- }
-
-
-
- else if ($Lookup[$luli]['Type'] == 5) {
- $html .= '<div class="lookuptype">LookupType 5: MarkToLigature attachment </div>';
- $MarkCoverage = $subtable_offset + $this->read_ushort();
-
- $LigatureCoverage = $subtable_offset + $this->read_ushort();
- $ClassCount = $this->read_ushort();
- $MarkArray = $subtable_offset + $this->read_ushort();
- $LigatureArray = $subtable_offset + $this->read_ushort();
- $this->seek($MarkCoverage);
- $MarkGlyphs = $this->_getCoverage();
- $this->seek($LigatureCoverage);
- $LigatureGlyphs = $this->_getCoverage();
- $firstMark = '';
- $html .= '<div class="glyphs">Marks: <span class="unchanged">';
- $MarkRecord = array();
- for ($i = 0; $i < count($MarkGlyphs); $i++) {
- if ($level == 2 && strpos($lcoverage, $MarkGlyphs[$i]) === false) {
- continue;
- } else {
- if (!$firstMark) {
- $firstMark = $MarkGlyphs[$i];
- }
- }
-
- $MarkRecord[$i] = $this->_getMarkRecord($MarkArray, $i);
-
- $html .= ' ' . $this->formatEntity($MarkGlyphs[$i]) . ' ';
- }
- $html .= '</span></div>';
- if (!$firstMark) {
- return;
- }
- $this->seek($LigatureArray);
- $LigatureCount = $this->read_ushort();
- $LigatureAttach = array();
- $html .= '<div class="glyphs">Ligatures: <span class="unchanged">';
- for ($j = 0; $j < count($LigatureGlyphs); $j++) {
-
- $LigatureAttach[$j] = $LigatureArray + $this->read_ushort();
- $html .= ' ' . $this->formatEntity($LigatureGlyphs[$j]) . ' ';
- }
- $html .= '</span></div>';
-
- }
-
-
-
- else if ($Lookup[$luli]['Type'] == 6) {
- $html .= '<div class="lookuptype">LookupType 6: MarkToMark attachment </div>';
- $Mark1Coverage = $subtable_offset + $this->read_ushort();
-
- $Mark2Coverage = $subtable_offset + $this->read_ushort();
- $ClassCount = $this->read_ushort();
- $this->seek($Mark1Coverage);
- $Mark1Glyphs = $this->_getCoverage();
- $this->seek($Mark2Coverage);
- $Mark2Glyphs = $this->_getCoverage();
- $firstMark = '';
- $html .= '<div class="glyphs">Marks: <span class="unchanged">';
- for ($i = 0; $i < count($Mark1Glyphs); $i++) {
- if ($level == 2 && strpos($lcoverage, $Mark1Glyphs[$i]) === false) {
- continue;
- } else {
- if (!$firstMark) {
- $firstMark = $Mark1Glyphs[$i];
- }
- }
- $html .= ' ' . $this->formatEntity($Mark1Glyphs[$i]) . ' ';
- }
- $html .= '</span></div>';
- if ($firstMark) {
- $html .= '<div class="glyphs">Bases: <span class="unchanged">';
- for ($j = 0; $j < count($Mark2Glyphs); $j++) {
- $html .= ' ' . $this->formatEntity($Mark2Glyphs[$j]) . ' ';
- }
- $html .= '</span></div>';
-
- $html .= '<div class="glyphs" style="font-feature-settings:\'' . $tag . '\' 1;">Example(s): <span class="changed">';
- for ($j = 0; $j < min(count($Mark2Glyphs), 20); $j++) {
- $html .= ' ' . $this->formatEntity($Mark2Glyphs[$j]) . $this->formatEntity($firstMark, true) . ' ';
- }
- $html .= '</span></div>';
- }
- }
-
-
-
- else if ($Lookup[$luli]['Type'] == 7) {
- $html .= '<div class="lookuptype">LookupType 7: Context positioning [Format ' . $PosFormat . ']</div>';
-
-
-
- if ($PosFormat == 1) {
- throw new MpdfException("GPOS Lookup Type " . $Type . " Format " . $PosFormat . " not YET TESTED.");
- }
-
-
-
- else if ($PosFormat == 2) {
- throw new MpdfException("GPOS Lookup Type " . $Type . " Format " . $PosFormat . " not YET TESTED.");
- }
-
-
-
- else if ($PosFormat == 3) {
- throw new MpdfException("GPOS Lookup Type " . $Type . " Format " . $PosFormat . " not YET TESTED.");
- } else {
- throw new MpdfException("GPOS Lookup Type " . $Type . ", Format " . $PosFormat . " not supported.");
- }
- }
-
-
-
- else if ($Lookup[$luli]['Type'] == 8) {
- $html .= '<div class="lookuptype">LookupType 8: Chained Context positioning [Format ' . $PosFormat . ']</div>';
-
-
-
- if ($PosFormat == 1) {
- throw new MpdfException("GPOS Lookup Type " . $Type . " Format " . $PosFormat . " not TESTED YET.");
- }
-
-
-
- else if ($PosFormat == 2) {
- $html .= '<div>GPOS Lookup Type 8: Format 2 not yet supported in OTL dump</div>';
- continue;
-
- throw new MpdfException("GPOS Lookup Type " . $Type . " Format " . $PosFormat . " not TESTED YET.");
- }
-
-
-
- else if ($PosFormat == 3) {
- $BacktrackGlyphCount = $this->read_ushort();
- $CoverageBacktrackOffset = array();
- for ($b = 0; $b < $BacktrackGlyphCount; $b++) {
- $CoverageBacktrackOffset[] = $subtable_offset + $this->read_ushort();
- }
- $InputGlyphCount = $this->read_ushort();
- $CoverageInputOffset = array();
- for ($b = 0; $b < $InputGlyphCount; $b++) {
- $CoverageInputOffset[] = $subtable_offset + $this->read_ushort();
- }
- $LookaheadGlyphCount = $this->read_ushort();
- $CoverageLookaheadOffset = array();
- for ($b = 0; $b < $LookaheadGlyphCount; $b++) {
- $CoverageLookaheadOffset[] = $subtable_offset + $this->read_ushort();
- }
- $PosCount = $this->read_ushort();
- $PosLookupRecord = array();
- for ($p = 0; $p < $PosCount; $p++) {
-
- $PosLookupRecord[$p]['SequenceIndex'] = $this->read_ushort();
- $PosLookupRecord[$p]['LookupListIndex'] = $this->read_ushort();
- }
- $backtrackGlyphs = array();
- for ($b = 0; $b < $BacktrackGlyphCount; $b++) {
- $this->seek($CoverageBacktrackOffset[$b]);
- $backtrackGlyphs[$b] = implode('|', $this->_getCoverage());
- }
- $inputGlyphs = array();
- for ($b = 0; $b < $InputGlyphCount; $b++) {
- $this->seek($CoverageInputOffset[$b]);
- $inputGlyphs[$b] = implode('|', $this->_getCoverage());
- }
- $lookaheadGlyphs = array();
- for ($b = 0; $b < $LookaheadGlyphCount; $b++) {
- $this->seek($CoverageLookaheadOffset[$b]);
- $lookaheadGlyphs[$b] = implode('|', $this->_getCoverage());
- }
- $exampleB = array();
- $exampleI = array();
- $exampleL = array();
- $html .= '<div class="context">CONTEXT: ';
- for ($ff = count($backtrackGlyphs) - 1; $ff >= 0; $ff--) {
- $html .= '<div>Backtrack #' . $ff . ': <span class="unicode">' . $this->formatUniStr($backtrackGlyphs[$ff]) . '</span></div>';
- $exampleB[] = $this->formatEntityFirst($backtrackGlyphs[$ff]);
- }
- for ($ff = 0; $ff < count($inputGlyphs); $ff++) {
- $html .= '<div>Input #' . $ff . ': <span class="unchanged"> ' . $this->formatEntityStr($inputGlyphs[$ff]) . ' </span></div>';
- $exampleI[] = $this->formatEntityFirst($inputGlyphs[$ff]);
- }
- for ($ff = 0; $ff < count($lookaheadGlyphs); $ff++) {
- $html .= '<div>Lookahead #' . $ff . ': <span class="unicode">' . $this->formatUniStr($lookaheadGlyphs[$ff]) . '</span></div>';
- $exampleL[] = $this->formatEntityFirst($lookaheadGlyphs[$ff]);
- }
- $html .= '</div>';
- for ($p = 0; $p < $PosCount; $p++) {
- $lup = $PosLookupRecord[$p]['LookupListIndex'];
- $seqIndex = $PosLookupRecord[$p]['SequenceIndex'];
-
- $exB = '';
- $exL = '';
- if (count($exampleB)) {
- $exB .= '<span class="backtrack">' . implode('‍', $exampleB) . '</span>';
- }
- if ($seqIndex > 0) {
- $exB .= '<span class="inputother">';
- for ($ip = 0; $ip < $seqIndex; $ip++) {
- $exB .= $exampleI[$ip] . '‍';
- }
- $exB .= '</span>';
- }
- if (count($inputGlyphs) > ($seqIndex + 1)) {
- $exL .= '<span class="inputother">';
- for ($ip = $seqIndex + 1; $ip < count($inputGlyphs); $ip++) {
- $exL .= '‍' . $exampleI[$ip];
- }
- $exL .= '</span>';
- }
- if (count($exampleL)) {
- $exL .= '<span class="lookahead">' . implode('‍', $exampleL) . '</span>';
- }
- $html .= '<div class="sequenceIndex">Substitution Position: ' . $seqIndex . '</div>';
- $lul2 = array($lup => $tag);
-
-
-
-
- $html .= $this->_getGPOSarray($Lookup, $lul2, $scripttag, 2, $inputGlyphs[$seqIndex], $exB, $exL);
- }
- }
- }
- }
- $html .= '</div>';
- }
- if ($level == 1) {
- $this->mpdf->WriteHTML($html);
- } else {
- return $html;
- }
- }
-
-
-
-
- function count_bits($n)
- {
- for ($c = 0; $n; $c++) {
- $n &= $n - 1;
- }
- return $c;
- }
- function _getValueRecord($ValueFormat)
- {
-
- $vra = array();
-
- if (($ValueFormat & 0x0001) == 0x0001) {
- $vra['XPlacement'] = $this->read_short();
- }
-
- if (($ValueFormat & 0x0002) == 0x0002) {
- $vra['YPlacement'] = $this->read_short();
- }
-
- if (($ValueFormat & 0x0004) == 0x0004) {
- $vra['XAdvance'] = $this->read_short();
- }
-
- if (($ValueFormat & 0x0008) == 0x0008) {
- $this->read_short();
- }
-
- if (($ValueFormat & 0x0010) == 0x0010) {
- $this->read_ushort();
- }
-
- if (($ValueFormat & 0x0020) == 0x0020) {
- $this->read_ushort();
- }
-
- if (($ValueFormat & 0x0040) == 0x0040) {
- $this->read_ushort();
- }
-
- if (($ValueFormat & 0x0080) == 0x0080) {
- $this->read_ushort();
- }
- return $vra;
- }
- function _getAnchorTable($offset = 0)
- {
- if ($offset) {
- $this->seek($offset);
- }
- $AnchorFormat = $this->read_ushort();
- $XCoordinate = $this->read_short();
- $YCoordinate = $this->read_short();
-
- return array($XCoordinate, $YCoordinate);
- }
- function _getMarkRecord($offset, $MarkPos)
- {
- $this->seek($offset);
- $MarkCount = $this->read_ushort();
- $this->skip($MarkPos * 4);
- $Class = $this->read_ushort();
- $MarkAnchor = $offset + $this->read_ushort();
- list($x, $y) = $this->_getAnchorTable($MarkAnchor);
- $MarkRecord = array('Class' => $Class, 'AnchorX' => $x, 'AnchorY' => $y);
- return $MarkRecord;
- }
-
-
- function getGlyphData($originalGlyphIdx, &$maxdepth, &$depth, &$points, &$contours)
- {
- $depth++;
- $maxdepth = max($maxdepth, $depth);
- if (count($this->glyphdata[$originalGlyphIdx]['compGlyphs'])) {
- foreach ($this->glyphdata[$originalGlyphIdx]['compGlyphs'] AS $glyphIdx) {
- $this->getGlyphData($glyphIdx, $maxdepth, $depth, $points, $contours);
- }
- } else if (($this->glyphdata[$originalGlyphIdx]['nContours'] > 0) && $depth > 0) {
- $contours += $this->glyphdata[$originalGlyphIdx]['nContours'];
- $points += $this->glyphdata[$originalGlyphIdx]['nPoints'];
- }
- $depth--;
- }
-
-
- function getGlyphs($originalGlyphIdx, &$start, &$glyphSet, &$subsetglyphs)
- {
- $glyphPos = $this->glyphPos[$originalGlyphIdx];
- $glyphLen = $this->glyphPos[$originalGlyphIdx + 1] - $glyphPos;
- if (!$glyphLen) {
- return;
- }
- $this->seek($start + $glyphPos);
- $numberOfContours = $this->read_short();
- if ($numberOfContours < 0) {
- $this->skip(8);
- $flags = GF_MORE;
- while ($flags & GF_MORE) {
- $flags = $this->read_ushort();
- $glyphIdx = $this->read_ushort();
- if (!isset($glyphSet[$glyphIdx])) {
- $glyphSet[$glyphIdx] = count($subsetglyphs);
- $subsetglyphs[$glyphIdx] = true;
- }
- $savepos = ftell($this->fh);
- $this->getGlyphs($glyphIdx, $start, $glyphSet, $subsetglyphs);
- $this->seek($savepos);
- if ($flags & GF_WORDS)
- $this->skip(4);
- else
- $this->skip(2);
- if ($flags & GF_SCALE)
- $this->skip(2);
- else if ($flags & GF_XYSCALE)
- $this->skip(4);
- else if ($flags & GF_TWOBYTWO)
- $this->skip(8);
- }
- }
- }
-
- function getHMTX($numberOfHMetrics, $numGlyphs, &$glyphToChar, $scale)
- {
- $start = $this->seek_table("hmtx");
- $aw = 0;
- $this->charWidths = str_pad('', 256 * 256 * 2, "\x00");
- if ($this->maxUniChar > 65536) {
- $this->charWidths .= str_pad('', 256 * 256 * 2, "\x00");
- }
- if ($this->maxUniChar > 131072) {
- $this->charWidths .= str_pad('', 256 * 256 * 2, "\x00");
- }
- $nCharWidths = 0;
- if (($numberOfHMetrics * 4) < $this->maxStrLenRead) {
- $data = $this->get_chunk($start, ($numberOfHMetrics * 4));
- $arr = unpack("n*", $data);
- } else {
- $this->seek($start);
- }
- for ($glyph = 0; $glyph < $numberOfHMetrics; $glyph++) {
- if (($numberOfHMetrics * 4) < $this->maxStrLenRead) {
- $aw = $arr[($glyph * 2) + 1];
- } else {
- $aw = $this->read_ushort();
- $lsb = $this->read_ushort();
- }
- if (isset($glyphToChar[$glyph]) || $glyph == 0) {
- if ($aw >= (1 << 15)) {
- $aw = 0;
- }
-
- if ($glyph == 0) {
- $this->defaultWidth = $scale * $aw;
- continue;
- }
- foreach ($glyphToChar[$glyph] AS $char) {
-
- if ($char != 0 && $char != 65535) {
- $w = intval(round($scale * $aw));
- if ($w == 0) {
- $w = 65535;
- }
- if ($char < 196608) {
- $this->charWidths[$char * 2] = chr($w >> 8);
- $this->charWidths[$char * 2 + 1] = chr($w & 0xFF);
- $nCharWidths++;
- }
- }
- }
- }
- }
- $data = $this->get_chunk(($start + $numberOfHMetrics * 4), ($numGlyphs * 2));
- $arr = unpack("n*", $data);
- $diff = $numGlyphs - $numberOfHMetrics;
- $w = intval(round($scale * $aw));
- if ($w == 0) {
- $w = 65535;
- }
- for ($pos = 0; $pos < $diff; $pos++) {
- $glyph = $pos + $numberOfHMetrics;
- if (isset($glyphToChar[$glyph])) {
- foreach ($glyphToChar[$glyph] AS $char) {
- if ($char != 0 && $char != 65535) {
- if ($char < 196608) {
- $this->charWidths[$char * 2] = chr($w >> 8);
- $this->charWidths[$char * 2 + 1] = chr($w & 0xFF);
- $nCharWidths++;
- }
- }
- }
- }
- }
-
-
- $this->charWidths[0] = chr($nCharWidths >> 8);
- $this->charWidths[1] = chr($nCharWidths & 0xFF);
- }
- function getHMetric($numberOfHMetrics, $gid)
- {
- $start = $this->seek_table("hmtx");
- if ($gid < $numberOfHMetrics) {
- $this->seek($start + ($gid * 4));
- $hm = fread($this->fh, 4);
- } else {
- $this->seek($start + (($numberOfHMetrics - 1) * 4));
- $hm = fread($this->fh, 2);
- $this->seek($start + ($numberOfHMetrics * 2) + ($gid * 2));
- $hm .= fread($this->fh, 2);
- }
- return $hm;
- }
- function getLOCA($indexToLocFormat, $numGlyphs)
- {
- $start = $this->seek_table('loca');
- $this->glyphPos = array();
- if ($indexToLocFormat == 0) {
- $data = $this->get_chunk($start, ($numGlyphs * 2) + 2);
- $arr = unpack("n*", $data);
- for ($n = 0; $n <= $numGlyphs; $n++) {
- $this->glyphPos[] = ($arr[$n + 1] * 2);
- }
- } else if ($indexToLocFormat == 1) {
- $data = $this->get_chunk($start, ($numGlyphs * 4) + 4);
- $arr = unpack("N*", $data);
- for ($n = 0; $n <= $numGlyphs; $n++) {
- $this->glyphPos[] = ($arr[$n + 1]);
- }
- } else {
- throw new MpdfException('Unknown location table format ' . $indexToLocFormat);
- }
- }
-
- function getCMAP4($unicode_cmap_offset, &$glyphToChar, &$charToGlyph)
- {
- $this->maxUniChar = 0;
- $this->seek($unicode_cmap_offset + 2);
- $length = $this->read_ushort();
- $limit = $unicode_cmap_offset + $length;
- $this->skip(2);
- $segCount = $this->read_ushort() / 2;
- $this->skip(6);
- $endCount = array();
- for ($i = 0; $i < $segCount; $i++) {
- $endCount[] = $this->read_ushort();
- }
- $this->skip(2);
- $startCount = array();
- for ($i = 0; $i < $segCount; $i++) {
- $startCount[] = $this->read_ushort();
- }
- $idDelta = array();
- for ($i = 0; $i < $segCount; $i++) {
- $idDelta[] = $this->read_short();
- }
- $idRangeOffset_start = $this->_pos;
- $idRangeOffset = array();
- for ($i = 0; $i < $segCount; $i++) {
- $idRangeOffset[] = $this->read_ushort();
- }
- for ($n = 0; $n < $segCount; $n++) {
- $endpoint = ($endCount[$n] + 1);
- for ($unichar = $startCount[$n]; $unichar < $endpoint; $unichar++) {
- if ($idRangeOffset[$n] == 0)
- $glyph = ($unichar + $idDelta[$n]) & 0xFFFF;
- else {
- $offset = ($unichar - $startCount[$n]) * 2 + $idRangeOffset[$n];
- $offset = $idRangeOffset_start + 2 * $n + $offset;
- if ($offset >= $limit)
- $glyph = 0;
- else {
- $glyph = $this->get_ushort($offset);
- if ($glyph != 0)
- $glyph = ($glyph + $idDelta[$n]) & 0xFFFF;
- }
- }
- $charToGlyph[$unichar] = $glyph;
- if ($unichar < 196608) {
- $this->maxUniChar = max($unichar, $this->maxUniChar);
- }
- $glyphToChar[$glyph][] = $unichar;
- }
- }
- }
- function formatUni($char)
- {
- $x = preg_replace('/^[0]*/', '', $char);
- $x = str_pad($x, 4, '0', STR_PAD_LEFT);
- $d = hexdec($x);
- if (($d > 57343 && $d < 63744) || ($d > 122879 && $d < 126977)) {
- $id = 'M';
- }
- else {
- $id = 'U';
- }
- return $id . '+' . $x;
- }
- function formatEntity($char, $allowjoining = false)
- {
- $char = preg_replace('/^[0]/', '', $char);
- $x = '&#x' . $char . ';';
- if (strpos($this->GlyphClassMarks, $char) !== false) {
- if (!$allowjoining) {
- $x = '◌' . $x;
- }
- }
- return $x;
- }
- function formatUniArr($arr)
- {
- $s = array();
- foreach ($arr AS $c) {
- $x = preg_replace('/^[0]*/', '', $c);
- $d = hexdec($x);
- if (($d > 57343 && $d < 63744) || ($d > 122879 && $d < 126977)) {
- $id = 'M';
- }
- else {
- $id = 'U';
- }
- $s[] = $id . '+' . str_pad($x, 4, '0', STR_PAD_LEFT);
- }
- return implode(', ', $s);
- }
- function formatEntityArr($arr)
- {
- $s = array();
- foreach ($arr AS $c) {
- $c = preg_replace('/^[0]/', '', $c);
- $x = '&#x' . $c . ';';
- if (strpos($this->GlyphClassMarks, $c) !== false) {
- $x = '◌' . $x;
- }
- $s[] = $x;
- }
- return implode(' ', $s);
- }
- function formatClassArr($arr)
- {
- $s = array();
- foreach ($arr AS $c) {
- $x = preg_replace('/^[0]*/', '', $c);
- $d = hexdec($x);
- if (($d > 57343 && $d < 63744) || ($d > 122879 && $d < 126977)) {
- $id = 'M';
- }
- else {
- $id = 'U';
- }
- $s[] = $id . '+' . str_pad($x, 4, '0', STR_PAD_LEFT);
- }
- return implode(', ', $s);
- }
- function formatUniStr($str)
- {
- $s = array();
- $arr = explode('|', $str);
- foreach ($arr AS $c) {
- $x = preg_replace('/^[0]*/', '', $c);
- $d = hexdec($x);
- if (($d > 57343 && $d < 63744) || ($d > 122879 && $d < 126977)) {
- $id = 'M';
- }
- else {
- $id = 'U';
- }
- $s[] = $id . '+' . str_pad($x, 4, '0', STR_PAD_LEFT);
- }
- return implode(', ', $s);
- }
- function formatEntityStr($str)
- {
- $s = array();
- $arr = explode('|', $str);
- foreach ($arr AS $c) {
- $c = preg_replace('/^[0]/', '', $c);
- $x = '&#x' . $c . ';';
- if (strpos($this->GlyphClassMarks, $c) !== false) {
- $x = '◌' . $x;
- }
- $s[] = $x;
- }
- return implode(' ', $s);
- }
- function formatEntityFirst($str)
- {
- $arr = explode('|', $str);
- $char = preg_replace('/^[0]/', '', $arr[0]);
- $x = '&#x' . $char . ';';
- if (strpos($this->GlyphClassMarks, $char) !== false) {
- $x = '◌' . $x;
- }
- return $x;
- }
- }
|