🔒 Repository is read-only – file editing is disabled.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766
diff -Naur a/include/freetype/config/ftoption.h b/include/freetype/config/ftoption.h
--- a/include/freetype/config/ftoption.h 2021-07-15 12:09:04.000000000 +0200
+++ b/include/freetype/config/ftoption.h 2021-09-27 18:42:00.896661978 +0200
@@ -123,7 +123,7 @@
* When this macro is not defined, FreeType offers alternative LCD
* rendering technology that produces excellent output.
*/
-/* #define FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
+#define FT_CONFIG_OPTION_SUBPIXEL_RENDERING
/**************************************************************************
@@ -688,8 +688,8 @@
* https://www.microsoft.com/typography/cleartype/truetypecleartype.aspx
*/
/* #define TT_CONFIG_OPTION_SUBPIXEL_HINTING 1 */
-#define TT_CONFIG_OPTION_SUBPIXEL_HINTING 2
-/* #define TT_CONFIG_OPTION_SUBPIXEL_HINTING ( 1 | 2 ) */
+/* #define TT_CONFIG_OPTION_SUBPIXEL_HINTING 2 */
+#define TT_CONFIG_OPTION_SUBPIXEL_HINTING ( 1 | 2 )
/**************************************************************************
@@ -877,7 +877,7 @@
* If this option is activated, it can be controlled with the
* `no-long-family-names` property of the 'pcf' driver module.
*/
-/* #define PCF_CONFIG_OPTION_LONG_FAMILY_NAMES */
+#define PCF_CONFIG_OPTION_LONG_FAMILY_NAMES
/*************************************************************************/
diff -Naur a/include/freetype/ftcolor.h.orig b/include/freetype/ftcolor.h.orig
--- a/include/freetype/ftcolor.h.orig 1970-01-01 01:00:00.000000000 +0100
+++ b/include/freetype/ftcolor.h.orig 2021-07-01 07:02:04.000000000 +0200
@@ -0,0 +1,1609 @@
+/****************************************************************************
+ *
+ * ftcolor.h
+ *
+ * FreeType's glyph color management (specification).
+ *
+ * Copyright (C) 2018-2021 by
+ * David Turner, Robert Wilhelm, and Werner Lemberg.
+ *
+ * This file is part of the FreeType project, and may only be used,
+ * modified, and distributed under the terms of the FreeType project
+ * license, LICENSE.TXT. By continuing to use, modify, or distribute
+ * this file you indicate that you have read the license and
+ * understand and accept it fully.
+ *
+ */
+
+
+#ifndef FTCOLOR_H_
+#define FTCOLOR_H_
+
+#include <freetype/freetype.h>
+
+#ifdef FREETYPE_H
+#error "freetype.h of FreeType 1 has been loaded!"
+#error "Please fix the directory search order for header files"
+#error "so that freetype.h of FreeType 2 is found first."
+#endif
+
+
+FT_BEGIN_HEADER
+
+
+ /**************************************************************************
+ *
+ * @section:
+ * color_management
+ *
+ * @title:
+ * Glyph Color Management
+ *
+ * @abstract:
+ * Retrieving and manipulating OpenType's 'CPAL' table data.
+ *
+ * @description:
+ * The functions described here allow access and manipulation of color
+ * palette entries in OpenType's 'CPAL' tables.
+ */
+
+
+ /**************************************************************************
+ *
+ * @struct:
+ * FT_Color
+ *
+ * @description:
+ * This structure models a BGRA color value of a 'CPAL' palette entry.
+ *
+ * The used color space is sRGB; the colors are not pre-multiplied, and
+ * alpha values must be explicitly set.
+ *
+ * @fields:
+ * blue ::
+ * Blue value.
+ *
+ * green ::
+ * Green value.
+ *
+ * red ::
+ * Red value.
+ *
+ * alpha ::
+ * Alpha value, giving the red, green, and blue color's opacity.
+ *
+ * @since:
+ * 2.10
+ */
+ typedef struct FT_Color_
+ {
+ FT_Byte blue;
+ FT_Byte green;
+ FT_Byte red;
+ FT_Byte alpha;
+
+ } FT_Color;
+
+
+ /**************************************************************************
+ *
+ * @enum:
+ * FT_PALETTE_XXX
+ *
+ * @description:
+ * A list of bit field constants used in the `palette_flags` array of the
+ * @FT_Palette_Data structure to indicate for which background a palette
+ * with a given index is usable.
+ *
+ * @values:
+ * FT_PALETTE_FOR_LIGHT_BACKGROUND ::
+ * The palette is appropriate to use when displaying the font on a
+ * light background such as white.
+ *
+ * FT_PALETTE_FOR_DARK_BACKGROUND ::
+ * The palette is appropriate to use when displaying the font on a dark
+ * background such as black.
+ *
+ * @since:
+ * 2.10
+ */
+#define FT_PALETTE_FOR_LIGHT_BACKGROUND 0x01
+#define FT_PALETTE_FOR_DARK_BACKGROUND 0x02
+
+
+ /**************************************************************************
+ *
+ * @struct:
+ * FT_Palette_Data
+ *
+ * @description:
+ * This structure holds the data of the 'CPAL' table.
+ *
+ * @fields:
+ * num_palettes ::
+ * The number of palettes.
+ *
+ * palette_name_ids ::
+ * An optional read-only array of palette name IDs with `num_palettes`
+ * elements, corresponding to entries like 'dark' or 'light' in the
+ * font's 'name' table.
+ *
+ * An empty name ID in the 'CPAL' table gets represented as value
+ * 0xFFFF.
+ *
+ * `NULL` if the font's 'CPAL' table doesn't contain appropriate data.
+ *
+ * palette_flags ::
+ * An optional read-only array of palette flags with `num_palettes`
+ * elements. Possible values are an ORed combination of
+ * @FT_PALETTE_FOR_LIGHT_BACKGROUND and
+ * @FT_PALETTE_FOR_DARK_BACKGROUND.
+ *
+ * `NULL` if the font's 'CPAL' table doesn't contain appropriate data.
+ *
+ * num_palette_entries ::
+ * The number of entries in a single palette. All palettes have the
+ * same size.
+ *
+ * palette_entry_name_ids ::
+ * An optional read-only array of palette entry name IDs with
+ * `num_palette_entries`. In each palette, entries with the same index
+ * have the same function. For example, index~0 might correspond to
+ * string 'outline' in the font's 'name' table to indicate that this
+ * palette entry is used for outlines, index~1 might correspond to
+ * 'fill' to indicate the filling color palette entry, etc.
+ *
+ * An empty entry name ID in the 'CPAL' table gets represented as value
+ * 0xFFFF.
+ *
+ * `NULL` if the font's 'CPAL' table doesn't contain appropriate data.
+ *
+ * @note:
+ * Use function @FT_Get_Sfnt_Name to map name IDs and entry name IDs to
+ * name strings.
+ *
+ * Use function @FT_Palette_Select to get the colors associated with a
+ * palette entry.
+ *
+ * @since:
+ * 2.10
+ */
+ typedef struct FT_Palette_Data_ {
+ FT_UShort num_palettes;
+ const FT_UShort* palette_name_ids;
+ const FT_UShort* palette_flags;
+
+ FT_UShort num_palette_entries;
+ const FT_UShort* palette_entry_name_ids;
+
+ } FT_Palette_Data;
+
+
+ /**************************************************************************
+ *
+ * @function:
+ * FT_Palette_Data_Get
+ *
+ * @description:
+ * Retrieve the face's color palette data.
+ *
+ * @input:
+ * face ::
+ * The source face handle.
+ *
+ * @output:
+ * apalette ::
+ * A pointer to an @FT_Palette_Data structure.
+ *
+ * @return:
+ * FreeType error code. 0~means success.
+ *
+ * @note:
+ * All arrays in the returned @FT_Palette_Data structure are read-only.
+ *
+ * This function always returns an error if the config macro
+ * `TT_CONFIG_OPTION_COLOR_LAYERS` is not defined in `ftoption.h`.
+ *
+ * @since:
+ * 2.10
+ */
+ FT_EXPORT( FT_Error )
+ FT_Palette_Data_Get( FT_Face face,
+ FT_Palette_Data *apalette );
+
+
+ /**************************************************************************
+ *
+ * @function:
+ * FT_Palette_Select
+ *
+ * @description:
+ * This function has two purposes.
+ *
+ * (1) It activates a palette for rendering color glyphs, and
+ *
+ * (2) it retrieves all (unmodified) color entries of this palette. This
+ * function returns a read-write array, which means that a calling
+ * application can modify the palette entries on demand.
+ *
+ * A corollary of (2) is that calling the function, then modifying some
+ * values, then calling the function again with the same arguments resets
+ * all color entries to the original 'CPAL' values; all user modifications
+ * are lost.
+ *
+ * @input:
+ * face ::
+ * The source face handle.
+ *
+ * palette_index ::
+ * The palette index.
+ *
+ * @output:
+ * apalette ::
+ * An array of color entries for a palette with index `palette_index`,
+ * having `num_palette_entries` elements (as found in the
+ * `FT_Palette_Data` structure). If `apalette` is set to `NULL`, no
+ * array gets returned (and no color entries can be modified).
+ *
+ * In case the font doesn't support color palettes, `NULL` is returned.
+ *
+ * @return:
+ * FreeType error code. 0~means success.
+ *
+ * @note:
+ * The array pointed to by `apalette_entries` is owned and managed by
+ * FreeType.
+ *
+ * This function always returns an error if the config macro
+ * `TT_CONFIG_OPTION_COLOR_LAYERS` is not defined in `ftoption.h`.
+ *
+ * @since:
+ * 2.10
+ */
+ FT_EXPORT( FT_Error )
+ FT_Palette_Select( FT_Face face,
+ FT_UShort palette_index,
+ FT_Color* *apalette );
+
+
+ /**************************************************************************
+ *
+ * @function:
+ * FT_Palette_Set_Foreground_Color
+ *
+ * @description:
+ * 'COLR' uses palette index 0xFFFF to indicate a 'text foreground
+ * color'. This function sets this value.
+ *
+ * @input:
+ * face ::
+ * The source face handle.
+ *
+ * foreground_color ::
+ * An `FT_Color` structure to define the text foreground color.
+ *
+ * @return:
+ * FreeType error code. 0~means success.
+ *
+ * @note:
+ * If this function isn't called, the text foreground color is set to
+ * white opaque (BGRA value 0xFFFFFFFF) if
+ * @FT_PALETTE_FOR_DARK_BACKGROUND is present for the current palette,
+ * and black opaque (BGRA value 0x000000FF) otherwise, including the case
+ * that no palette types are available in the 'CPAL' table.
+ *
+ * This function always returns an error if the config macro
+ * `TT_CONFIG_OPTION_COLOR_LAYERS` is not defined in `ftoption.h`.
+ *
+ * @since:
+ * 2.10
+ */
+ FT_EXPORT( FT_Error )
+ FT_Palette_Set_Foreground_Color( FT_Face face,
+ FT_Color foreground_color );
+
+
+ /**************************************************************************
+ *
+ * @section:
+ * layer_management
+ *
+ * @title:
+ * Glyph Layer Management
+ *
+ * @abstract:
+ * Retrieving and manipulating OpenType's 'COLR' table data.
+ *
+ * @description:
+ * The functions described here allow access of colored glyph layer data
+ * in OpenType's 'COLR' tables.
+ */
+
+
+ /**************************************************************************
+ *
+ * @struct:
+ * FT_LayerIterator
+ *
+ * @description:
+ * This iterator object is needed for @FT_Get_Color_Glyph_Layer.
+ *
+ * @fields:
+ * num_layers ::
+ * The number of glyph layers for the requested glyph index. Will be
+ * set by @FT_Get_Color_Glyph_Layer.
+ *
+ * layer ::
+ * The current layer. Will be set by @FT_Get_Color_Glyph_Layer.
+ *
+ * p ::
+ * An opaque pointer into 'COLR' table data. The caller must set this
+ * to `NULL` before the first call of @FT_Get_Color_Glyph_Layer.
+ */
+ typedef struct FT_LayerIterator_
+ {
+ FT_UInt num_layers;
+ FT_UInt layer;
+ FT_Byte* p;
+
+ } FT_LayerIterator;
+
+
+ /**************************************************************************
+ *
+ * @function:
+ * FT_Get_Color_Glyph_Layer
+ *
+ * @description:
+ * This is an interface to the 'COLR' table in OpenType fonts to
+ * iteratively retrieve the colored glyph layers associated with the
+ * current glyph slot.
+ *
+ * https://docs.microsoft.com/en-us/typography/opentype/spec/colr
+ *
+ * The glyph layer data for a given glyph index, if present, provides an
+ * alternative, multi-color glyph representation: Instead of rendering
+ * the outline or bitmap with the given glyph index, glyphs with the
+ * indices and colors returned by this function are rendered layer by
+ * layer.
+ *
+ * The returned elements are ordered in the z~direction from bottom to
+ * top; the 'n'th element should be rendered with the associated palette
+ * color and blended on top of the already rendered layers (elements 0,
+ * 1, ..., n-1).
+ *
+ * @input:
+ * face ::
+ * A handle to the parent face object.
+ *
+ * base_glyph ::
+ * The glyph index the colored glyph layers are associated with.
+ *
+ * @inout:
+ * iterator ::
+ * An @FT_LayerIterator object. For the first call you should set
+ * `iterator->p` to `NULL`. For all following calls, simply use the
+ * same object again.
+ *
+ * @output:
+ * aglyph_index ::
+ * The glyph index of the current layer.
+ *
+ * acolor_index ::
+ * The color index into the font face's color palette of the current
+ * layer. The value 0xFFFF is special; it doesn't reference a palette
+ * entry but indicates that the text foreground color should be used
+ * instead (to be set up by the application outside of FreeType).
+ *
+ * The color palette can be retrieved with @FT_Palette_Select.
+ *
+ * @return:
+ * Value~1 if everything is OK. If there are no more layers (or if there
+ * are no layers at all), value~0 gets returned. In case of an error,
+ * value~0 is returned also.
+ *
+ * @note:
+ * This function is necessary if you want to handle glyph layers by
+ * yourself. In particular, functions that operate with @FT_GlyphRec
+ * objects (like @FT_Get_Glyph or @FT_Glyph_To_Bitmap) don't have access
+ * to this information.
+ *
+ * Note that @FT_Render_Glyph is able to handle colored glyph layers
+ * automatically if the @FT_LOAD_COLOR flag is passed to a previous call
+ * to @FT_Load_Glyph. [This is an experimental feature.]
+ *
+ * @example:
+ * ```
+ * FT_Color* palette;
+ * FT_LayerIterator iterator;
+ *
+ * FT_Bool have_layers;
+ * FT_UInt layer_glyph_index;
+ * FT_UInt layer_color_index;
+ *
+ *
+ * error = FT_Palette_Select( face, palette_index, &palette );
+ * if ( error )
+ * palette = NULL;
+ *
+ * iterator.p = NULL;
+ * have_layers = FT_Get_Color_Glyph_Layer( face,
+ * glyph_index,
+ * &layer_glyph_index,
+ * &layer_color_index,
+ * &iterator );
+ *
+ * if ( palette && have_layers )
+ * {
+ * do
+ * {
+ * FT_Color layer_color;
+ *
+ *
+ * if ( layer_color_index == 0xFFFF )
+ * layer_color = text_foreground_color;
+ * else
+ * layer_color = palette[layer_color_index];
+ *
+ * // Load and render glyph `layer_glyph_index', then
+ * // blend resulting pixmap (using color `layer_color')
+ * // with previously created pixmaps.
+ *
+ * } while ( FT_Get_Color_Glyph_Layer( face,
+ * glyph_index,
+ * &layer_glyph_index,
+ * &layer_color_index,
+ * &iterator ) );
+ * }
+ * ```
+ */
+ FT_EXPORT( FT_Bool )
+ FT_Get_Color_Glyph_Layer( FT_Face face,
+ FT_UInt base_glyph,
+ FT_UInt *aglyph_index,
+ FT_UInt *acolor_index,
+ FT_LayerIterator* iterator );
+
+
+ /**************************************************************************
+ *
+ * @enum:
+ * FT_PaintFormat
+ *
+ * @description:
+ * Enumeration describing the different paint format types of the v1
+ * extensions to the 'COLR' table, see
+ * 'https://github.com/googlefonts/colr-gradients-spec'.
+ *
+ * The enumeration values losely correspond with the format numbers of
+ * the specification: FreeType always returns a fully specified 'Paint'
+ * structure for the 'Transform', 'Translate', 'Scale', 'Rotate', and
+ * 'Skew' table types even though the specification has different formats
+ * depending on whether or not a center is specified, whether the scale
+ * is uniform in x and y~direction or not, etc. Also, only non-variable
+ * format identifiers are listed in this enumeration; as soon as support
+ * for variable 'COLR' v1 fonts is implemented, interpolation is
+ * performed dependent on axis coordinates, which are configured on the
+ * @FT_Face through @FT_Set_Var_Design_Coordinates. This implies that
+ * always static, readily interpolated values are returned in the 'Paint'
+ * structures.
+ *
+ * @since:
+ * 2.11 -- **currently experimental only!** There might be changes
+ * without retaining backward compatibility of both the API and ABI.
+ *
+ */
+ typedef enum FT_PaintFormat_
+ {
+ FT_COLR_PAINTFORMAT_COLR_LAYERS = 1,
+ FT_COLR_PAINTFORMAT_SOLID = 2,
+ FT_COLR_PAINTFORMAT_LINEAR_GRADIENT = 4,
+ FT_COLR_PAINTFORMAT_RADIAL_GRADIENT = 6,
+ FT_COLR_PAINTFORMAT_SWEEP_GRADIENT = 8,
+ FT_COLR_PAINTFORMAT_GLYPH = 10,
+ FT_COLR_PAINTFORMAT_COLR_GLYPH = 11,
+ FT_COLR_PAINTFORMAT_TRANSFORM = 12,
+ FT_COLR_PAINTFORMAT_TRANSLATE = 14,
+ FT_COLR_PAINTFORMAT_SCALE = 16,
+ FT_COLR_PAINTFORMAT_ROTATE = 24,
+ FT_COLR_PAINTFORMAT_SKEW = 28,
+ FT_COLR_PAINTFORMAT_COMPOSITE = 32,
+ FT_COLR_PAINT_FORMAT_MAX = 33,
+ FT_COLR_PAINTFORMAT_UNSUPPORTED = 255
+
+ } FT_PaintFormat;
+
+
+ /**************************************************************************
+ *
+ * @struct:
+ * FT_ColorStopIterator
+ *
+ * @description:
+ * This iterator object is needed for @FT_Get_Colorline_Stops. It keeps
+ * state while iterating over the stops of an @FT_ColorLine,
+ * representing the `ColorLine` struct of the v1 extensions to 'COLR',
+ * see 'https://github.com/googlefonts/colr-gradients-spec'.
+ *
+ * @fields:
+ * num_color_stops ::
+ * The number of color stops for the requested glyph index. Set by
+ * @FT_Get_Colorline_Stops.
+ *
+ * current_color_stop ::
+ * The current color stop. Set by @FT_Get_Colorline_Stops.
+ *
+ * p ::
+ * An opaque pointer into 'COLR' table data. The caller must set this
+ * to `NULL` before the first call of @FT_Get_Colorline_Stops.
+ *
+ * @since:
+ * 2.11 -- **currently experimental only!** There might be changes
+ * without retaining backward compatibility of both the API and ABI.
+ *
+ */
+ typedef struct FT_ColorStopIterator_
+ {
+ FT_UInt num_color_stops;
+ FT_UInt current_color_stop;
+
+ FT_Byte* p;
+
+ } FT_ColorStopIterator;
+
+
+ /**************************************************************************
+ *
+ * @struct:
+ * FT_ColorIndex
+ *
+ * @description:
+ * A structure representing a `ColorIndex` value of the 'COLR' v1
+ * extensions, see 'https://github.com/googlefonts/colr-gradients-spec'.
+ *
+ * @fields:
+ * palette_index ::
+ * The palette index into a 'CPAL' palette.
+ *
+ * alpha ::
+ * Alpha transparency value multiplied with the value from 'CPAL'.
+ *
+ * @since:
+ * 2.11 -- **currently experimental only!** There might be changes
+ * without retaining backward compatibility of both the API and ABI.
+ *
+ */
+ typedef struct FT_ColorIndex_
+ {
+ FT_UInt16 palette_index;
+ FT_F2Dot14 alpha;
+
+ } FT_ColorIndex;
+
+
+ /**************************************************************************
+ *
+ * @struct:
+ * FT_ColorStop
+ *
+ * @description:
+ * A structure representing a `ColorStop` value of the 'COLR' v1
+ * extensions, see 'https://github.com/googlefonts/colr-gradients-spec'.
+ *
+ * @fields:
+ * stop_offset ::
+ * The stop offset between 0 and 1 along the gradient.
+ *
+ * color ::
+ * The color information for this stop, see @FT_ColorIndex.
+ *
+ * @since:
+ * 2.11 -- **currently experimental only!** There might be changes
+ * without retaining backward compatibility of both the API and ABI.
+ *
+ */
+ typedef struct FT_ColorStop_
+ {
+ FT_F2Dot14 stop_offset;
+ FT_ColorIndex color;
+
+ } FT_ColorStop;
+
+
+ /**************************************************************************
+ *
+ * @enum:
+ * FT_PaintExtend
+ *
+ * @description:
+ * An enumeration representing the 'Extend' mode of the 'COLR' v1
+ * extensions, see 'https://github.com/googlefonts/colr-gradients-spec'.
+ * It describes how the gradient fill continues at the other boundaries.
+ *
+ * @since:
+ * 2.11 -- **currently experimental only!** There might be changes
+ * without retaining backward compatibility of both the API and ABI.
+ *
+ */
+ typedef enum FT_PaintExtend_
+ {
+ FT_COLR_PAINT_EXTEND_PAD = 0,
+ FT_COLR_PAINT_EXTEND_REPEAT = 1,
+ FT_COLR_PAINT_EXTEND_REFLECT = 2
+
+ } FT_PaintExtend;
+
+
+ /**************************************************************************
+ *
+ * @struct:
+ * FT_ColorLine
+ *
+ * @description:
+ * A structure representing a `ColorLine` value of the 'COLR' v1
+ * extensions, see 'https://github.com/googlefonts/colr-gradients-spec'.
+ * It describes a list of color stops along the defined gradient.
+ *
+ * @fields:
+ * extend ::
+ * The extend mode at the outer boundaries, see @FT_PaintExtend.
+ *
+ * color_stop_iterator ::
+ * The @FT_ColorStopIterator used to enumerate and retrieve the
+ * actual @FT_ColorStop's.
+ *
+ * @since:
+ * 2.11 -- **currently experimental only!** There might be changes
+ * without retaining backward compatibility of both the API and ABI.
+ *
+ */
+ typedef struct FT_ColorLine_
+ {
+ FT_PaintExtend extend;
+ FT_ColorStopIterator color_stop_iterator;
+
+ } FT_ColorLine;
+
+
+ /**************************************************************************
+ *
+ * @struct:
+ * FT_Affine23
+ *
+ * @description:
+ * A structure used to store a 2x3 matrix. Coefficients are in
+ * 16.16 fixed-point format. The computation performed is
+ *
+ * ```
+ * x' = x*xx + y*xy + dx
+ * y' = x*yx + y*yy + dy
+ * ```
+ *
+ * @fields:
+ * xx ::
+ * Matrix coefficient.
+ *
+ * xy ::
+ * Matrix coefficient.
+ *
+ * dx ::
+ * x translation.
+ *
+ * yx ::
+ * Matrix coefficient.
+ *
+ * yy ::
+ * Matrix coefficient.
+ *
+ * dy ::
+ * y translation.
+ *
+ * @since:
+ * 2.11 -- **currently experimental only!** There might be changes
+ * without retaining backward compatibility of both the API and ABI.
+ *
+ */
+ typedef struct FT_Affine_23_
+ {
+ FT_Fixed xx, xy, dx;
+ FT_Fixed yx, yy, dy;
+
+ } FT_Affine23;
+
+
+ /**************************************************************************
+ *
+ * @enum:
+ * FT_Composite_Mode
+ *
+ * @description:
+ * An enumeration listing the 'COLR' v1 composite modes used in
+ * @FT_PaintComposite. For more details on each paint mode, see
+ * 'https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators'.
+ *
+ * @since:
+ * 2.11 -- **currently experimental only!** There might be changes
+ * without retaining backward compatibility of both the API and ABI.
+ *
+ */
+ typedef enum FT_Composite_Mode_
+ {
+ FT_COLR_COMPOSITE_CLEAR = 0,
+ FT_COLR_COMPOSITE_SRC = 1,
+ FT_COLR_COMPOSITE_DEST = 2,
+ FT_COLR_COMPOSITE_SRC_OVER = 3,
+ FT_COLR_COMPOSITE_DEST_OVER = 4,
+ FT_COLR_COMPOSITE_SRC_IN = 5,
+ FT_COLR_COMPOSITE_DEST_IN = 6,
+ FT_COLR_COMPOSITE_SRC_OUT = 7,
+ FT_COLR_COMPOSITE_DEST_OUT = 8,
+ FT_COLR_COMPOSITE_SRC_ATOP = 9,
+ FT_COLR_COMPOSITE_DEST_ATOP = 10,
+ FT_COLR_COMPOSITE_XOR = 11,
+ FT_COLR_COMPOSITE_SCREEN = 12,
+ FT_COLR_COMPOSITE_OVERLAY = 13,
+ FT_COLR_COMPOSITE_DARKEN = 14,
+ FT_COLR_COMPOSITE_LIGHTEN = 15,
+ FT_COLR_COMPOSITE_COLOR_DODGE = 16,
+ FT_COLR_COMPOSITE_COLOR_BURN = 17,
+ FT_COLR_COMPOSITE_HARD_LIGHT = 18,
+ FT_COLR_COMPOSITE_SOFT_LIGHT = 19,
+ FT_COLR_COMPOSITE_DIFFERENCE = 20,
+ FT_COLR_COMPOSITE_EXCLUSION = 21,
+ FT_COLR_COMPOSITE_MULTIPLY = 22,
+ FT_COLR_COMPOSITE_HSL_HUE = 23,
+ FT_COLR_COMPOSITE_HSL_SATURATION = 24,
+ FT_COLR_COMPOSITE_HSL_COLOR = 25,
+ FT_COLR_COMPOSITE_HSL_LUMINOSITY = 26,
+ FT_COLR_COMPOSITE_MAX = 27
+
+ } FT_Composite_Mode;
+
+
+ /**************************************************************************
+ *
+ * @struct:
+ * FT_OpaquePaint
+ *
+ * @description:
+ * A structure representing an offset to a `Paint` value stored in any
+ * of the paint tables of a 'COLR' v1 font. Compare Offset<24> there.
+ * When 'COLR' v1 paint tables represented by FreeType objects such as
+ * @FT_PaintColrLayers, @FT_PaintComposite, or @FT_PaintTransform
+ * reference downstream nested paint tables, we do not immediately
+ * retrieve them but encapsulate their location in this type. Use
+ * @FT_Get_Paint to retrieve the actual @FT_COLR_Paint object that
+ * describes the details of the respective paint table.
+ *
+ * @fields:
+ * p ::
+ * An internal offset to a Paint table, needs to be set to NULL before
+ * passing this struct as an argument to @FT_Get_Paint.
+ *
+ * insert_root_transform ::
+ * An internal boolean to track whether an initial root transform is
+ * to be provided. Do not set this value.
+ *
+ * @since:
+ * 2.11 -- **currently experimental only!** There might be changes
+ * without retaining backward compatibility of both the API and ABI.
+ *
+ */
+ typedef struct FT_Opaque_Paint_
+ {
+ FT_Byte* p;
+ FT_Bool insert_root_transform;
+ } FT_OpaquePaint;
+
+
+ /**************************************************************************
+ *
+ * @struct:
+ * FT_PaintColrLayers
+ *
+ * @description:
+ * A structure representing a `PaintColrLayers` table of a 'COLR' v1
+ * font. This table describes a set of layers that are to be composited
+ * with composite mode `FT_COLR_COMPOSITE_SRC_OVER`. The return value
+ * of this function is an @FT_LayerIterator initialized so that it can
+ * be used with @FT_Get_Paint_Layers to retrieve the @FT_OpaquePaint
+ * objects as references to each layer.
+ *
+ * @fields:
+ * layer_iterator ::
+ * The layer iterator that describes the layers of this paint.
+ *
+ * @since:
+ * 2.11 -- **currently experimental only!** There might be changes
+ * without retaining backward compatibility of both the API and ABI.
+ *
+ */
+ typedef struct FT_PaintColrLayers_
+ {
+ FT_LayerIterator layer_iterator;
+
+ } FT_PaintColrLayers;
+
+
+ /**************************************************************************
+ *
+ * @struct:
+ * FT_PaintSolid
+ *
+ * @description:
+ * A structure representing a `PaintSolid` value of the 'COLR' v1
+ * extensions, see 'https://github.com/googlefonts/colr-gradients-spec'.
+ * Using a `PaintSolid` value means that the glyph layer filled with
+ * this paint is solid-colored and does not contain a gradient.
+ *
+ * @fields:
+ * color ::
+ * The color information for this solid paint, see @FT_ColorIndex.
+ *
+ * @since:
+ * 2.11 -- **currently experimental only!** There might be changes
+ * without retaining backward compatibility of both the API and ABI.
+ *
+ */
+ typedef struct FT_PaintSolid_
+ {
+ FT_ColorIndex color;
+
+ } FT_PaintSolid;
+
+
+ /**************************************************************************
+ *
+ * @struct:
+ * FT_PaintLinearGradient
+ *
+ * @description:
+ * A structure representing a `PaintLinearGradient` value of the 'COLR'
+ * v1 extensions, see
+ * 'https://github.com/googlefonts/colr-gradients-spec'. The glyph
+ * layer filled with this paint is drawn filled with a linear gradient.
+ *
+ * @fields:
+ * colorline ::
+ * The @FT_ColorLine information for this paint, i.e., the list of
+ * color stops along the gradient.
+ *
+ * p0 ::
+ * The starting point of the gradient definition (in font units).
+ *
+ * p1 ::
+ * The end point of the gradient definition (in font units).
+ *
+ * p2 ::
+ * Optional point~p2 to rotate the gradient (in font units).
+ * Otherwise equal to~p0.
+ *
+ * @since:
+ * 2.11 -- **currently experimental only!** There might be changes
+ * without retaining backward compatibility of both the API and ABI.
+ *
+ */
+ typedef struct FT_PaintLinearGradient_
+ {
+ FT_ColorLine colorline;
+
+ /* TODO: Potentially expose those as x0, y0 etc. */
+ FT_Vector p0;
+ FT_Vector p1;
+ FT_Vector p2;
+
+ } FT_PaintLinearGradient;
+
+
+ /**************************************************************************
+ *
+ * @struct:
+ * FT_PaintRadialGradient
+ *
+ * @description:
+ * A structure representing a `PaintRadialGradient` value of the 'COLR'
+ * v1 extensions, see
+ * 'https://github.com/googlefonts/colr-gradients-spec'. The glyph
+ * layer filled with this paint is drawn filled filled with a radial
+ * gradient.
+ *
+ * @fields:
+ * colorline ::
+ * The @FT_ColorLine information for this paint, i.e., the list of
+ * color stops along the gradient.
+ *
+ * c0 ::
+ * The center of the starting point of the radial gradient (in font
+ * units).
+ *
+ * r0 ::
+ * The radius of the starting circle of the radial gradient (in font
+ * units).
+ *
+ * c1 ::
+ * The center of the end point of the radial gradient (in font units).
+ *
+ * r1 ::
+ * The radius of the end circle of the radial gradient (in font
+ * units).
+ *
+ * @since:
+ * 2.11 -- **currently experimental only!** There might be changes
+ * without retaining backward compatibility of both the API and ABI.
+ *
+ */
+ typedef struct FT_PaintRadialGradient_
+ {
+ FT_ColorLine colorline;
+
+ FT_Vector c0;
+ FT_UShort r0;
+ FT_Vector c1;
+ FT_UShort r1;
+
+ } FT_PaintRadialGradient;
+
+
+ /**************************************************************************
+ *
+ * @struct:
+ * FT_PaintSweepGradient
+ *
+ * @description:
+ * A structure representing a `PaintSweepGradient` value of the 'COLR'
+ * v1 extensions, see
+ * 'https://github.com/googlefonts/colr-gradients-spec'. The glyph
+ * layer filled with this paint is drawn filled with a sweep gradient
+ * from `start_angle` to `end_angle`.
+ *
+ * @fields:
+ * colorline ::
+ * The @FT_ColorLine information for this paint, i.e., the list of
+ * color stops along the gradient.
+ *
+ * center ::
+ * The center of the sweep gradient (in font units).
+ *
+ * start_angle ::
+ * The start angle of the sweep gradient, in 16.16 fixed point format
+ * specifying degrees. Values are given counter-clockwise, starting
+ * from the (positive) y~axis.
+ *
+ * end_angle ::
+ * The end angle of the sweep gradient, in 16.16 fixed point format
+ * specifying degrees. Values are given counter-clockwise, starting
+ * from the (positive) y~axis.
+ *
+ * @since:
+ * 2.11 -- **currently experimental only!** There might be changes
+ * without retaining backward compatibility of both the API and ABI.
+ *
+ */
+ typedef struct FT_PaintSweepGradient_
+ {
+ FT_ColorLine colorline;
+
+ FT_Vector center;
+ FT_Fixed start_angle;
+ FT_Fixed end_angle;
+
+ } FT_PaintSweepGradient;
+
+
+ /**************************************************************************
+ *
+ * @struct:
+ * FT_PaintGlyph
+ *
+ * @description:
+ * A structure representing a 'COLR' v1 `PaintGlyph` paint table.
+ *
+ * @fields:
+ * paint ::
+ * An opaque paint object pointing to a `Paint` table that serves as
+ * the fill for the glyph ID.
+ *
+ * glyphID ::
+ * The glyph ID from the 'glyf' table, which serves as the contour
+ * information that is filled with paint.
+ *
+ * @since:
+ * 2.11 -- **currently experimental only!** There might be changes
+ * without retaining backward compatibility of both the API and ABI.
+ *
+ */
+ typedef struct FT_PaintGlyph_
+ {
+ FT_OpaquePaint paint;
+ FT_UInt glyphID;
+
+ } FT_PaintGlyph;
+
+
+ /**************************************************************************
+ *
+ * @struct:
+ * FT_PaintColrGlyph
+ *
+ * @description:
+ * A structure representing a 'COLR' v1 `PaintColorGlyph` paint table.
+ *
+ * @fields:
+ * glyphID ::
+ * The glyph ID from the `BaseGlyphV1List` table that is drawn for
+ * this paint.
+ *
+ * @since:
+ * 2.11 -- **currently experimental only!** There might be changes
+ * without retaining backward compatibility of both the API and ABI.
+ *
+ */
+ typedef struct FT_PaintColrGlyph_
+ {
+ FT_UInt glyphID;
+
+ } FT_PaintColrGlyph;
+
+
+ /**************************************************************************
+ *
+ * @struct:
+ * FT_PaintTransform
+ *
+ * @description:
+ * A structure representing a 'COLR' v1 `PaintTransform` paint table.
+ *
+ * @fields:
+ * paint ::
+ * An opaque paint that is subject to being transformed.
+ *
+ * affine ::
+ * A 2x3 transformation matrix in @FT_Affine23 format.
+ *
+ * @since:
+ * 2.11 -- **currently experimental only!** There might be changes
+ * without retaining backward compatibility of both the API and ABI.
+ *
+ */
+ typedef struct FT_PaintTransform_
+ {
+ FT_OpaquePaint paint;
+ FT_Affine23 affine;
+
+ } FT_PaintTransform;
+
+
+ /**************************************************************************
+ *
+ * @struct:
+ * FT_PaintTranslate
+ *
+ * @description:
+ * A structure representing a 'COLR' v1 `PaintTranslate` paint table.
+ * Used for translating downstream paints by a given x and y~delta.
+ *
+ * @fields:
+ * paint ::
+ * An @FT_OpaquePaint object referencing the paint that is to be
+ * rotated.
+ *
+ * dx ::
+ * Translation in x~direction (in font units).
+ *
+ * dy ::
+ * Translation in y~direction (in font units).
+ *
+ * @since:
+ * 2.11 -- **currently experimental only!** There might be changes
+ * without retaining backward compatibility of both the API and ABI.
+ *
+ */
+ typedef struct FT_PaintTranslate_
+ {
+ FT_OpaquePaint paint;
+
+ FT_Fixed dx;
+ FT_Fixed dy;
+
+ } FT_PaintTranslate;
+
+
+ /**************************************************************************
+ *
+ * @struct:
+ * FT_PaintScale
+ *
+ * @description:
+ * A structure representing all of the 'COLR' v1 'PaintScale*' paint
+ * tables. Used for scaling downstream paints by a given x and y~scale,
+ * with a given center. This structure is used for all 'PaintScale*'
+ * types that are part of specification; fields of this structure are
+ * filled accordingly. If there is a center, the center values are set,
+ * otherwise they are set to the zero coordinate. If the source font
+ * file has 'PaintScaleUniform*' set, the scale values are set
+ * accordingly to the same value.
+ *
+ * @fields:
+ * paint ::
+ * An @FT_OpaquePaint object referencing the paint that is to be
+ * scaled.
+ *
+ * scale_x ::
+ * Scale factor in x~direction.
+ *
+ * scale_y ::
+ * Scale factor in y~direction.
+ *
+ * center_x ::
+ * x~coordinate of center point to scale from.
+ *
+ * center_y ::
+ * y~coordinate of center point to scale from.
+ *
+ * @since:
+ * 2.11 -- **currently experimental only!** There might be changes
+ * without retaining backward-compatibility of both the API and ABI.
+ *
+ */
+ typedef struct FT_PaintScale_
+ {
+ FT_OpaquePaint paint;
+
+ FT_Fixed scale_x;
+ FT_Fixed scale_y;
+
+ FT_Fixed center_x;
+ FT_Fixed center_y;
+
+ } FT_PaintScale;
+
+
+ /**************************************************************************
+ *
+ * @struct:
+ * FT_PaintRotate
+ *
+ * @description:
+ * A structure representing a 'COLR' v1 `PaintRotate` paint table. Used
+ * for rotating downstream paints with a given center and angle.
+ *
+ * @fields:
+ * paint ::
+ * An @FT_OpaquePaint object referencing the paint that is to be
+ * rotated.
+ *
+ * angle ::
+ * The rotation angle that is to be applied.
+ *
+ * center_x ::
+ * The x~coordinate of the pivot point of the rotation (in font
+ * units).
+ *
+ * center_y ::
+ * The y~coordinate of the pivot point of the rotation (in font
+ * units).
+ *
+ * @since:
+ * 2.11 -- **currently experimental only!** There might be changes
+ * without retaining backward compatibility of both the API and ABI.
+ *
+ */
+
+ typedef struct FT_PaintRotate_
+ {
+ FT_OpaquePaint paint;
+
+ FT_Fixed angle;
+
+ FT_Fixed center_x;
+ FT_Fixed center_y;
+
+ } FT_PaintRotate;
+
+
+ /**************************************************************************
+ *
+ * @struct:
+ * FT_PaintSkew
+ *
+ * @description:
+ * A structure representing a 'COLR' v1 `PaintSkew` paint table. Used
+ * for skewing or shearing downstream paints by a given center and
+ * angle.
+ *
+ * @fields:
+ * paint ::
+ * An @FT_OpaquePaint object referencing the paint that is to be
+ * skewed.
+ *
+ * x_skew_angle ::
+ * The skewing angle in x~direction.
+ *
+ * y_skew_angle ::
+ * The skewing angle in y~direction.
+ *
+ * center_x ::
+ * The x~coordinate of the pivot point of the skew (in font units).
+ *
+ * center_y ::
+ * The y~coordinate of the pivot point of the skew (in font units).
+ *
+ * @since:
+ * 2.11 -- **currently experimental only!** There might be changes
+ * without retaining backward compatibility of both the API and ABI.
+ *
+ */
+ typedef struct FT_PaintSkew_
+ {
+ FT_OpaquePaint paint;
+
+ FT_Fixed x_skew_angle;
+ FT_Fixed y_skew_angle;
+
+ FT_Fixed center_x;
+ FT_Fixed center_y;
+
+ } FT_PaintSkew;
+
+
+ /**************************************************************************
+ *
+ * @struct:
+ * FT_PaintComposite
+ *
+ * @description:
+ * A structure representing a 'COLR'v1 `PaintComposite` paint table.
+ * Used for compositing two paints in a 'COLR' v1 directed acycling
+ * graph.
+ *
+ * @fields:
+ * source_paint ::
+ * An @FT_OpaquePaint object referencing the source that is to be
+ * composited.
+ *
+ * composite_mode ::
+ * An @FT_Composite_Mode enum value determining the composition
+ * operation.
+ *
+ * backdrop_paint ::
+ * An @FT_OpaquePaint object referencing the backdrop paint that
+ * `source_paint` is composited onto.
+ *
+ * @since:
+ * 2.11 -- **currently experimental only!** There might be changes
+ * without retaining backward compatibility of both the API and ABI.
+ *
+ */
+ typedef struct FT_PaintComposite_
+ {
+ FT_OpaquePaint source_paint;
+ FT_Composite_Mode composite_mode;
+ FT_OpaquePaint backdrop_paint;
+
+ } FT_PaintComposite;
+
+
+ /**************************************************************************
+ *
+ * @union:
+ * FT_COLR_Paint
+ *
+ * @description:
+ * A union object representing format and details of a paint table of a
+ * 'COLR' v1 font, see
+ * 'https://github.com/googlefonts/colr-gradients-spec'. Use
+ * @FT_Get_Paint to retrieve a @FT_COLR_Paint for an @FT_OpaquePaint
+ * object.
+ *
+ * @fields:
+ * format ::
+ * The gradient format for this Paint structure.
+ *
+ * u ::
+ * Union of all paint table types:
+ *
+ * * @FT_PaintColrLayers
+ * * @FT_PaintGlyph
+ * * @FT_PaintSolid
+ * * @FT_PaintLinearGradient
+ * * @FT_PaintRadialGradient
+ * * @FT_PaintSweepGradient
+ * * @FT_PaintTransform
+ * * @FT_PaintTranslate
+ * * @FT_PaintRotate
+ * * @FT_PaintSkew
+ * * @FT_PaintComposite
+ * * @FT_PaintColrGlyph
+ *
+ * @since:
+ * 2.11 -- **currently experimental only!** There might be changes
+ * without retaining backward compatibility of both the API and ABI.
+ *
+ */
+ typedef struct FT_COLR_Paint_
+ {
+ FT_PaintFormat format;
+
+ union
+ {
+ FT_PaintColrLayers colr_layers;
+ FT_PaintGlyph glyph;
+ FT_PaintSolid solid;
+ FT_PaintLinearGradient linear_gradient;
+ FT_PaintRadialGradient radial_gradient;
+ FT_PaintSweepGradient sweep_gradient;
+ FT_PaintTransform transform;
+ FT_PaintTranslate translate;
+ FT_PaintScale scale;
+ FT_PaintRotate rotate;
+ FT_PaintSkew skew;
+ FT_PaintComposite composite;
+ FT_PaintColrGlyph colr_glyph;
+
+ } u;
+
+ } FT_COLR_Paint;
+
+
+ /**************************************************************************
+ *
+ * @enum:
+ * FT_Color_Root_Transform
+ *
+ * @description:
+ * An enumeration to specify whether @FT_Get_Color_Glyph_Paint is to
+ * return a root transform to configure the client's graphics context
+ * matrix.
+ *
+ * @values:
+ * FT_COLOR_INCLUDE_ROOT_TRANSFORM ::
+ * Do include the root transform as the initial @FT_COLR_Paint object.
+ *
+ * FT_COLOR_NO_ROOT_TRANSFORM ::
+ * Do not output an initial root transform.
+ *
+ * @since:
+ * 2.11 -- **currently experimental only!** There might be changes
+ * without retaining backward compatibility of both the API and ABI.
+ *
+ */
+ typedef enum FT_Color_Root_Transform_
+ {
+ FT_COLOR_INCLUDE_ROOT_TRANSFORM,
+ FT_COLOR_NO_ROOT_TRANSFORM,
+
+ FT_COLOR_ROOT_TRANSFORM_MAX
+
+ } FT_Color_Root_Transform;
+
+
+ /**************************************************************************
+ *
+ * @function:
+ * FT_Get_Color_Glyph_Paint
+ *
+ * @description:
+ * This is the starting point and interface to color gradient
+ * information in a 'COLR' v1 table in OpenType fonts to recursively
+ * retrieve the paint tables for the directed acyclic graph of a colored
+ * glyph, given a glyph ID.
+ *
+ * https://github.com/googlefonts/colr-gradients-spec
+ *
+ * In a 'COLR' v1 font, each color glyph defines a directed acyclic
+ * graph of nested paint tables, such as `PaintGlyph`, `PaintSolid`,
+ * `PaintLinearGradient`, `PaintRadialGradient`, and so on. Using this
+ * function and specifying a glyph ID, one retrieves the root paint
+ * table for this glyph ID.
+ *
+ * This function allows control whether an initial root transform is
+ * returned to configure scaling, transform, and translation correctly
+ * on the client's graphics context. The initial root transform is
+ * computed and returned according to the values configured for @FT_Size
+ * and @FT_Set_Transform on the @FT_Face object, see below for details
+ * of the `root_transform` parameter. This has implications for a
+ * client 'COLR' v1 implementation: When this function returns an
+ * initially computed root transform, at the time of executing the
+ * @FT_PaintGlyph operation, the contours should be retrieved using
+ * @FT_Load_Glyph at unscaled, untransformed size. This is because the
+ * root transform applied to the graphics context will take care of
+ * correct scaling.
+ *
+ * Alternatively, to allow hinting of contours, at the time of executing
+ * @FT_Load_Glyph, the current graphics context transformation matrix
+ * can be decomposed into a scaling matrix and a remainder, and
+ * @FT_Load_Glyph can be used to retrieve the contours at scaled size.
+ * Care must then be taken to blit or clip to the graphics context with
+ * taking this remainder transformation into account.
+ *
+ * @input:
+ * face ::
+ * A handle to the parent face object.
+ *
+ * base_glyph ::
+ * The glyph index for which to retrieve the root paint table.
+ *
+ * root_transform ::
+ * Specifies whether an initially computed root is returned by the
+ * @FT_PaintTransform operation to account for the activated size
+ * (see @FT_Activate_Size) and the configured transform and translate
+ * (see @FT_Set_Transform).
+ *
+ * This root transform is returned before nodes of the glyph graph of
+ * the font are returned. Subsequent @FT_COLR_Paint structures
+ * contain unscaled and untransformed values. The inserted root
+ * transform enables the client application to apply an initial
+ * transform to its graphics context. When executing subsequent
+ * FT_COLR_Paint operations, values from @FT_COLR_Paint operations
+ * will ultimately be correctly scaled because of the root transform
+ * applied to the graphics context. Use
+ * @FT_COLOR_INCLUDE_ROOT_TRANSFORM to include the root transform, use
+ * @FT_COLOR_NO_ROOT_TRANSFORM to not include it. The latter may be
+ * useful when traversing the 'COLR' v1 glyph graph and reaching a
+ * @FT_PaintColrGlyph. When recursing into @FT_PaintColrGlyph and
+ * painting that inline, no additional root transform is needed as it
+ * has already been applied to the graphics context at the beginning
+ * of drawing this glyph.
+ *
+ * @output:
+ * paint ::
+ * The @FT_OpaquePaint object that references the actual paint table.
+ *
+ * The respective actual @FT_COLR_Paint object is retrieved via
+ * @FT_Get_Paint.
+ *
+ * @return:
+ * Value~1 if everything is OK. If no color glyph is found, or the root
+ * paint could not be retrieved, value~0 gets returned. In case of an
+ * error, value~0 is returned also.
+ *
+ * @since:
+ * 2.11 -- **currently experimental only!** There might be changes
+ * without retaining backward compatibility of both the API and ABI.
+ *
+ */
+ FT_EXPORT( FT_Bool )
+ FT_Get_Color_Glyph_Paint( FT_Face face,
+ FT_UInt base_glyph,
+ FT_Color_Root_Transform root_transform,
+ FT_OpaquePaint* paint );
+
+
+ /**************************************************************************
+ *
+ * @function:
+ * FT_Get_Paint_Layers
+ *
+ * @description:
+ * Access the layers of a `PaintColrLayers` table.
+ *
+ * If the root paint of a color glyph, or a nested paint of a 'COLR'
+ * glyph is a `PaintColrLayers` table, this function retrieves the
+ * layers of the `PaintColrLayers` table.
+ *
+ * The @FT_PaintColrLayers object contains an @FT_LayerIterator, which
+ * is used here to iterate over the layers. Each layer is returned as
+ * an @FT_OpaquePaint object, which then can be used with @FT_Get_Paint
+ * to retrieve the actual paint object.
+ *
+ * @input:
+ * face ::
+ * A handle to the parent face object.
+ *
+ * @inout:
+ * iterator ::
+ * The @FT_LayerIterator from an @FT_PaintColrLayers object, for which
+ * the layers are to be retrieved. The internal state of the iterator
+ * is incremented after one call to this function for retrieving one
+ * layer.
+ *
+ * @output:
+ * paint ::
+ * The @FT_OpaquePaint object that references the actual paint table.
+ * The respective actual @FT_COLR_Paint object is retrieved via
+ * @FT_Get_Paint.
+ *
+ * @return:
+ * Value~1 if everything is OK. Value~0 gets returned when the paint
+ * object can not be retrieved or any other error occurs.
+ *
+ * @since:
+ * 2.11 -- **currently experimental only!** There might be changes
+ * without retaining backward compatibility of both the API and ABI.
+ *
+ */
+ FT_EXPORT( FT_Bool )
+ FT_Get_Paint_Layers( FT_Face face,
+ FT_LayerIterator* iterator,
+ FT_OpaquePaint* paint );
+
+
+ /**************************************************************************
+ *
+ * @function:
+ * FT_Get_Colorline_Stops
+ *
+ * @description:
+ * This is an interface to color gradient information in a 'COLR' v1
+ * table in OpenType fonts to iteratively retrieve the gradient and
+ * solid fill information for colored glyph layers for a specified glyph
+ * ID.
+ *
+ * https://github.com/googlefonts/colr-gradients-spec
+ *
+ * @input:
+ * face ::
+ * A handle to the parent face object.
+ *
+ * @inout:
+ * iterator ::
+ * The retrieved @FT_ColorStopIterator, configured on an @FT_ColorLine,
+ * which in turn got retrieved via paint information in
+ * @FT_PaintLinearGradient or @FT_PaintRadialGradient.
+ *
+ * @output:
+ * color_stop ::
+ * Color index and alpha value for the retrieved color stop.
+ *
+ * @return:
+ * Value~1 if everything is OK. If there are no more color stops,
+ * value~0 gets returned. In case of an error, value~0 is returned
+ * also.
+ *
+ * @since:
+ * 2.11 -- **currently experimental only!** There might be changes
+ * without retaining backward compatibility of both the API and ABI.
+ *
+ */
+ FT_EXPORT( FT_Bool )
+ FT_Get_Colorline_Stops( FT_Face face,
+ FT_ColorStop* color_stop,
+ FT_ColorStopIterator* iterator );
+
+
+ /**************************************************************************
+ *
+ * @function:
+ * FT_Get_Paint
+ *
+ * @description:
+ * Access the details of a paint using an @FT_OpaquePaint opaque paint
+ * object, which internally stores the offset to the respective `Paint`
+ * object in the 'COLR' table.
+ *
+ * @input:
+ * face ::
+ * A handle to the parent face object.
+ *
+ * opaque_paint ::
+ * The opaque paint object for which the underlying @FT_COLR_Paint
+ * data is to be retrieved.
+ *
+ * @output:
+ * paint ::
+ * The specific @FT_COLR_Paint object containing information coming
+ * from one of the font's `Paint*` tables.
+ *
+ * @return:
+ * Value~1 if everything is OK. Value~0 if no details can be found for
+ * this paint or any other error occured.
+ *
+ * @since:
+ * 2.11 -- **currently experimental only!** There might be changes
+ * without retaining backward compatibility of both the API and ABI.
+ *
+ */
+ FT_EXPORT( FT_Bool )
+ FT_Get_Paint( FT_Face face,
+ FT_OpaquePaint opaque_paint,
+ FT_COLR_Paint* paint );
+
+ /* */
+
+
+FT_END_HEADER
+
+#endif /* FTCOLOR_H_ */
+
+
+/* END */
diff -Naur a/include/freetype/internal/sfnt.h b/include/freetype/internal/sfnt.h
--- a/include/freetype/internal/sfnt.h 2021-02-13 09:16:54.000000000 +0100
+++ b/include/freetype/internal/sfnt.h 2021-09-27 18:42:28.366661850 +0200
@@ -558,6 +558,44 @@
/**************************************************************************
*
* @functype:
+ * TT_Get_Color_Glyph_ClipBox_Func
+ *
+ * @description:
+ * Search for a 'COLR' v1 clip box for the specified `base_glyph` and
+ * fill the `clip_box` parameter with the 'COLR' v1 'ClipBox' information
+ * if one is found.
+ *
+ * @input:
+ * face ::
+ * A handle to the parent face object.
+ *
+ * base_glyph ::
+ * The glyph index for which to retrieve the clip box.
+ *
+ * @output:
+ * clip_box ::
+ * The clip box for the requested base_glyph if one is found. The clip
+ * box is computed taking scale and transformations configured on the
+ * @FT_Face into account. @FT_ClipBox contains @FT_Vector values in
+ * 26.6 format.
+ *
+ * @note:
+ * To retrieve the clip box in font units, reset scale to units-per-em
+ * and remove transforms configured using @FT_Set_Transform.
+ *
+ * @return:
+ * Value~1 if a ClipBox is found. If no clip box is found or an
+ * error occured, value~0 is returned.
+ */
+ typedef FT_Bool
+ ( *TT_Get_Color_Glyph_ClipBox_Func )( TT_Face face,
+ FT_UInt base_glyph,
+ FT_ClipBox* clip_box );
+
+
+ /**************************************************************************
+ *
+ * @functype:
* TT_Get_Paint_Layers_Func
*
* @description:
@@ -890,17 +928,18 @@
TT_Set_SBit_Strike_Func set_sbit_strike;
TT_Load_Strike_Metrics_Func load_strike_metrics;
- TT_Load_Table_Func load_cpal;
- TT_Load_Table_Func load_colr;
- TT_Free_Table_Func free_cpal;
- TT_Free_Table_Func free_colr;
- TT_Set_Palette_Func set_palette;
- TT_Get_Colr_Layer_Func get_colr_layer;
- TT_Get_Color_Glyph_Paint_Func get_colr_glyph_paint;
- TT_Get_Paint_Layers_Func get_paint_layers;
- TT_Get_Colorline_Stops_Func get_colorline_stops;
- TT_Get_Paint_Func get_paint;
- TT_Blend_Colr_Func colr_blend;
+ TT_Load_Table_Func load_cpal;
+ TT_Load_Table_Func load_colr;
+ TT_Free_Table_Func free_cpal;
+ TT_Free_Table_Func free_colr;
+ TT_Set_Palette_Func set_palette;
+ TT_Get_Colr_Layer_Func get_colr_layer;
+ TT_Get_Color_Glyph_Paint_Func get_colr_glyph_paint;
+ TT_Get_Color_Glyph_ClipBox_Func get_color_glyph_clipbox;
+ TT_Get_Paint_Layers_Func get_paint_layers;
+ TT_Get_Colorline_Stops_Func get_colorline_stops;
+ TT_Get_Paint_Func get_paint;
+ TT_Blend_Colr_Func colr_blend;
TT_Get_Metrics_Func get_metrics;
@@ -951,6 +990,7 @@
set_palette_, \
get_colr_layer_, \
get_colr_glyph_paint_, \
+ get_color_glyph_clipbox, \
get_paint_layers_, \
get_colorline_stops_, \
get_paint_, \
@@ -995,6 +1035,7 @@
set_palette_, \
get_colr_layer_, \
get_colr_glyph_paint_, \
+ get_color_glyph_clipbox, \
get_paint_layers_, \
get_colorline_stops_, \
get_paint_, \
diff -Naur a/modules.cfg b/modules.cfg
--- a/modules.cfg 2021-05-19 07:43:30.000000000 +0200
+++ b/modules.cfg 2021-09-27 18:41:49.669995360 +0200
@@ -114,7 +114,7 @@
# TrueType GX/AAT table validation. Needs `ftgxval.c' below.
#
-# AUX_MODULES += gxvalid
+AUX_MODULES += gxvalid
# Support for streams compressed with gzip (files with suffix .gz).
#
@@ -133,7 +133,7 @@
# OpenType table validation. Needs `ftotval.c' below.
#
-# AUX_MODULES += otvalid
+AUX_MODULES += otvalid
# Auxiliary PostScript driver component to share common code.
#
diff -Naur a/src/base/ftobjs.c.orig b/src/base/ftobjs.c.orig
--- a/src/base/ftobjs.c.orig 1970-01-01 01:00:00.000000000 +0100
+++ b/src/base/ftobjs.c.orig 2021-09-27 18:42:19.096661893 +0200
@@ -0,0 +1,5728 @@
+/****************************************************************************
+ *
+ * ftobjs.c
+ *
+ * The FreeType private base classes (body).
+ *
+ * Copyright (C) 1996-2021 by
+ * David Turner, Robert Wilhelm, and Werner Lemberg.
+ *
+ * This file is part of the FreeType project, and may only be used,
+ * modified, and distributed under the terms of the FreeType project
+ * license, LICENSE.TXT. By continuing to use, modify, or distribute
+ * this file you indicate that you have read the license and
+ * understand and accept it fully.
+ *
+ */
+
+
+#include <freetype/ftlist.h>
+#include <freetype/ftoutln.h>
+#include <freetype/ftfntfmt.h>
+
+#include <freetype/internal/ftvalid.h>
+#include <freetype/internal/ftobjs.h>
+#include <freetype/internal/ftdebug.h>
+#include <freetype/internal/ftrfork.h>
+#include <freetype/internal/ftstream.h>
+#include <freetype/internal/sfnt.h> /* for SFNT_Load_Table_Func */
+#include <freetype/internal/psaux.h> /* for PS_Driver */
+
+#include <freetype/tttables.h>
+#include <freetype/tttags.h>
+#include <freetype/ttnameid.h>
+
+#include <freetype/internal/services/svprop.h>
+#include <freetype/internal/services/svsfnt.h>
+#include <freetype/internal/services/svpostnm.h>
+#include <freetype/internal/services/svgldict.h>
+#include <freetype/internal/services/svttcmap.h>
+#include <freetype/internal/services/svkern.h>
+#include <freetype/internal/services/svtteng.h>
+
+#include <freetype/ftdriver.h>
+
+#ifdef FT_CONFIG_OPTION_MAC_FONTS
+#include "ftbase.h"
+#endif
+
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+
+#include <freetype/ftbitmap.h>
+
+#if defined( _MSC_VER ) /* Visual C++ (and Intel C++) */
+ /* We disable the warning `conversion from XXX to YYY, */
+ /* possible loss of data' in order to compile cleanly with */
+ /* the maximum level of warnings: `md5.c' is non-FreeType */
+ /* code, and it gets used during development builds only. */
+#pragma warning( push )
+#pragma warning( disable : 4244 )
+#endif /* _MSC_VER */
+
+ /* It's easiest to include `md5.c' directly. However, since OpenSSL */
+ /* also provides the same functions, there might be conflicts if */
+ /* both FreeType and OpenSSL are built as static libraries. For */
+ /* this reason, we put the MD5 stuff into the `FT_' namespace. */
+#define MD5_u32plus FT_MD5_u32plus
+#define MD5_CTX FT_MD5_CTX
+#define MD5_Init FT_MD5_Init
+#define MD5_Update FT_MD5_Update
+#define MD5_Final FT_MD5_Final
+
+#undef HAVE_OPENSSL
+
+#include "md5.c"
+
+#if defined( _MSC_VER )
+#pragma warning( pop )
+#endif
+
+ /* This array must stay in sync with the @FT_Pixel_Mode enumeration */
+ /* (in file `ftimage.h`). */
+
+ static const char* const pixel_modes[] =
+ {
+ "none",
+ "monochrome bitmap",
+ "gray 8-bit bitmap",
+ "gray 2-bit bitmap",
+ "gray 4-bit bitmap",
+ "LCD 8-bit bitmap",
+ "vertical LCD 8-bit bitmap",
+ "BGRA 32-bit color image bitmap",
+ "SDF 8-bit bitmap"
+ };
+
+#endif /* FT_DEBUG_LEVEL_TRACE */
+
+
+#define GRID_FIT_METRICS
+
+
+ /* forward declaration */
+ static FT_Error
+ ft_open_face_internal( FT_Library library,
+ const FT_Open_Args* args,
+ FT_Long face_index,
+ FT_Face *aface,
+ FT_Bool test_mac_fonts );
+
+
+ FT_BASE_DEF( FT_Pointer )
+ ft_service_list_lookup( FT_ServiceDesc service_descriptors,
+ const char* service_id )
+ {
+ FT_Pointer result = NULL;
+ FT_ServiceDesc desc = service_descriptors;
+
+
+ if ( desc && service_id )
+ {
+ for ( ; desc->serv_id != NULL; desc++ )
+ {
+ if ( ft_strcmp( desc->serv_id, service_id ) == 0 )
+ {
+ result = (FT_Pointer)desc->serv_data;
+ break;
+ }
+ }
+ }
+
+ return result;
+ }
+
+
+ FT_BASE_DEF( void )
+ ft_validator_init( FT_Validator valid,
+ const FT_Byte* base,
+ const FT_Byte* limit,
+ FT_ValidationLevel level )
+ {
+ valid->base = base;
+ valid->limit = limit;
+ valid->level = level;
+ valid->error = FT_Err_Ok;
+ }
+
+
+ FT_BASE_DEF( FT_Int )
+ ft_validator_run( FT_Validator valid )
+ {
+ /* This function doesn't work! None should call it. */
+ FT_UNUSED( valid );
+
+ return -1;
+ }
+
+
+ FT_BASE_DEF( void )
+ ft_validator_error( FT_Validator valid,
+ FT_Error error )
+ {
+ /* since the cast below also disables the compiler's */
+ /* type check, we introduce a dummy variable, which */
+ /* will be optimized away */
+ volatile ft_jmp_buf* jump_buffer = &valid->jump_buffer;
+
+
+ valid->error = error;
+
+ /* throw away volatileness; use `jump_buffer' or the */
+ /* compiler may warn about an unused local variable */
+ ft_longjmp( *(ft_jmp_buf*) jump_buffer, 1 );
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** ****/
+ /**** S T R E A M ****/
+ /**** ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /* create a new input stream from an FT_Open_Args structure */
+ /* */
+ FT_BASE_DEF( FT_Error )
+ FT_Stream_New( FT_Library library,
+ const FT_Open_Args* args,
+ FT_Stream *astream )
+ {
+ FT_Error error;
+ FT_Memory memory;
+ FT_Stream stream = NULL;
+ FT_UInt mode;
+
+
+ *astream = NULL;
+
+ if ( !library )
+ return FT_THROW( Invalid_Library_Handle );
+
+ if ( !args )
+ return FT_THROW( Invalid_Argument );
+
+ memory = library->memory;
+ mode = args->flags &
+ ( FT_OPEN_MEMORY | FT_OPEN_STREAM | FT_OPEN_PATHNAME );
+
+ if ( mode == FT_OPEN_MEMORY )
+ {
+ /* create a memory-based stream */
+ if ( FT_NEW( stream ) )
+ goto Exit;
+
+ FT_Stream_OpenMemory( stream,
+ (const FT_Byte*)args->memory_base,
+ (FT_ULong)args->memory_size );
+ }
+
+#ifndef FT_CONFIG_OPTION_DISABLE_STREAM_SUPPORT
+
+ else if ( mode == FT_OPEN_PATHNAME )
+ {
+ /* create a normal system stream */
+ if ( FT_NEW( stream ) )
+ goto Exit;
+
+ error = FT_Stream_Open( stream, args->pathname );
+ if ( error )
+ FT_FREE( stream );
+ }
+ else if ( ( mode == FT_OPEN_STREAM ) && args->stream )
+ {
+ /* use an existing, user-provided stream */
+
+ /* in this case, we do not need to allocate a new stream object */
+ /* since the caller is responsible for closing it himself */
+ stream = args->stream;
+ error = FT_Err_Ok;
+ }
+
+#endif
+
+ else
+ {
+ error = FT_THROW( Invalid_Argument );
+ if ( ( args->flags & FT_OPEN_STREAM ) && args->stream )
+ FT_Stream_Close( args->stream );
+ }
+
+ if ( !error )
+ {
+ stream->memory = memory;
+ *astream = stream;
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ FT_BASE_DEF( void )
+ FT_Stream_Free( FT_Stream stream,
+ FT_Int external )
+ {
+ if ( stream )
+ {
+ FT_Memory memory = stream->memory;
+
+
+ FT_Stream_Close( stream );
+
+ if ( !external )
+ FT_FREE( stream );
+ }
+ }
+
+
+ /**************************************************************************
+ *
+ * The macro FT_COMPONENT is used in trace mode. It is an implicit
+ * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
+ * messages during execution.
+ */
+#undef FT_COMPONENT
+#define FT_COMPONENT objs
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** ****/
+ /**** FACE, SIZE & GLYPH SLOT OBJECTS ****/
+ /**** ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ static FT_Error
+ ft_glyphslot_init( FT_GlyphSlot slot )
+ {
+ FT_Driver driver = slot->face->driver;
+ FT_Driver_Class clazz = driver->clazz;
+ FT_Memory memory = driver->root.memory;
+ FT_Error error = FT_Err_Ok;
+ FT_Slot_Internal internal = NULL;
+
+
+ slot->library = driver->root.library;
+
+ if ( FT_NEW( internal ) )
+ goto Exit;
+
+ slot->internal = internal;
+
+ if ( FT_DRIVER_USES_OUTLINES( driver ) )
+ error = FT_GlyphLoader_New( memory, &internal->loader );
+
+ if ( !error && clazz->init_slot )
+ error = clazz->init_slot( slot );
+
+ Exit:
+ return error;
+ }
+
+
+ FT_BASE_DEF( void )
+ ft_glyphslot_free_bitmap( FT_GlyphSlot slot )
+ {
+ if ( slot->internal && ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) )
+ {
+ FT_Memory memory = FT_FACE_MEMORY( slot->face );
+
+
+ FT_FREE( slot->bitmap.buffer );
+ slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
+ }
+ else
+ {
+ /* assume that the bitmap buffer was stolen or not */
+ /* allocated from the heap */
+ slot->bitmap.buffer = NULL;
+ }
+ }
+
+
+ /* overflow-resistant presetting of bitmap position and dimensions; */
+ /* also check whether the size is too large for rendering */
+ FT_BASE_DEF( FT_Bool )
+ ft_glyphslot_preset_bitmap( FT_GlyphSlot slot,
+ FT_Render_Mode mode,
+ const FT_Vector* origin )
+ {
+ FT_Outline* outline = &slot->outline;
+ FT_Bitmap* bitmap = &slot->bitmap;
+
+ FT_Pixel_Mode pixel_mode;
+
+ FT_BBox cbox, pbox;
+ FT_Pos x_shift = 0;
+ FT_Pos y_shift = 0;
+ FT_Pos x_left, y_top;
+ FT_Pos width, height, pitch;
+
+
+ if ( slot->format != FT_GLYPH_FORMAT_OUTLINE )
+ return 1;
+
+ if ( origin )
+ {
+ x_shift = origin->x;
+ y_shift = origin->y;
+ }
+
+ /* compute the control box, and grid-fit it, */
+ /* taking into account the origin shift */
+ FT_Outline_Get_CBox( outline, &cbox );
+
+ /* rough estimate of pixel box */
+ pbox.xMin = ( cbox.xMin >> 6 ) + ( x_shift >> 6 );
+ pbox.yMin = ( cbox.yMin >> 6 ) + ( y_shift >> 6 );
+ pbox.xMax = ( cbox.xMax >> 6 ) + ( x_shift >> 6 );
+ pbox.yMax = ( cbox.yMax >> 6 ) + ( y_shift >> 6 );
+
+ /* tiny remainder box */
+ cbox.xMin = ( cbox.xMin & 63 ) + ( x_shift & 63 );
+ cbox.yMin = ( cbox.yMin & 63 ) + ( y_shift & 63 );
+ cbox.xMax = ( cbox.xMax & 63 ) + ( x_shift & 63 );
+ cbox.yMax = ( cbox.yMax & 63 ) + ( y_shift & 63 );
+
+ switch ( mode )
+ {
+ case FT_RENDER_MODE_MONO:
+ pixel_mode = FT_PIXEL_MODE_MONO;
+#if 1
+ /* x */
+
+ /* undocumented but confirmed: bbox values get rounded; */
+ /* we do asymmetric rounding so that the center of a pixel */
+ /* gets always included */
+
+ pbox.xMin += ( cbox.xMin + 31 ) >> 6;
+ pbox.xMax += ( cbox.xMax + 32 ) >> 6;
+
+ /* if the bbox collapsed, we add a pixel based on the total */
+ /* rounding remainder to cover most of the original cbox */
+
+ if ( pbox.xMin == pbox.xMax )
+ {
+ if ( ( ( cbox.xMin + 31 ) & 63 ) - 31 +
+ ( ( cbox.xMax + 32 ) & 63 ) - 32 < 0 )
+ pbox.xMin -= 1;
+ else
+ pbox.xMax += 1;
+ }
+
+ /* y */
+
+ pbox.yMin += ( cbox.yMin + 31 ) >> 6;
+ pbox.yMax += ( cbox.yMax + 32 ) >> 6;
+
+ if ( pbox.yMin == pbox.yMax )
+ {
+ if ( ( ( cbox.yMin + 31 ) & 63 ) - 31 +
+ ( ( cbox.yMax + 32 ) & 63 ) - 32 < 0 )
+ pbox.yMin -= 1;
+ else
+ pbox.yMax += 1;
+ }
+
+ break;
+#else
+ goto Adjust;
+#endif
+
+ case FT_RENDER_MODE_LCD:
+ pixel_mode = FT_PIXEL_MODE_LCD;
+ ft_lcd_padding( &cbox, slot, mode );
+ goto Adjust;
+
+ case FT_RENDER_MODE_LCD_V:
+ pixel_mode = FT_PIXEL_MODE_LCD_V;
+ ft_lcd_padding( &cbox, slot, mode );
+ goto Adjust;
+
+ case FT_RENDER_MODE_NORMAL:
+ case FT_RENDER_MODE_LIGHT:
+ default:
+ pixel_mode = FT_PIXEL_MODE_GRAY;
+ Adjust:
+ pbox.xMin += cbox.xMin >> 6;
+ pbox.yMin += cbox.yMin >> 6;
+ pbox.xMax += ( cbox.xMax + 63 ) >> 6;
+ pbox.yMax += ( cbox.yMax + 63 ) >> 6;
+ }
+
+ x_left = pbox.xMin;
+ y_top = pbox.yMax;
+
+ width = pbox.xMax - pbox.xMin;
+ height = pbox.yMax - pbox.yMin;
+
+ switch ( pixel_mode )
+ {
+ case FT_PIXEL_MODE_MONO:
+ pitch = ( ( width + 15 ) >> 4 ) << 1;
+ break;
+
+ case FT_PIXEL_MODE_LCD:
+ width *= 3;
+ pitch = FT_PAD_CEIL( width, 4 );
+ break;
+
+ case FT_PIXEL_MODE_LCD_V:
+ height *= 3;
+ /* fall through */
+
+ case FT_PIXEL_MODE_GRAY:
+ default:
+ pitch = width;
+ }
+
+ slot->bitmap_left = (FT_Int)x_left;
+ slot->bitmap_top = (FT_Int)y_top;
+
+ bitmap->pixel_mode = (unsigned char)pixel_mode;
+ bitmap->num_grays = 256;
+ bitmap->width = (unsigned int)width;
+ bitmap->rows = (unsigned int)height;
+ bitmap->pitch = pitch;
+
+ if ( pbox.xMin < -0x8000 || pbox.xMax > 0x7FFF ||
+ pbox.yMin < -0x8000 || pbox.yMax > 0x7FFF )
+ {
+ FT_TRACE3(( "ft_glyphslot_preset_bitmap: [%ld %ld %ld %ld]\n",
+ pbox.xMin, pbox.yMin, pbox.xMax, pbox.yMax ));
+ return 1;
+ }
+
+ return 0;
+ }
+
+
+ FT_BASE_DEF( void )
+ ft_glyphslot_set_bitmap( FT_GlyphSlot slot,
+ FT_Byte* buffer )
+ {
+ ft_glyphslot_free_bitmap( slot );
+
+ slot->bitmap.buffer = buffer;
+
+ FT_ASSERT( (slot->internal->flags & FT_GLYPH_OWN_BITMAP) == 0 );
+ }
+
+
+ FT_BASE_DEF( FT_Error )
+ ft_glyphslot_alloc_bitmap( FT_GlyphSlot slot,
+ FT_ULong size )
+ {
+ FT_Memory memory = FT_FACE_MEMORY( slot->face );
+ FT_Error error;
+
+
+ if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
+ FT_FREE( slot->bitmap.buffer );
+ else
+ slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
+
+ (void)FT_ALLOC( slot->bitmap.buffer, size );
+ return error;
+ }
+
+
+ static void
+ ft_glyphslot_clear( FT_GlyphSlot slot )
+ {
+ /* free bitmap if needed */
+ ft_glyphslot_free_bitmap( slot );
+
+ /* clear all public fields in the glyph slot */
+ slot->glyph_index = 0;
+
+ FT_ZERO( &slot->metrics );
+ FT_ZERO( &slot->outline );
+
+ slot->bitmap.width = 0;
+ slot->bitmap.rows = 0;
+ slot->bitmap.pitch = 0;
+ slot->bitmap.pixel_mode = 0;
+ /* `slot->bitmap.buffer' has been handled by ft_glyphslot_free_bitmap */
+
+ slot->bitmap_left = 0;
+ slot->bitmap_top = 0;
+ slot->num_subglyphs = 0;
+ slot->subglyphs = NULL;
+ slot->control_data = NULL;
+ slot->control_len = 0;
+ slot->other = NULL;
+ slot->format = FT_GLYPH_FORMAT_NONE;
+
+ slot->linearHoriAdvance = 0;
+ slot->linearVertAdvance = 0;
+ slot->advance.x = 0;
+ slot->advance.y = 0;
+ slot->lsb_delta = 0;
+ slot->rsb_delta = 0;
+ }
+
+
+ static void
+ ft_glyphslot_done( FT_GlyphSlot slot )
+ {
+ FT_Driver driver = slot->face->driver;
+ FT_Driver_Class clazz = driver->clazz;
+ FT_Memory memory = driver->root.memory;
+
+
+ if ( clazz->done_slot )
+ clazz->done_slot( slot );
+
+ /* free bitmap buffer if needed */
+ ft_glyphslot_free_bitmap( slot );
+
+ /* slot->internal might be NULL in out-of-memory situations */
+ if ( slot->internal )
+ {
+ /* free glyph loader */
+ if ( FT_DRIVER_USES_OUTLINES( driver ) )
+ {
+ FT_GlyphLoader_Done( slot->internal->loader );
+ slot->internal->loader = NULL;
+ }
+
+ FT_FREE( slot->internal );
+ }
+ }
+
+
+ /* documentation is in ftobjs.h */
+
+ FT_BASE_DEF( FT_Error )
+ FT_New_GlyphSlot( FT_Face face,
+ FT_GlyphSlot *aslot )
+ {
+ FT_Error error;
+ FT_Driver driver;
+ FT_Driver_Class clazz;
+ FT_Memory memory;
+ FT_GlyphSlot slot = NULL;
+
+
+ if ( !face )
+ return FT_THROW( Invalid_Face_Handle );
+
+ if ( !face->driver )
+ return FT_THROW( Invalid_Argument );
+
+ driver = face->driver;
+ clazz = driver->clazz;
+ memory = driver->root.memory;
+
+ FT_TRACE4(( "FT_New_GlyphSlot: Creating new slot object\n" ));
+ if ( !FT_ALLOC( slot, clazz->slot_object_size ) )
+ {
+ slot->face = face;
+
+ error = ft_glyphslot_init( slot );
+ if ( error )
+ {
+ ft_glyphslot_done( slot );
+ FT_FREE( slot );
+ goto Exit;
+ }
+
+ slot->next = face->glyph;
+ face->glyph = slot;
+
+ if ( aslot )
+ *aslot = slot;
+ }
+ else if ( aslot )
+ *aslot = NULL;
+
+
+ Exit:
+ FT_TRACE4(( "FT_New_GlyphSlot: Return 0x%x\n", error ));
+
+ return error;
+ }
+
+
+ /* documentation is in ftobjs.h */
+
+ FT_BASE_DEF( void )
+ FT_Done_GlyphSlot( FT_GlyphSlot slot )
+ {
+ if ( slot )
+ {
+ FT_Driver driver = slot->face->driver;
+ FT_Memory memory = driver->root.memory;
+ FT_GlyphSlot prev;
+ FT_GlyphSlot cur;
+
+
+ /* Remove slot from its parent face's list */
+ prev = NULL;
+ cur = slot->face->glyph;
+
+ while ( cur )
+ {
+ if ( cur == slot )
+ {
+ if ( !prev )
+ slot->face->glyph = cur->next;
+ else
+ prev->next = cur->next;
+
+ /* finalize client-specific data */
+ if ( slot->generic.finalizer )
+ slot->generic.finalizer( slot );
+
+ ft_glyphslot_done( slot );
+ FT_FREE( slot );
+ break;
+ }
+ prev = cur;
+ cur = cur->next;
+ }
+ }
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( void )
+ FT_Set_Transform( FT_Face face,
+ FT_Matrix* matrix,
+ FT_Vector* delta )
+ {
+ FT_Face_Internal internal;
+
+
+ if ( !face )
+ return;
+
+ internal = face->internal;
+
+ internal->transform_flags = 0;
+
+ if ( !matrix )
+ {
+ internal->transform_matrix.xx = 0x10000L;
+ internal->transform_matrix.xy = 0;
+ internal->transform_matrix.yx = 0;
+ internal->transform_matrix.yy = 0x10000L;
+
+ matrix = &internal->transform_matrix;
+ }
+ else
+ internal->transform_matrix = *matrix;
+
+ /* set transform_flags bit flag 0 if `matrix' isn't the identity */
+ if ( ( matrix->xy | matrix->yx ) ||
+ matrix->xx != 0x10000L ||
+ matrix->yy != 0x10000L )
+ internal->transform_flags |= 1;
+
+ if ( !delta )
+ {
+ internal->transform_delta.x = 0;
+ internal->transform_delta.y = 0;
+
+ delta = &internal->transform_delta;
+ }
+ else
+ internal->transform_delta = *delta;
+
+ /* set transform_flags bit flag 1 if `delta' isn't the null vector */
+ if ( delta->x | delta->y )
+ internal->transform_flags |= 2;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( void )
+ FT_Get_Transform( FT_Face face,
+ FT_Matrix* matrix,
+ FT_Vector* delta )
+ {
+ FT_Face_Internal internal;
+
+
+ if ( !face )
+ return;
+
+ internal = face->internal;
+
+ if ( matrix )
+ *matrix = internal->transform_matrix;
+
+ if ( delta )
+ *delta = internal->transform_delta;
+ }
+
+
+ static FT_Renderer
+ ft_lookup_glyph_renderer( FT_GlyphSlot slot );
+
+
+#ifdef GRID_FIT_METRICS
+ static void
+ ft_glyphslot_grid_fit_metrics( FT_GlyphSlot slot,
+ FT_Bool vertical )
+ {
+ FT_Glyph_Metrics* metrics = &slot->metrics;
+ FT_Pos right, bottom;
+
+
+ if ( vertical )
+ {
+ metrics->horiBearingX = FT_PIX_FLOOR( metrics->horiBearingX );
+ metrics->horiBearingY = FT_PIX_CEIL_LONG( metrics->horiBearingY );
+
+ right = FT_PIX_CEIL_LONG( ADD_LONG( metrics->vertBearingX,
+ metrics->width ) );
+ bottom = FT_PIX_CEIL_LONG( ADD_LONG( metrics->vertBearingY,
+ metrics->height ) );
+
+ metrics->vertBearingX = FT_PIX_FLOOR( metrics->vertBearingX );
+ metrics->vertBearingY = FT_PIX_FLOOR( metrics->vertBearingY );
+
+ metrics->width = SUB_LONG( right,
+ metrics->vertBearingX );
+ metrics->height = SUB_LONG( bottom,
+ metrics->vertBearingY );
+ }
+ else
+ {
+ metrics->vertBearingX = FT_PIX_FLOOR( metrics->vertBearingX );
+ metrics->vertBearingY = FT_PIX_FLOOR( metrics->vertBearingY );
+
+ right = FT_PIX_CEIL_LONG( ADD_LONG( metrics->horiBearingX,
+ metrics->width ) );
+ bottom = FT_PIX_FLOOR( SUB_LONG( metrics->horiBearingY,
+ metrics->height ) );
+
+ metrics->horiBearingX = FT_PIX_FLOOR( metrics->horiBearingX );
+ metrics->horiBearingY = FT_PIX_CEIL_LONG( metrics->horiBearingY );
+
+ metrics->width = SUB_LONG( right,
+ metrics->horiBearingX );
+ metrics->height = SUB_LONG( metrics->horiBearingY,
+ bottom );
+ }
+
+ metrics->horiAdvance = FT_PIX_ROUND_LONG( metrics->horiAdvance );
+ metrics->vertAdvance = FT_PIX_ROUND_LONG( metrics->vertAdvance );
+ }
+#endif /* GRID_FIT_METRICS */
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Load_Glyph( FT_Face face,
+ FT_UInt glyph_index,
+ FT_Int32 load_flags )
+ {
+ FT_Error error;
+ FT_Driver driver;
+ FT_GlyphSlot slot;
+ FT_Library library;
+ FT_Bool autohint = FALSE;
+ FT_Module hinter;
+ TT_Face ttface = (TT_Face)face;
+
+
+ if ( !face || !face->size || !face->glyph )
+ return FT_THROW( Invalid_Face_Handle );
+
+ /* The validity test for `glyph_index' is performed by the */
+ /* font drivers. */
+
+ slot = face->glyph;
+ ft_glyphslot_clear( slot );
+
+ driver = face->driver;
+ library = driver->root.library;
+ hinter = library->auto_hinter;
+
+ /* resolve load flags dependencies */
+
+ if ( load_flags & FT_LOAD_NO_RECURSE )
+ load_flags |= FT_LOAD_NO_SCALE |
+ FT_LOAD_IGNORE_TRANSFORM;
+
+ if ( load_flags & FT_LOAD_NO_SCALE )
+ {
+ load_flags |= FT_LOAD_NO_HINTING |
+ FT_LOAD_NO_BITMAP;
+
+ load_flags &= ~FT_LOAD_RENDER;
+ }
+
+ if ( load_flags & FT_LOAD_BITMAP_METRICS_ONLY )
+ load_flags &= ~FT_LOAD_RENDER;
+
+ /*
+ * Determine whether we need to auto-hint or not.
+ * The general rules are:
+ *
+ * - Do only auto-hinting if we have
+ *
+ * - a hinter module,
+ * - a scalable font,
+ * - not a tricky font, and
+ * - no transforms except simple slants and/or rotations by
+ * integer multiples of 90 degrees.
+ *
+ * - Then, auto-hint if FT_LOAD_FORCE_AUTOHINT is set or if we don't
+ * have a native font hinter.
+ *
+ * - Otherwise, auto-hint for LIGHT hinting mode or if there isn't
+ * any hinting bytecode in the TrueType/OpenType font.
+ *
+ * - Exception: The font is `tricky' and requires the native hinter to
+ * load properly.
+ */
+
+ if ( hinter &&
+ !( load_flags & FT_LOAD_NO_HINTING ) &&
+ !( load_flags & FT_LOAD_NO_AUTOHINT ) &&
+ FT_IS_SCALABLE( face ) &&
+ !FT_IS_TRICKY( face ) &&
+ ( ( load_flags & FT_LOAD_IGNORE_TRANSFORM ) ||
+ ( face->internal->transform_matrix.yx == 0 &&
+ face->internal->transform_matrix.xx != 0 ) ||
+ ( face->internal->transform_matrix.xx == 0 &&
+ face->internal->transform_matrix.yx != 0 ) ) )
+ {
+ if ( ( load_flags & FT_LOAD_FORCE_AUTOHINT ) ||
+ !FT_DRIVER_HAS_HINTER( driver ) )
+ autohint = TRUE;
+ else
+ {
+ FT_Render_Mode mode = FT_LOAD_TARGET_MODE( load_flags );
+ FT_Bool is_light_type1;
+
+
+ /* only the new Adobe engine (for both CFF and Type 1) is `light'; */
+ /* we use `strstr' to catch both `Type 1' and `CID Type 1' */
+ is_light_type1 =
+ ft_strstr( FT_Get_Font_Format( face ), "Type 1" ) != NULL &&
+ ((PS_Driver)driver)->hinting_engine == FT_HINTING_ADOBE;
+
+ /* the check for `num_locations' assures that we actually */
+ /* test for instructions in a TTF and not in a CFF-based OTF */
+ /* */
+ /* since `maxSizeOfInstructions' might be unreliable, we */
+ /* check the size of the `fpgm' and `prep' tables, too -- */
+ /* the assumption is that there don't exist real TTFs where */
+ /* both `fpgm' and `prep' tables are missing */
+ if ( ( mode == FT_RENDER_MODE_LIGHT &&
+ ( !FT_DRIVER_HINTS_LIGHTLY( driver ) &&
+ !is_light_type1 ) ) ||
+ ( FT_IS_SFNT( face ) &&
+ ttface->num_locations &&
+ ttface->max_profile.maxSizeOfInstructions == 0 &&
+ ttface->font_program_size == 0 &&
+ ttface->cvt_program_size == 0 ) )
+ autohint = TRUE;
+ }
+ }
+
+ if ( autohint )
+ {
+ FT_AutoHinter_Interface hinting;
+
+
+ /* try to load embedded bitmaps first if available */
+ /* */
+ /* XXX: This is really a temporary hack that should disappear */
+ /* promptly with FreeType 2.1! */
+ /* */
+ if ( FT_HAS_FIXED_SIZES( face ) &&
+ ( load_flags & FT_LOAD_NO_BITMAP ) == 0 )
+ {
+ error = driver->clazz->load_glyph( slot, face->size,
+ glyph_index,
+ load_flags | FT_LOAD_SBITS_ONLY );
+
+ if ( !error && slot->format == FT_GLYPH_FORMAT_BITMAP )
+ goto Load_Ok;
+ }
+
+ {
+ FT_Face_Internal internal = face->internal;
+ FT_Int transform_flags = internal->transform_flags;
+
+
+ /* since the auto-hinter calls FT_Load_Glyph by itself, */
+ /* make sure that glyphs aren't transformed */
+ internal->transform_flags = 0;
+
+ /* load auto-hinted outline */
+ hinting = (FT_AutoHinter_Interface)hinter->clazz->module_interface;
+
+ error = hinting->load_glyph( (FT_AutoHinter)hinter,
+ slot, face->size,
+ glyph_index, load_flags );
+
+ internal->transform_flags = transform_flags;
+ }
+ }
+ else
+ {
+ error = driver->clazz->load_glyph( slot,
+ face->size,
+ glyph_index,
+ load_flags );
+ if ( error )
+ goto Exit;
+
+ if ( slot->format == FT_GLYPH_FORMAT_OUTLINE )
+ {
+ /* check that the loaded outline is correct */
+ error = FT_Outline_Check( &slot->outline );
+ if ( error )
+ goto Exit;
+
+#ifdef GRID_FIT_METRICS
+ if ( !( load_flags & FT_LOAD_NO_HINTING ) )
+ ft_glyphslot_grid_fit_metrics(
+ slot,
+ FT_BOOL( load_flags & FT_LOAD_VERTICAL_LAYOUT ) );
+#endif
+ }
+ }
+
+ Load_Ok:
+ /* compute the advance */
+ if ( load_flags & FT_LOAD_VERTICAL_LAYOUT )
+ {
+ slot->advance.x = 0;
+ slot->advance.y = slot->metrics.vertAdvance;
+ }
+ else
+ {
+ slot->advance.x = slot->metrics.horiAdvance;
+ slot->advance.y = 0;
+ }
+
+ /* compute the linear advance in 16.16 pixels */
+ if ( ( load_flags & FT_LOAD_LINEAR_DESIGN ) == 0 &&
+ FT_IS_SCALABLE( face ) )
+ {
+ FT_Size_Metrics* metrics = &face->size->metrics;
+
+
+ /* it's tricky! */
+ slot->linearHoriAdvance = FT_MulDiv( slot->linearHoriAdvance,
+ metrics->x_scale, 64 );
+
+ slot->linearVertAdvance = FT_MulDiv( slot->linearVertAdvance,
+ metrics->y_scale, 64 );
+ }
+
+ if ( ( load_flags & FT_LOAD_IGNORE_TRANSFORM ) == 0 )
+ {
+ FT_Face_Internal internal = face->internal;
+
+
+ /* now, transform the glyph image if needed */
+ if ( internal->transform_flags )
+ {
+ /* get renderer */
+ FT_Renderer renderer = ft_lookup_glyph_renderer( slot );
+
+
+ if ( renderer )
+ error = renderer->clazz->transform_glyph(
+ renderer, slot,
+ &internal->transform_matrix,
+ &internal->transform_delta );
+ else if ( slot->format == FT_GLYPH_FORMAT_OUTLINE )
+ {
+ /* apply `standard' transformation if no renderer is available */
+ if ( internal->transform_flags & 1 )
+ FT_Outline_Transform( &slot->outline,
+ &internal->transform_matrix );
+
+ if ( internal->transform_flags & 2 )
+ FT_Outline_Translate( &slot->outline,
+ internal->transform_delta.x,
+ internal->transform_delta.y );
+ }
+
+ /* transform advance */
+ FT_Vector_Transform( &slot->advance, &internal->transform_matrix );
+ }
+ }
+
+ slot->glyph_index = glyph_index;
+ slot->internal->load_flags = load_flags;
+
+ /* do we need to render the image or preset the bitmap now? */
+ if ( !error &&
+ ( load_flags & FT_LOAD_NO_SCALE ) == 0 &&
+ slot->format != FT_GLYPH_FORMAT_BITMAP &&
+ slot->format != FT_GLYPH_FORMAT_COMPOSITE )
+ {
+ FT_Render_Mode mode = FT_LOAD_TARGET_MODE( load_flags );
+
+
+ if ( mode == FT_RENDER_MODE_NORMAL &&
+ load_flags & FT_LOAD_MONOCHROME )
+ mode = FT_RENDER_MODE_MONO;
+
+ if ( load_flags & FT_LOAD_RENDER )
+ error = FT_Render_Glyph( slot, mode );
+ else
+ ft_glyphslot_preset_bitmap( slot, mode, NULL );
+ }
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+ FT_TRACE5(( "FT_Load_Glyph: index %d, flags 0x%x\n",
+ glyph_index, load_flags ));
+ FT_TRACE5(( " bitmap %dx%d %s, %s (mode %d)\n",
+ slot->bitmap.width,
+ slot->bitmap.rows,
+ slot->outline.points ?
+ slot->bitmap.buffer ? "rendered"
+ : "preset"
+ :
+ slot->internal->flags & FT_GLYPH_OWN_BITMAP ? "owned"
+ : "unowned",
+ pixel_modes[slot->bitmap.pixel_mode],
+ slot->bitmap.pixel_mode ));
+ FT_TRACE5(( "\n" ));
+ FT_TRACE5(( " x advance: %f\n", slot->advance.x / 64.0 ));
+ FT_TRACE5(( " y advance: %f\n", slot->advance.y / 64.0 ));
+ FT_TRACE5(( " linear x advance: %f\n",
+ slot->linearHoriAdvance / 65536.0 ));
+ FT_TRACE5(( " linear y advance: %f\n",
+ slot->linearVertAdvance / 65536.0 ));
+
+ {
+ FT_Glyph_Metrics* metrics = &slot->metrics;
+
+
+ FT_TRACE5(( " metrics:\n" ));
+ FT_TRACE5(( " width: %f\n", metrics->width / 64.0 ));
+ FT_TRACE5(( " height: %f\n", metrics->height / 64.0 ));
+ FT_TRACE5(( "\n" ));
+ FT_TRACE5(( " horiBearingX: %f\n", metrics->horiBearingX / 64.0 ));
+ FT_TRACE5(( " horiBearingY: %f\n", metrics->horiBearingY / 64.0 ));
+ FT_TRACE5(( " horiAdvance: %f\n", metrics->horiAdvance / 64.0 ));
+ FT_TRACE5(( "\n" ));
+ FT_TRACE5(( " vertBearingX: %f\n", metrics->vertBearingX / 64.0 ));
+ FT_TRACE5(( " vertBearingY: %f\n", metrics->vertBearingY / 64.0 ));
+ FT_TRACE5(( " vertAdvance: %f\n", metrics->vertAdvance / 64.0 ));
+ }
+#endif
+
+ Exit:
+ return error;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Load_Char( FT_Face face,
+ FT_ULong char_code,
+ FT_Int32 load_flags )
+ {
+ FT_UInt glyph_index;
+
+
+ if ( !face )
+ return FT_THROW( Invalid_Face_Handle );
+
+ glyph_index = (FT_UInt)char_code;
+ if ( face->charmap )
+ glyph_index = FT_Get_Char_Index( face, char_code );
+
+ return FT_Load_Glyph( face, glyph_index, load_flags );
+ }
+
+
+ /* destructor for sizes list */
+ static void
+ destroy_size( FT_Memory memory,
+ FT_Size size,
+ FT_Driver driver )
+ {
+ /* finalize client-specific data */
+ if ( size->generic.finalizer )
+ size->generic.finalizer( size );
+
+ /* finalize format-specific stuff */
+ if ( driver->clazz->done_size )
+ driver->clazz->done_size( size );
+
+ FT_FREE( size->internal );
+ FT_FREE( size );
+ }
+
+
+ static void
+ ft_cmap_done_internal( FT_CMap cmap );
+
+
+ static void
+ destroy_charmaps( FT_Face face,
+ FT_Memory memory )
+ {
+ FT_Int n;
+
+
+ if ( !face )
+ return;
+
+ for ( n = 0; n < face->num_charmaps; n++ )
+ {
+ FT_CMap cmap = FT_CMAP( face->charmaps[n] );
+
+
+ ft_cmap_done_internal( cmap );
+
+ face->charmaps[n] = NULL;
+ }
+
+ FT_FREE( face->charmaps );
+ face->num_charmaps = 0;
+ }
+
+
+ /* destructor for faces list */
+ static void
+ destroy_face( FT_Memory memory,
+ FT_Face face,
+ FT_Driver driver )
+ {
+ FT_Driver_Class clazz = driver->clazz;
+
+
+ /* discard auto-hinting data */
+ if ( face->autohint.finalizer )
+ face->autohint.finalizer( face->autohint.data );
+
+ /* Discard glyph slots for this face. */
+ /* Beware! FT_Done_GlyphSlot() changes the field `face->glyph' */
+ while ( face->glyph )
+ FT_Done_GlyphSlot( face->glyph );
+
+ /* discard all sizes for this face */
+ FT_List_Finalize( &face->sizes_list,
+ (FT_List_Destructor)destroy_size,
+ memory,
+ driver );
+ face->size = NULL;
+
+ /* now discard client data */
+ if ( face->generic.finalizer )
+ face->generic.finalizer( face );
+
+ /* discard charmaps */
+ destroy_charmaps( face, memory );
+
+ /* finalize format-specific stuff */
+ if ( clazz->done_face )
+ clazz->done_face( face );
+
+ /* close the stream for this face if needed */
+ FT_Stream_Free(
+ face->stream,
+ ( face->face_flags & FT_FACE_FLAG_EXTERNAL_STREAM ) != 0 );
+
+ face->stream = NULL;
+
+ /* get rid of it */
+ if ( face->internal )
+ {
+ FT_FREE( face->internal );
+ }
+ FT_FREE( face );
+ }
+
+
+ static void
+ Destroy_Driver( FT_Driver driver )
+ {
+ FT_List_Finalize( &driver->faces_list,
+ (FT_List_Destructor)destroy_face,
+ driver->root.memory,
+ driver );
+ }
+
+
+ /**************************************************************************
+ *
+ * @Function:
+ * find_unicode_charmap
+ *
+ * @Description:
+ * This function finds a Unicode charmap, if there is one.
+ * And if there is more than one, it tries to favour the more
+ * extensive one, i.e., one that supports UCS-4 against those which
+ * are limited to the BMP (said UCS-2 encoding.)
+ *
+ * This function is called from open_face() (just below), and also
+ * from FT_Select_Charmap( ..., FT_ENCODING_UNICODE ).
+ */
+ static FT_Error
+ find_unicode_charmap( FT_Face face )
+ {
+ FT_CharMap* first;
+ FT_CharMap* cur;
+
+
+ /* caller should have already checked that `face' is valid */
+ FT_ASSERT( face );
+
+ first = face->charmaps;
+
+ if ( !first )
+ return FT_THROW( Invalid_CharMap_Handle );
+
+ /*
+ * The original TrueType specification(s) only specified charmap
+ * formats that are capable of mapping 8 or 16 bit character codes to
+ * glyph indices.
+ *
+ * However, recent updates to the Apple and OpenType specifications
+ * introduced new formats that are capable of mapping 32-bit character
+ * codes as well. And these are already used on some fonts, mainly to
+ * map non-BMP Asian ideographs as defined in Unicode.
+ *
+ * For compatibility purposes, these fonts generally come with
+ * *several* Unicode charmaps:
+ *
+ * - One of them in the "old" 16-bit format, that cannot access
+ * all glyphs in the font.
+ *
+ * - Another one in the "new" 32-bit format, that can access all
+ * the glyphs.
+ *
+ * This function has been written to always favor a 32-bit charmap
+ * when found. Otherwise, a 16-bit one is returned when found.
+ */
+
+ /* Since the `interesting' table, with IDs (3,10), is normally the */
+ /* last one, we loop backwards. This loses with type1 fonts with */
+ /* non-BMP characters (<.0001%), this wins with .ttf with non-BMP */
+ /* chars (.01% ?), and this is the same about 99.99% of the time! */
+
+ cur = first + face->num_charmaps; /* points after the last one */
+
+ for ( ; --cur >= first; )
+ {
+ if ( cur[0]->encoding == FT_ENCODING_UNICODE )
+ {
+ /* XXX If some new encodings to represent UCS-4 are added, */
+ /* they should be added here. */
+ if ( ( cur[0]->platform_id == TT_PLATFORM_MICROSOFT &&
+ cur[0]->encoding_id == TT_MS_ID_UCS_4 ) ||
+ ( cur[0]->platform_id == TT_PLATFORM_APPLE_UNICODE &&
+ cur[0]->encoding_id == TT_APPLE_ID_UNICODE_32 ) )
+ {
+ face->charmap = cur[0];
+ return FT_Err_Ok;
+ }
+ }
+ }
+
+ /* We do not have any UCS-4 charmap. */
+ /* Do the loop again and search for UCS-2 charmaps. */
+ cur = first + face->num_charmaps;
+
+ for ( ; --cur >= first; )
+ {
+ if ( cur[0]->encoding == FT_ENCODING_UNICODE )
+ {
+ face->charmap = cur[0];
+ return FT_Err_Ok;
+ }
+ }
+
+ return FT_THROW( Invalid_CharMap_Handle );
+ }
+
+
+ /**************************************************************************
+ *
+ * @Function:
+ * find_variant_selector_charmap
+ *
+ * @Description:
+ * This function finds the variant selector charmap, if there is one.
+ * There can only be one (platform=0, specific=5, format=14).
+ */
+ static FT_CharMap
+ find_variant_selector_charmap( FT_Face face )
+ {
+ FT_CharMap* first;
+ FT_CharMap* end;
+ FT_CharMap* cur;
+
+
+ /* caller should have already checked that `face' is valid */
+ FT_ASSERT( face );
+
+ first = face->charmaps;
+
+ if ( !first )
+ return NULL;
+
+ end = first + face->num_charmaps; /* points after the last one */
+
+ for ( cur = first; cur < end; cur++ )
+ {
+ if ( cur[0]->platform_id == TT_PLATFORM_APPLE_UNICODE &&
+ cur[0]->encoding_id == TT_APPLE_ID_VARIANT_SELECTOR &&
+ FT_Get_CMap_Format( cur[0] ) == 14 )
+ return cur[0];
+ }
+
+ return NULL;
+ }
+
+
+ /**************************************************************************
+ *
+ * @Function:
+ * open_face
+ *
+ * @Description:
+ * This function does some work for FT_Open_Face().
+ */
+ static FT_Error
+ open_face( FT_Driver driver,
+ FT_Stream *astream,
+ FT_Bool external_stream,
+ FT_Long face_index,
+ FT_Int num_params,
+ FT_Parameter* params,
+ FT_Face *aface )
+ {
+ FT_Memory memory;
+ FT_Driver_Class clazz;
+ FT_Face face = NULL;
+ FT_Face_Internal internal = NULL;
+
+ FT_Error error, error2;
+
+
+ clazz = driver->clazz;
+ memory = driver->root.memory;
+
+ /* allocate the face object and perform basic initialization */
+ if ( FT_ALLOC( face, clazz->face_object_size ) )
+ goto Fail;
+
+ face->driver = driver;
+ face->memory = memory;
+ face->stream = *astream;
+
+ /* set the FT_FACE_FLAG_EXTERNAL_STREAM bit for FT_Done_Face */
+ if ( external_stream )
+ face->face_flags |= FT_FACE_FLAG_EXTERNAL_STREAM;
+
+ if ( FT_NEW( internal ) )
+ goto Fail;
+
+ face->internal = internal;
+
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+ {
+ int i;
+
+
+ face->internal->incremental_interface = NULL;
+ for ( i = 0; i < num_params && !face->internal->incremental_interface;
+ i++ )
+ if ( params[i].tag == FT_PARAM_TAG_INCREMENTAL )
+ face->internal->incremental_interface =
+ (FT_Incremental_Interface)params[i].data;
+ }
+#endif
+
+ face->internal->random_seed = -1;
+
+ if ( clazz->init_face )
+ error = clazz->init_face( *astream,
+ face,
+ (FT_Int)face_index,
+ num_params,
+ params );
+ *astream = face->stream; /* Stream may have been changed. */
+ if ( error )
+ goto Fail;
+
+ /* select Unicode charmap by default */
+ error2 = find_unicode_charmap( face );
+
+ /* if no Unicode charmap can be found, FT_Err_Invalid_CharMap_Handle */
+ /* is returned. */
+
+ /* no error should happen, but we want to play safe */
+ if ( error2 && FT_ERR_NEQ( error2, Invalid_CharMap_Handle ) )
+ {
+ error = error2;
+ goto Fail;
+ }
+
+ *aface = face;
+
+ Fail:
+ if ( error )
+ {
+ destroy_charmaps( face, memory );
+ if ( clazz->done_face )
+ clazz->done_face( face );
+ FT_FREE( internal );
+ FT_FREE( face );
+ *aface = NULL;
+ }
+
+ return error;
+ }
+
+
+ /* there's a Mac-specific extended implementation of FT_New_Face() */
+ /* in src/base/ftmac.c */
+
+#ifndef FT_MACINTOSH
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_New_Face( FT_Library library,
+ const char* pathname,
+ FT_Long face_index,
+ FT_Face *aface )
+ {
+ FT_Open_Args args;
+
+
+ /* test for valid `library' and `aface' delayed to `FT_Open_Face' */
+ if ( !pathname )
+ return FT_THROW( Invalid_Argument );
+
+ args.flags = FT_OPEN_PATHNAME;
+ args.pathname = (char*)pathname;
+ args.stream = NULL;
+
+ return ft_open_face_internal( library, &args, face_index, aface, 1 );
+ }
+
+#endif
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_New_Memory_Face( FT_Library library,
+ const FT_Byte* file_base,
+ FT_Long file_size,
+ FT_Long face_index,
+ FT_Face *aface )
+ {
+ FT_Open_Args args;
+
+
+ /* test for valid `library' and `face' delayed to `FT_Open_Face' */
+ if ( !file_base )
+ return FT_THROW( Invalid_Argument );
+
+ args.flags = FT_OPEN_MEMORY;
+ args.memory_base = file_base;
+ args.memory_size = file_size;
+ args.stream = NULL;
+
+ return ft_open_face_internal( library, &args, face_index, aface, 1 );
+ }
+
+
+#ifdef FT_CONFIG_OPTION_MAC_FONTS
+
+ /* The behavior here is very similar to that in base/ftmac.c, but it */
+ /* is designed to work on non-mac systems, so no mac specific calls. */
+ /* */
+ /* We look at the file and determine if it is a mac dfont file or a mac */
+ /* resource file, or a macbinary file containing a mac resource file. */
+ /* */
+ /* Unlike ftmac I'm not going to look at a `FOND'. I don't really see */
+ /* the point, especially since there may be multiple `FOND' resources. */
+ /* Instead I'll just look for `sfnt' and `POST' resources, ordered as */
+ /* they occur in the file. */
+ /* */
+ /* Note that multiple `POST' resources do not mean multiple postscript */
+ /* fonts; they all get jammed together to make what is essentially a */
+ /* pfb file. */
+ /* */
+ /* We aren't interested in `NFNT' or `FONT' bitmap resources. */
+ /* */
+ /* As soon as we get an `sfnt' load it into memory and pass it off to */
+ /* FT_Open_Face. */
+ /* */
+ /* If we have a (set of) `POST' resources, massage them into a (memory) */
+ /* pfb file and pass that to FT_Open_Face. (As with ftmac.c I'm not */
+ /* going to try to save the kerning info. After all that lives in the */
+ /* `FOND' which isn't in the file containing the `POST' resources so */
+ /* we don't really have access to it. */
+
+
+ /* Finalizer for a memory stream; gets called by FT_Done_Face(). */
+ /* It frees the memory it uses. */
+ /* From `ftmac.c'. */
+ static void
+ memory_stream_close( FT_Stream stream )
+ {
+ FT_Memory memory = stream->memory;
+
+
+ FT_FREE( stream->base );
+
+ stream->size = 0;
+ stream->base = NULL;
+ stream->close = NULL;
+ }
+
+
+ /* Create a new memory stream from a buffer and a size. */
+ /* From `ftmac.c'. */
+ static FT_Error
+ new_memory_stream( FT_Library library,
+ FT_Byte* base,
+ FT_ULong size,
+ FT_Stream_CloseFunc close,
+ FT_Stream *astream )
+ {
+ FT_Error error;
+ FT_Memory memory;
+ FT_Stream stream = NULL;
+
+
+ if ( !library )
+ return FT_THROW( Invalid_Library_Handle );
+
+ if ( !base )
+ return FT_THROW( Invalid_Argument );
+
+ *astream = NULL;
+ memory = library->memory;
+ if ( FT_NEW( stream ) )
+ goto Exit;
+
+ FT_Stream_OpenMemory( stream, base, size );
+
+ stream->close = close;
+
+ *astream = stream;
+
+ Exit:
+ return error;
+ }
+
+
+ /* Create a new FT_Face given a buffer and a driver name. */
+ /* From `ftmac.c'. */
+ FT_LOCAL_DEF( FT_Error )
+ open_face_from_buffer( FT_Library library,
+ FT_Byte* base,
+ FT_ULong size,
+ FT_Long face_index,
+ const char* driver_name,
+ FT_Face *aface )
+ {
+ FT_Open_Args args;
+ FT_Error error;
+ FT_Stream stream = NULL;
+ FT_Memory memory = library->memory;
+
+
+ error = new_memory_stream( library,
+ base,
+ size,
+ memory_stream_close,
+ &stream );
+ if ( error )
+ {
+ FT_FREE( base );
+ return error;
+ }
+
+ args.flags = FT_OPEN_STREAM;
+ args.stream = stream;
+ if ( driver_name )
+ {
+ args.flags = args.flags | FT_OPEN_DRIVER;
+ args.driver = FT_Get_Module( library, driver_name );
+ }
+
+#ifdef FT_MACINTOSH
+ /* At this point, the face index has served its purpose; */
+ /* whoever calls this function has already used it to */
+ /* locate the correct font data. We should not propagate */
+ /* this index to FT_Open_Face() (unless it is negative). */
+
+ if ( face_index > 0 )
+ face_index &= 0x7FFF0000L; /* retain GX data */
+#endif
+
+ error = ft_open_face_internal( library, &args, face_index, aface, 0 );
+
+ if ( !error )
+ (*aface)->face_flags &= ~FT_FACE_FLAG_EXTERNAL_STREAM;
+ else
+#ifdef FT_MACINTOSH
+ FT_Stream_Free( stream, 0 );
+#else
+ {
+ FT_Stream_Close( stream );
+ FT_FREE( stream );
+ }
+#endif
+
+ return error;
+ }
+
+
+ /* Look up `TYP1' or `CID ' table from sfnt table directory. */
+ /* `offset' and `length' must exclude the binary header in tables. */
+
+ /* Type 1 and CID-keyed font drivers should recognize sfnt-wrapped */
+ /* format too. Here, since we can't expect that the TrueType font */
+ /* driver is loaded unconditionally, we must parse the font by */
+ /* ourselves. We are only interested in the name of the table and */
+ /* the offset. */
+
+ static FT_Error
+ ft_lookup_PS_in_sfnt_stream( FT_Stream stream,
+ FT_Long face_index,
+ FT_ULong* offset,
+ FT_ULong* length,
+ FT_Bool* is_sfnt_cid )
+ {
+ FT_Error error;
+ FT_UShort numTables;
+ FT_Long pstable_index;
+ FT_ULong tag;
+ int i;
+
+
+ *offset = 0;
+ *length = 0;
+ *is_sfnt_cid = FALSE;
+
+ /* TODO: support for sfnt-wrapped PS/CID in TTC format */
+
+ /* version check for 'typ1' (should be ignored?) */
+ if ( FT_READ_ULONG( tag ) )
+ return error;
+ if ( tag != TTAG_typ1 )
+ return FT_THROW( Unknown_File_Format );
+
+ if ( FT_READ_USHORT( numTables ) )
+ return error;
+ if ( FT_STREAM_SKIP( 2 * 3 ) ) /* skip binary search header */
+ return error;
+
+ pstable_index = -1;
+ *is_sfnt_cid = FALSE;
+
+ for ( i = 0; i < numTables; i++ )
+ {
+ if ( FT_READ_ULONG( tag ) || FT_STREAM_SKIP( 4 ) ||
+ FT_READ_ULONG( *offset ) || FT_READ_ULONG( *length ) )
+ return error;
+
+ if ( tag == TTAG_CID )
+ {
+ pstable_index++;
+ *offset += 22;
+ *length -= 22;
+ *is_sfnt_cid = TRUE;
+ if ( face_index < 0 )
+ return FT_Err_Ok;
+ }
+ else if ( tag == TTAG_TYP1 )
+ {
+ pstable_index++;
+ *offset += 24;
+ *length -= 24;
+ *is_sfnt_cid = FALSE;
+ if ( face_index < 0 )
+ return FT_Err_Ok;
+ }
+ if ( face_index >= 0 && pstable_index == face_index )
+ return FT_Err_Ok;
+ }
+
+ return FT_THROW( Table_Missing );
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ open_face_PS_from_sfnt_stream( FT_Library library,
+ FT_Stream stream,
+ FT_Long face_index,
+ FT_Int num_params,
+ FT_Parameter *params,
+ FT_Face *aface )
+ {
+ FT_Error error;
+ FT_Memory memory = library->memory;
+ FT_ULong offset, length;
+ FT_ULong pos;
+ FT_Bool is_sfnt_cid;
+ FT_Byte* sfnt_ps = NULL;
+
+ FT_UNUSED( num_params );
+ FT_UNUSED( params );
+
+
+ /* ignore GX stuff */
+ if ( face_index > 0 )
+ face_index &= 0xFFFFL;
+
+ pos = FT_STREAM_POS();
+
+ error = ft_lookup_PS_in_sfnt_stream( stream,
+ face_index,
+ &offset,
+ &length,
+ &is_sfnt_cid );
+ if ( error )
+ goto Exit;
+
+ if ( offset > stream->size )
+ {
+ FT_TRACE2(( "open_face_PS_from_sfnt_stream: invalid table offset\n" ));
+ error = FT_THROW( Invalid_Table );
+ goto Exit;
+ }
+ else if ( length > stream->size - offset )
+ {
+ FT_TRACE2(( "open_face_PS_from_sfnt_stream: invalid table length\n" ));
+ error = FT_THROW( Invalid_Table );
+ goto Exit;
+ }
+
+ error = FT_Stream_Seek( stream, pos + offset );
+ if ( error )
+ goto Exit;
+
+ if ( FT_QALLOC( sfnt_ps, (FT_Long)length ) )
+ goto Exit;
+
+ error = FT_Stream_Read( stream, (FT_Byte *)sfnt_ps, length );
+ if ( error )
+ {
+ FT_FREE( sfnt_ps );
+ goto Exit;
+ }
+
+ error = open_face_from_buffer( library,
+ sfnt_ps,
+ length,
+ FT_MIN( face_index, 0 ),
+ is_sfnt_cid ? "cid" : "type1",
+ aface );
+ Exit:
+ {
+ FT_Error error1;
+
+
+ if ( FT_ERR_EQ( error, Unknown_File_Format ) )
+ {
+ error1 = FT_Stream_Seek( stream, pos );
+ if ( error1 )
+ return error1;
+ }
+
+ return error;
+ }
+ }
+
+
+#ifndef FT_MACINTOSH
+
+ /* The resource header says we've got resource_cnt `POST' (type1) */
+ /* resources in this file. They all need to be coalesced into */
+ /* one lump which gets passed on to the type1 driver. */
+ /* Here can be only one PostScript font in a file so face_index */
+ /* must be 0 (or -1). */
+ /* */
+ static FT_Error
+ Mac_Read_POST_Resource( FT_Library library,
+ FT_Stream stream,
+ FT_Long *offsets,
+ FT_Long resource_cnt,
+ FT_Long face_index,
+ FT_Face *aface )
+ {
+ FT_Error error = FT_ERR( Cannot_Open_Resource );
+ FT_Memory memory = library->memory;
+
+ FT_Byte* pfb_data = NULL;
+ int i, type, flags;
+ FT_ULong len;
+ FT_ULong pfb_len, pfb_pos, pfb_lenpos;
+ FT_ULong rlen, temp;
+
+
+ if ( face_index == -1 )
+ face_index = 0;
+ if ( face_index != 0 )
+ return error;
+
+ /* Find the length of all the POST resources, concatenated. Assume */
+ /* worst case (each resource in its own section). */
+ pfb_len = 0;
+ for ( i = 0; i < resource_cnt; i++ )
+ {
+ error = FT_Stream_Seek( stream, (FT_ULong)offsets[i] );
+ if ( error )
+ goto Exit;
+ if ( FT_READ_ULONG( temp ) ) /* actually LONG */
+ goto Exit;
+
+ /* FT2 allocator takes signed long buffer length,
+ * too large value causing overflow should be checked
+ */
+ FT_TRACE4(( " POST fragment #%d: length=0x%08lx"
+ " total pfb_len=0x%08lx\n",
+ i, temp, pfb_len + temp + 6 ));
+
+ if ( FT_MAC_RFORK_MAX_LEN < temp ||
+ FT_MAC_RFORK_MAX_LEN - temp < pfb_len + 6 )
+ {
+ FT_TRACE2(( " MacOS resource length cannot exceed"
+ " 0x%08lx\n",
+ FT_MAC_RFORK_MAX_LEN ));
+
+ error = FT_THROW( Invalid_Offset );
+ goto Exit;
+ }
+
+ pfb_len += temp + 6;
+ }
+
+ FT_TRACE2(( " total buffer size to concatenate"
+ " %ld POST fragments: 0x%08lx\n",
+ resource_cnt, pfb_len + 2 ));
+
+ if ( pfb_len + 2 < 6 )
+ {
+ FT_TRACE2(( " too long fragment length makes"
+ " pfb_len confused: pfb_len=0x%08lx\n",
+ pfb_len ));
+
+ error = FT_THROW( Array_Too_Large );
+ goto Exit;
+ }
+
+ if ( FT_QALLOC( pfb_data, (FT_Long)pfb_len + 2 ) )
+ goto Exit;
+
+ pfb_data[0] = 0x80;
+ pfb_data[1] = 1; /* Ascii section */
+ pfb_data[2] = 0; /* 4-byte length, fill in later */
+ pfb_data[3] = 0;
+ pfb_data[4] = 0;
+ pfb_data[5] = 0;
+ pfb_pos = 6;
+ pfb_lenpos = 2;
+
+ len = 0;
+ type = 1;
+
+ for ( i = 0; i < resource_cnt; i++ )
+ {
+ error = FT_Stream_Seek( stream, (FT_ULong)offsets[i] );
+ if ( error )
+ goto Exit2;
+ if ( FT_READ_ULONG( rlen ) )
+ goto Exit2;
+
+ /* FT2 allocator takes signed long buffer length,
+ * too large fragment length causing overflow should be checked
+ */
+ if ( 0x7FFFFFFFUL < rlen )
+ {
+ error = FT_THROW( Invalid_Offset );
+ goto Exit2;
+ }
+
+ if ( FT_READ_USHORT( flags ) )
+ goto Exit2;
+
+ FT_TRACE3(( "POST fragment[%d]:"
+ " offsets=0x%08lx, rlen=0x%08lx, flags=0x%04x\n",
+ i, offsets[i], rlen, flags ));
+
+ error = FT_ERR( Array_Too_Large );
+
+ /* postpone the check of `rlen longer than buffer' */
+ /* until `FT_Stream_Read' */
+
+ if ( ( flags >> 8 ) == 0 ) /* Comment, should not be loaded */
+ {
+ FT_TRACE3(( " Skip POST fragment #%d because it is a comment\n",
+ i ));
+ continue;
+ }
+
+ /* the flags are part of the resource, so rlen >= 2, */
+ /* but some fonts declare rlen = 0 for empty fragment */
+ if ( rlen > 2 )
+ rlen -= 2;
+ else
+ rlen = 0;
+
+ if ( ( flags >> 8 ) == type )
+ len += rlen;
+ else
+ {
+ FT_TRACE3(( " Write POST fragment #%d header (4-byte) to buffer"
+ " %p + 0x%08lx\n",
+ i, (void*)pfb_data, pfb_lenpos ));
+
+ if ( pfb_lenpos + 3 > pfb_len + 2 )
+ goto Exit2;
+
+ pfb_data[pfb_lenpos ] = (FT_Byte)( len );
+ pfb_data[pfb_lenpos + 1] = (FT_Byte)( len >> 8 );
+ pfb_data[pfb_lenpos + 2] = (FT_Byte)( len >> 16 );
+ pfb_data[pfb_lenpos + 3] = (FT_Byte)( len >> 24 );
+
+ if ( ( flags >> 8 ) == 5 ) /* End of font mark */
+ break;
+
+ FT_TRACE3(( " Write POST fragment #%d header (6-byte) to buffer"
+ " %p + 0x%08lx\n",
+ i, (void*)pfb_data, pfb_pos ));
+
+ if ( pfb_pos + 6 > pfb_len + 2 )
+ goto Exit2;
+
+ pfb_data[pfb_pos++] = 0x80;
+
+ type = flags >> 8;
+ len = rlen;
+
+ pfb_data[pfb_pos++] = (FT_Byte)type;
+ pfb_lenpos = pfb_pos;
+ pfb_data[pfb_pos++] = 0; /* 4-byte length, fill in later */
+ pfb_data[pfb_pos++] = 0;
+ pfb_data[pfb_pos++] = 0;
+ pfb_data[pfb_pos++] = 0;
+ }
+
+ if ( pfb_pos > pfb_len || pfb_pos + rlen > pfb_len )
+ goto Exit2;
+
+ FT_TRACE3(( " Load POST fragment #%d (%ld byte) to buffer"
+ " %p + 0x%08lx\n",
+ i, rlen, (void*)pfb_data, pfb_pos ));
+
+ error = FT_Stream_Read( stream, (FT_Byte *)pfb_data + pfb_pos, rlen );
+ if ( error )
+ goto Exit2;
+
+ pfb_pos += rlen;
+ }
+
+ error = FT_ERR( Array_Too_Large );
+
+ if ( pfb_pos + 2 > pfb_len + 2 )
+ goto Exit2;
+ pfb_data[pfb_pos++] = 0x80;
+ pfb_data[pfb_pos++] = 3;
+
+ if ( pfb_lenpos + 3 > pfb_len + 2 )
+ goto Exit2;
+ pfb_data[pfb_lenpos ] = (FT_Byte)( len );
+ pfb_data[pfb_lenpos + 1] = (FT_Byte)( len >> 8 );
+ pfb_data[pfb_lenpos + 2] = (FT_Byte)( len >> 16 );
+ pfb_data[pfb_lenpos + 3] = (FT_Byte)( len >> 24 );
+
+ return open_face_from_buffer( library,
+ pfb_data,
+ pfb_pos,
+ face_index,
+ "type1",
+ aface );
+
+ Exit2:
+ if ( FT_ERR_EQ( error, Array_Too_Large ) )
+ FT_TRACE2(( " Abort due to too-short buffer to store"
+ " all POST fragments\n" ));
+ else if ( FT_ERR_EQ( error, Invalid_Offset ) )
+ FT_TRACE2(( " Abort due to invalid offset in a POST fragment\n" ));
+
+ if ( error )
+ error = FT_ERR( Cannot_Open_Resource );
+ FT_FREE( pfb_data );
+
+ Exit:
+ return error;
+ }
+
+
+ /* The resource header says we've got resource_cnt `sfnt' */
+ /* (TrueType/OpenType) resources in this file. Look through */
+ /* them for the one indicated by face_index, load it into mem, */
+ /* pass it on to the truetype driver, and return it. */
+ /* */
+ static FT_Error
+ Mac_Read_sfnt_Resource( FT_Library library,
+ FT_Stream stream,
+ FT_Long *offsets,
+ FT_Long resource_cnt,
+ FT_Long face_index,
+ FT_Face *aface )
+ {
+ FT_Memory memory = library->memory;
+ FT_Byte* sfnt_data = NULL;
+ FT_Error error;
+ FT_ULong flag_offset;
+ FT_Long rlen;
+ int is_cff;
+ FT_Long face_index_in_resource = 0;
+
+
+ if ( face_index < 0 )
+ face_index = -face_index - 1;
+ if ( face_index >= resource_cnt )
+ return FT_THROW( Cannot_Open_Resource );
+
+ flag_offset = (FT_ULong)offsets[face_index];
+ error = FT_Stream_Seek( stream, flag_offset );
+ if ( error )
+ goto Exit;
+
+ if ( FT_READ_LONG( rlen ) )
+ goto Exit;
+ if ( rlen < 1 )
+ return FT_THROW( Cannot_Open_Resource );
+ if ( (FT_ULong)rlen > FT_MAC_RFORK_MAX_LEN )
+ return FT_THROW( Invalid_Offset );
+
+ error = open_face_PS_from_sfnt_stream( library,
+ stream,
+ face_index,
+ 0, NULL,
+ aface );
+ if ( !error )
+ goto Exit;
+
+ /* rewind sfnt stream before open_face_PS_from_sfnt_stream() */
+ error = FT_Stream_Seek( stream, flag_offset + 4 );
+ if ( error )
+ goto Exit;
+
+ if ( FT_QALLOC( sfnt_data, rlen ) )
+ return error;
+ error = FT_Stream_Read( stream, (FT_Byte *)sfnt_data, (FT_ULong)rlen );
+ if ( error ) {
+ FT_FREE( sfnt_data );
+ goto Exit;
+ }
+
+ is_cff = rlen > 4 && !ft_memcmp( sfnt_data, "OTTO", 4 );
+ error = open_face_from_buffer( library,
+ sfnt_data,
+ (FT_ULong)rlen,
+ face_index_in_resource,
+ is_cff ? "cff" : "truetype",
+ aface );
+
+ Exit:
+ return error;
+ }
+
+
+ /* Check for a valid resource fork header, or a valid dfont */
+ /* header. In a resource fork the first 16 bytes are repeated */
+ /* at the location specified by bytes 4-7. In a dfont bytes */
+ /* 4-7 point to 16 bytes of zeroes instead. */
+ /* */
+ static FT_Error
+ IsMacResource( FT_Library library,
+ FT_Stream stream,
+ FT_Long resource_offset,
+ FT_Long face_index,
+ FT_Face *aface )
+ {
+ FT_Memory memory = library->memory;
+ FT_Error error;
+ FT_Long map_offset, rdata_pos;
+ FT_Long *data_offsets;
+ FT_Long count;
+
+
+ error = FT_Raccess_Get_HeaderInfo( library, stream, resource_offset,
+ &map_offset, &rdata_pos );
+ if ( error )
+ return error;
+
+ /* POST resources must be sorted to concatenate properly */
+ error = FT_Raccess_Get_DataOffsets( library, stream,
+ map_offset, rdata_pos,
+ TTAG_POST, TRUE,
+ &data_offsets, &count );
+ if ( !error )
+ {
+ error = Mac_Read_POST_Resource( library, stream, data_offsets, count,
+ face_index, aface );
+ FT_FREE( data_offsets );
+ /* POST exists in an LWFN providing a single face */
+ if ( !error )
+ (*aface)->num_faces = 1;
+ return error;
+ }
+
+ /* sfnt resources should not be sorted to preserve the face order by
+ QuickDraw API */
+ error = FT_Raccess_Get_DataOffsets( library, stream,
+ map_offset, rdata_pos,
+ TTAG_sfnt, FALSE,
+ &data_offsets, &count );
+ if ( !error )
+ {
+ FT_Long face_index_internal = face_index % count;
+
+
+ error = Mac_Read_sfnt_Resource( library, stream, data_offsets, count,
+ face_index_internal, aface );
+ FT_FREE( data_offsets );
+ if ( !error )
+ (*aface)->num_faces = count;
+ }
+
+ return error;
+ }
+
+
+ /* Check for a valid macbinary header, and if we find one */
+ /* check that the (flattened) resource fork in it is valid. */
+ /* */
+ static FT_Error
+ IsMacBinary( FT_Library library,
+ FT_Stream stream,
+ FT_Long face_index,
+ FT_Face *aface )
+ {
+ unsigned char header[128];
+ FT_Error error;
+ FT_Long dlen, offset;
+
+
+ if ( !stream )
+ return FT_THROW( Invalid_Stream_Operation );
+
+ error = FT_Stream_Seek( stream, 0 );
+ if ( error )
+ goto Exit;
+
+ error = FT_Stream_Read( stream, (FT_Byte*)header, 128 );
+ if ( error )
+ goto Exit;
+
+ if ( header[ 0] != 0 ||
+ header[74] != 0 ||
+ header[82] != 0 ||
+ header[ 1] == 0 ||
+ header[ 1] > 33 ||
+ header[63] != 0 ||
+ header[2 + header[1]] != 0 ||
+ header[0x53] > 0x7F )
+ return FT_THROW( Unknown_File_Format );
+
+ dlen = ( header[0x53] << 24 ) |
+ ( header[0x54] << 16 ) |
+ ( header[0x55] << 8 ) |
+ header[0x56];
+#if 0
+ rlen = ( header[0x57] << 24 ) |
+ ( header[0x58] << 16 ) |
+ ( header[0x59] << 8 ) |
+ header[0x5A];
+#endif /* 0 */
+ offset = 128 + ( ( dlen + 127 ) & ~127 );
+
+ return IsMacResource( library, stream, offset, face_index, aface );
+
+ Exit:
+ return error;
+ }
+
+
+ static FT_Error
+ load_face_in_embedded_rfork( FT_Library library,
+ FT_Stream stream,
+ FT_Long face_index,
+ FT_Face *aface,
+ const FT_Open_Args *args )
+ {
+
+#undef FT_COMPONENT
+#define FT_COMPONENT raccess
+
+ FT_Memory memory = library->memory;
+ FT_Error error = FT_ERR( Unknown_File_Format );
+ FT_UInt i;
+
+ char* file_names[FT_RACCESS_N_RULES];
+ FT_Long offsets[FT_RACCESS_N_RULES];
+ FT_Error errors[FT_RACCESS_N_RULES];
+ FT_Bool is_darwin_vfs, vfs_rfork_has_no_font = FALSE; /* not tested */
+
+ FT_Open_Args args2;
+ FT_Stream stream2 = NULL;
+
+
+ FT_Raccess_Guess( library, stream,
+ args->pathname, file_names, offsets, errors );
+
+ for ( i = 0; i < FT_RACCESS_N_RULES; i++ )
+ {
+ is_darwin_vfs = ft_raccess_rule_by_darwin_vfs( library, i );
+ if ( is_darwin_vfs && vfs_rfork_has_no_font )
+ {
+ FT_TRACE3(( "Skip rule %d: darwin vfs resource fork"
+ " is already checked and"
+ " no font is found\n",
+ i ));
+ continue;
+ }
+
+ if ( errors[i] )
+ {
+ FT_TRACE3(( "Error 0x%x has occurred in rule %d\n",
+ errors[i], i ));
+ continue;
+ }
+
+ args2.flags = FT_OPEN_PATHNAME;
+ args2.pathname = file_names[i] ? file_names[i] : args->pathname;
+
+ FT_TRACE3(( "Try rule %d: %s (offset=%ld) ...",
+ i, args2.pathname, offsets[i] ));
+
+ error = FT_Stream_New( library, &args2, &stream2 );
+ if ( is_darwin_vfs && FT_ERR_EQ( error, Cannot_Open_Stream ) )
+ vfs_rfork_has_no_font = TRUE;
+
+ if ( error )
+ {
+ FT_TRACE3(( "failed\n" ));
+ continue;
+ }
+
+ error = IsMacResource( library, stream2, offsets[i],
+ face_index, aface );
+ FT_Stream_Free( stream2, 0 );
+
+ FT_TRACE3(( "%s\n", error ? "failed": "successful" ));
+
+ if ( !error )
+ break;
+ else if ( is_darwin_vfs )
+ vfs_rfork_has_no_font = TRUE;
+ }
+
+ for (i = 0; i < FT_RACCESS_N_RULES; i++)
+ {
+ if ( file_names[i] )
+ FT_FREE( file_names[i] );
+ }
+
+ /* Caller (load_mac_face) requires FT_Err_Unknown_File_Format. */
+ if ( error )
+ error = FT_ERR( Unknown_File_Format );
+
+ return error;
+
+#undef FT_COMPONENT
+#define FT_COMPONENT objs
+
+ }
+
+
+ /* Check for some macintosh formats without Carbon framework. */
+ /* Is this a macbinary file? If so look at the resource fork. */
+ /* Is this a mac dfont file? */
+ /* Is this an old style resource fork? (in data) */
+ /* Else call load_face_in_embedded_rfork to try extra rules */
+ /* (defined in `ftrfork.c'). */
+ /* */
+ static FT_Error
+ load_mac_face( FT_Library library,
+ FT_Stream stream,
+ FT_Long face_index,
+ FT_Face *aface,
+ const FT_Open_Args *args )
+ {
+ FT_Error error;
+ FT_UNUSED( args );
+
+
+ error = IsMacBinary( library, stream, face_index, aface );
+ if ( FT_ERR_EQ( error, Unknown_File_Format ) )
+ {
+
+#undef FT_COMPONENT
+#define FT_COMPONENT raccess
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+ FT_TRACE3(( "Try as dfont: " ));
+ if ( !( args->flags & FT_OPEN_MEMORY ) )
+ FT_TRACE3(( "%s ...", args->pathname ));
+#endif
+
+ error = IsMacResource( library, stream, 0, face_index, aface );
+
+ FT_TRACE3(( "%s\n", error ? "failed" : "successful" ));
+
+#undef FT_COMPONENT
+#define FT_COMPONENT objs
+
+ }
+
+ if ( ( FT_ERR_EQ( error, Unknown_File_Format ) ||
+ FT_ERR_EQ( error, Invalid_Stream_Operation ) ) &&
+ ( args->flags & FT_OPEN_PATHNAME ) )
+ error = load_face_in_embedded_rfork( library, stream,
+ face_index, aface, args );
+ return error;
+ }
+#endif
+
+#endif /* !FT_MACINTOSH && FT_CONFIG_OPTION_MAC_FONTS */
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Open_Face( FT_Library library,
+ const FT_Open_Args* args,
+ FT_Long face_index,
+ FT_Face *aface )
+ {
+ return ft_open_face_internal( library, args, face_index, aface, 1 );
+ }
+
+
+ static FT_Error
+ ft_open_face_internal( FT_Library library,
+ const FT_Open_Args* args,
+ FT_Long face_index,
+ FT_Face *aface,
+ FT_Bool test_mac_fonts )
+ {
+ FT_Error error;
+ FT_Driver driver = NULL;
+ FT_Memory memory = NULL;
+ FT_Stream stream = NULL;
+ FT_Face face = NULL;
+ FT_ListNode node = NULL;
+ FT_Bool external_stream;
+ FT_Module* cur;
+ FT_Module* limit;
+
+#ifndef FT_CONFIG_OPTION_MAC_FONTS
+ FT_UNUSED( test_mac_fonts );
+#endif
+
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+ FT_TRACE3(( "FT_Open_Face: " ));
+ if ( face_index < 0 )
+ FT_TRACE3(( "Requesting number of faces and named instances\n"));
+ else
+ {
+ FT_TRACE3(( "Requesting face %ld", face_index & 0xFFFFL ));
+ if ( face_index & 0x7FFF0000L )
+ FT_TRACE3(( ", named instance %ld", face_index >> 16 ));
+ FT_TRACE3(( "\n" ));
+ }
+#endif
+
+ /* test for valid `library' delayed to `FT_Stream_New' */
+
+ if ( ( !aface && face_index >= 0 ) || !args )
+ return FT_THROW( Invalid_Argument );
+
+ external_stream = FT_BOOL( ( args->flags & FT_OPEN_STREAM ) &&
+ args->stream );
+
+ /* create input stream */
+ error = FT_Stream_New( library, args, &stream );
+ if ( error )
+ goto Fail3;
+
+ memory = library->memory;
+
+ /* If the font driver is specified in the `args' structure, use */
+ /* it. Otherwise, we scan the list of registered drivers. */
+ if ( ( args->flags & FT_OPEN_DRIVER ) && args->driver )
+ {
+ driver = FT_DRIVER( args->driver );
+
+ /* not all modules are drivers, so check... */
+ if ( FT_MODULE_IS_DRIVER( driver ) )
+ {
+ FT_Int num_params = 0;
+ FT_Parameter* params = NULL;
+
+
+ if ( args->flags & FT_OPEN_PARAMS )
+ {
+ num_params = args->num_params;
+ params = args->params;
+ }
+
+ error = open_face( driver, &stream, external_stream, face_index,
+ num_params, params, &face );
+ if ( !error )
+ goto Success;
+ }
+ else
+ error = FT_THROW( Invalid_Handle );
+
+ FT_Stream_Free( stream, external_stream );
+ goto Fail;
+ }
+ else
+ {
+ error = FT_ERR( Missing_Module );
+
+ /* check each font driver for an appropriate format */
+ cur = library->modules;
+ limit = cur + library->num_modules;
+
+ for ( ; cur < limit; cur++ )
+ {
+ /* not all modules are font drivers, so check... */
+ if ( FT_MODULE_IS_DRIVER( cur[0] ) )
+ {
+ FT_Int num_params = 0;
+ FT_Parameter* params = NULL;
+
+
+ driver = FT_DRIVER( cur[0] );
+
+ if ( args->flags & FT_OPEN_PARAMS )
+ {
+ num_params = args->num_params;
+ params = args->params;
+ }
+
+ error = open_face( driver, &stream, external_stream, face_index,
+ num_params, params, &face );
+ if ( !error )
+ goto Success;
+
+#ifdef FT_CONFIG_OPTION_MAC_FONTS
+ if ( test_mac_fonts &&
+ ft_strcmp( cur[0]->clazz->module_name, "truetype" ) == 0 &&
+ FT_ERR_EQ( error, Table_Missing ) )
+ {
+ /* TrueType but essential tables are missing */
+ error = FT_Stream_Seek( stream, 0 );
+ if ( error )
+ break;
+
+ error = open_face_PS_from_sfnt_stream( library,
+ stream,
+ face_index,
+ num_params,
+ params,
+ aface );
+ if ( !error )
+ {
+ FT_Stream_Free( stream, external_stream );
+ return error;
+ }
+ }
+#endif
+
+ if ( FT_ERR_NEQ( error, Unknown_File_Format ) )
+ goto Fail3;
+ }
+ }
+
+ Fail3:
+ /* If we are on the mac, and we get an */
+ /* FT_Err_Invalid_Stream_Operation it may be because we have an */
+ /* empty data fork, so we need to check the resource fork. */
+ if ( FT_ERR_NEQ( error, Cannot_Open_Stream ) &&
+ FT_ERR_NEQ( error, Unknown_File_Format ) &&
+ FT_ERR_NEQ( error, Invalid_Stream_Operation ) )
+ goto Fail2;
+
+#if !defined( FT_MACINTOSH ) && defined( FT_CONFIG_OPTION_MAC_FONTS )
+ if ( test_mac_fonts )
+ {
+ error = load_mac_face( library, stream, face_index, aface, args );
+ if ( !error )
+ {
+ /* We don't want to go to Success here. We've already done */
+ /* that. On the other hand, if we succeeded we still need to */
+ /* close this stream (we opened a different stream which */
+ /* extracted the interesting information out of this stream */
+ /* here. That stream will still be open and the face will */
+ /* point to it). */
+ FT_Stream_Free( stream, external_stream );
+ return error;
+ }
+ }
+
+ if ( FT_ERR_NEQ( error, Unknown_File_Format ) )
+ goto Fail2;
+#endif /* !FT_MACINTOSH && FT_CONFIG_OPTION_MAC_FONTS */
+
+ /* no driver is able to handle this format */
+ error = FT_THROW( Unknown_File_Format );
+
+ Fail2:
+ FT_Stream_Free( stream, external_stream );
+ goto Fail;
+ }
+
+ Success:
+ FT_TRACE4(( "FT_Open_Face: New face object, adding to list\n" ));
+
+ /* add the face object to its driver's list */
+ if ( FT_NEW( node ) )
+ goto Fail;
+
+ node->data = face;
+ /* don't assume driver is the same as face->driver, so use */
+ /* face->driver instead. */
+ FT_List_Add( &face->driver->faces_list, node );
+
+ /* now allocate a glyph slot object for the face */
+ FT_TRACE4(( "FT_Open_Face: Creating glyph slot\n" ));
+
+ if ( face_index >= 0 )
+ {
+ error = FT_New_GlyphSlot( face, NULL );
+ if ( error )
+ goto Fail;
+
+ /* finally, allocate a size object for the face */
+ {
+ FT_Size size;
+
+
+ FT_TRACE4(( "FT_Open_Face: Creating size object\n" ));
+
+ error = FT_New_Size( face, &size );
+ if ( error )
+ goto Fail;
+
+ face->size = size;
+ }
+ }
+
+ /* some checks */
+
+ if ( FT_IS_SCALABLE( face ) )
+ {
+ if ( face->height < 0 )
+ face->height = (FT_Short)-face->height;
+
+ if ( !FT_HAS_VERTICAL( face ) )
+ face->max_advance_height = (FT_Short)face->height;
+ }
+
+ if ( FT_HAS_FIXED_SIZES( face ) )
+ {
+ FT_Int i;
+
+
+ for ( i = 0; i < face->num_fixed_sizes; i++ )
+ {
+ FT_Bitmap_Size* bsize = face->available_sizes + i;
+
+
+ if ( bsize->height < 0 )
+ bsize->height = -bsize->height;
+ if ( bsize->x_ppem < 0 )
+ bsize->x_ppem = -bsize->x_ppem;
+ if ( bsize->y_ppem < 0 )
+ bsize->y_ppem = -bsize->y_ppem;
+
+ /* check whether negation actually has worked */
+ if ( bsize->height < 0 || bsize->x_ppem < 0 || bsize->y_ppem < 0 )
+ {
+ FT_TRACE0(( "FT_Open_Face:"
+ " Invalid bitmap dimensions for strike %d,"
+ " now disabled\n", i ));
+ bsize->width = 0;
+ bsize->height = 0;
+ bsize->size = 0;
+ bsize->x_ppem = 0;
+ bsize->y_ppem = 0;
+ }
+ }
+ }
+
+ /* initialize internal face data */
+ {
+ FT_Face_Internal internal = face->internal;
+
+
+ internal->transform_matrix.xx = 0x10000L;
+ internal->transform_matrix.xy = 0;
+ internal->transform_matrix.yx = 0;
+ internal->transform_matrix.yy = 0x10000L;
+
+ internal->transform_delta.x = 0;
+ internal->transform_delta.y = 0;
+
+ internal->refcount = 1;
+
+ internal->no_stem_darkening = -1;
+
+#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
+ /* Per-face filtering can only be set up by FT_Face_Properties */
+ internal->lcd_filter_func = NULL;
+#endif
+ }
+
+ if ( aface )
+ *aface = face;
+ else
+ FT_Done_Face( face );
+
+ goto Exit;
+
+ Fail:
+ if ( node )
+ FT_Done_Face( face ); /* face must be in the driver's list */
+ else if ( face )
+ destroy_face( memory, face, driver );
+
+ Exit:
+#ifdef FT_DEBUG_LEVEL_TRACE
+ if ( !error && face_index < 0 )
+ {
+ FT_TRACE3(( "FT_Open_Face: The font has %ld face%s\n",
+ face->num_faces,
+ face->num_faces == 1 ? "" : "s" ));
+ FT_TRACE3(( " and %ld named instance%s for face %ld\n",
+ face->style_flags >> 16,
+ ( face->style_flags >> 16 ) == 1 ? "" : "s",
+ -face_index - 1 ));
+ }
+#endif
+
+ FT_TRACE4(( "FT_Open_Face: Return 0x%x\n", error ));
+
+ return error;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Attach_File( FT_Face face,
+ const char* filepathname )
+ {
+ FT_Open_Args open;
+
+
+ /* test for valid `face' delayed to `FT_Attach_Stream' */
+
+ if ( !filepathname )
+ return FT_THROW( Invalid_Argument );
+
+ open.stream = NULL;
+ open.flags = FT_OPEN_PATHNAME;
+ open.pathname = (char*)filepathname;
+
+ return FT_Attach_Stream( face, &open );
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Attach_Stream( FT_Face face,
+ FT_Open_Args* parameters )
+ {
+ FT_Stream stream;
+ FT_Error error;
+ FT_Driver driver;
+
+ FT_Driver_Class clazz;
+
+
+ /* test for valid `parameters' delayed to `FT_Stream_New' */
+
+ if ( !face )
+ return FT_THROW( Invalid_Face_Handle );
+
+ driver = face->driver;
+ if ( !driver )
+ return FT_THROW( Invalid_Driver_Handle );
+
+ error = FT_Stream_New( driver->root.library, parameters, &stream );
+ if ( error )
+ goto Exit;
+
+ /* we implement FT_Attach_Stream in each driver through the */
+ /* `attach_file' interface */
+
+ error = FT_ERR( Unimplemented_Feature );
+ clazz = driver->clazz;
+ if ( clazz->attach_file )
+ error = clazz->attach_file( face, stream );
+
+ /* close the attached stream */
+ FT_Stream_Free( stream,
+ FT_BOOL( parameters->stream &&
+ ( parameters->flags & FT_OPEN_STREAM ) ) );
+
+ Exit:
+ return error;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Reference_Face( FT_Face face )
+ {
+ if ( !face )
+ return FT_THROW( Invalid_Face_Handle );
+
+ face->internal->refcount++;
+
+ return FT_Err_Ok;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Done_Face( FT_Face face )
+ {
+ FT_Error error;
+ FT_Driver driver;
+ FT_Memory memory;
+ FT_ListNode node;
+
+
+ error = FT_ERR( Invalid_Face_Handle );
+ if ( face && face->driver )
+ {
+ face->internal->refcount--;
+ if ( face->internal->refcount > 0 )
+ error = FT_Err_Ok;
+ else
+ {
+ driver = face->driver;
+ memory = driver->root.memory;
+
+ /* find face in driver's list */
+ node = FT_List_Find( &driver->faces_list, face );
+ if ( node )
+ {
+ /* remove face object from the driver's list */
+ FT_List_Remove( &driver->faces_list, node );
+ FT_FREE( node );
+
+ /* now destroy the object proper */
+ destroy_face( memory, face, driver );
+ error = FT_Err_Ok;
+ }
+ }
+ }
+
+ return error;
+ }
+
+
+ /* documentation is in ftobjs.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_New_Size( FT_Face face,
+ FT_Size *asize )
+ {
+ FT_Error error;
+ FT_Memory memory;
+ FT_Driver driver;
+ FT_Driver_Class clazz;
+
+ FT_Size size = NULL;
+ FT_ListNode node = NULL;
+
+ FT_Size_Internal internal = NULL;
+
+
+ if ( !face )
+ return FT_THROW( Invalid_Face_Handle );
+
+ if ( !asize )
+ return FT_THROW( Invalid_Argument );
+
+ if ( !face->driver )
+ return FT_THROW( Invalid_Driver_Handle );
+
+ *asize = NULL;
+
+ driver = face->driver;
+ clazz = driver->clazz;
+ memory = face->memory;
+
+ /* Allocate new size object and perform basic initialisation */
+ if ( FT_ALLOC( size, clazz->size_object_size ) || FT_NEW( node ) )
+ goto Exit;
+
+ size->face = face;
+
+ if ( FT_NEW( internal ) )
+ goto Exit;
+
+ size->internal = internal;
+
+ if ( clazz->init_size )
+ error = clazz->init_size( size );
+
+ /* in case of success, add to the face's list */
+ if ( !error )
+ {
+ *asize = size;
+ node->data = size;
+ FT_List_Add( &face->sizes_list, node );
+ }
+
+ Exit:
+ if ( error )
+ {
+ FT_FREE( node );
+ if ( size )
+ FT_FREE( size->internal );
+ FT_FREE( size );
+ }
+
+ return error;
+ }
+
+
+ /* documentation is in ftobjs.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Done_Size( FT_Size size )
+ {
+ FT_Error error;
+ FT_Driver driver;
+ FT_Memory memory;
+ FT_Face face;
+ FT_ListNode node;
+
+
+ if ( !size )
+ return FT_THROW( Invalid_Size_Handle );
+
+ face = size->face;
+ if ( !face )
+ return FT_THROW( Invalid_Face_Handle );
+
+ driver = face->driver;
+ if ( !driver )
+ return FT_THROW( Invalid_Driver_Handle );
+
+ memory = driver->root.memory;
+
+ error = FT_Err_Ok;
+ node = FT_List_Find( &face->sizes_list, size );
+ if ( node )
+ {
+ FT_List_Remove( &face->sizes_list, node );
+ FT_FREE( node );
+
+ if ( face->size == size )
+ {
+ face->size = NULL;
+ if ( face->sizes_list.head )
+ face->size = (FT_Size)(face->sizes_list.head->data);
+ }
+
+ destroy_size( memory, size, driver );
+ }
+ else
+ error = FT_THROW( Invalid_Size_Handle );
+
+ return error;
+ }
+
+
+ /* documentation is in ftobjs.h */
+
+ FT_BASE_DEF( FT_Error )
+ FT_Match_Size( FT_Face face,
+ FT_Size_Request req,
+ FT_Bool ignore_width,
+ FT_ULong* size_index )
+ {
+ FT_Int i;
+ FT_Long w, h;
+
+
+ if ( !FT_HAS_FIXED_SIZES( face ) )
+ return FT_THROW( Invalid_Face_Handle );
+
+ /* FT_Bitmap_Size doesn't provide enough info... */
+ if ( req->type != FT_SIZE_REQUEST_TYPE_NOMINAL )
+ return FT_THROW( Unimplemented_Feature );
+
+ w = FT_REQUEST_WIDTH ( req );
+ h = FT_REQUEST_HEIGHT( req );
+
+ if ( req->width && !req->height )
+ h = w;
+ else if ( !req->width && req->height )
+ w = h;
+
+ w = FT_PIX_ROUND( w );
+ h = FT_PIX_ROUND( h );
+
+ if ( !w || !h )
+ return FT_THROW( Invalid_Pixel_Size );
+
+ for ( i = 0; i < face->num_fixed_sizes; i++ )
+ {
+ FT_Bitmap_Size* bsize = face->available_sizes + i;
+
+
+ if ( h != FT_PIX_ROUND( bsize->y_ppem ) )
+ continue;
+
+ if ( w == FT_PIX_ROUND( bsize->x_ppem ) || ignore_width )
+ {
+ FT_TRACE3(( "FT_Match_Size: bitmap strike %d matches\n", i ));
+
+ if ( size_index )
+ *size_index = (FT_ULong)i;
+
+ return FT_Err_Ok;
+ }
+ }
+
+ FT_TRACE3(( "FT_Match_Size: no matching bitmap strike\n" ));
+
+ return FT_THROW( Invalid_Pixel_Size );
+ }
+
+
+ /* documentation is in ftobjs.h */
+
+ FT_BASE_DEF( void )
+ ft_synthesize_vertical_metrics( FT_Glyph_Metrics* metrics,
+ FT_Pos advance )
+ {
+ FT_Pos height = metrics->height;
+
+
+ /* compensate for glyph with bbox above/below the baseline */
+ if ( metrics->horiBearingY < 0 )
+ {
+ if ( height < metrics->horiBearingY )
+ height = metrics->horiBearingY;
+ }
+ else if ( metrics->horiBearingY > 0 )
+ height -= metrics->horiBearingY;
+
+ /* the factor 1.2 is a heuristical value */
+ if ( !advance )
+ advance = height * 12 / 10;
+
+ metrics->vertBearingX = metrics->horiBearingX - metrics->horiAdvance / 2;
+ metrics->vertBearingY = ( advance - height ) / 2;
+ metrics->vertAdvance = advance;
+ }
+
+
+ static void
+ ft_recompute_scaled_metrics( FT_Face face,
+ FT_Size_Metrics* metrics )
+ {
+ /* Compute root ascender, descender, test height, and max_advance */
+
+#ifdef GRID_FIT_METRICS
+ metrics->ascender = FT_PIX_CEIL( FT_MulFix( face->ascender,
+ metrics->y_scale ) );
+
+ metrics->descender = FT_PIX_FLOOR( FT_MulFix( face->descender,
+ metrics->y_scale ) );
+
+ metrics->height = FT_PIX_ROUND( FT_MulFix( face->height,
+ metrics->y_scale ) );
+
+ metrics->max_advance = FT_PIX_ROUND( FT_MulFix( face->max_advance_width,
+ metrics->x_scale ) );
+#else /* !GRID_FIT_METRICS */
+ metrics->ascender = FT_MulFix( face->ascender,
+ metrics->y_scale );
+
+ metrics->descender = FT_MulFix( face->descender,
+ metrics->y_scale );
+
+ metrics->height = FT_MulFix( face->height,
+ metrics->y_scale );
+
+ metrics->max_advance = FT_MulFix( face->max_advance_width,
+ metrics->x_scale );
+#endif /* !GRID_FIT_METRICS */
+ }
+
+
+ FT_BASE_DEF( void )
+ FT_Select_Metrics( FT_Face face,
+ FT_ULong strike_index )
+ {
+ FT_Size_Metrics* metrics;
+ FT_Bitmap_Size* bsize;
+
+
+ metrics = &face->size->metrics;
+ bsize = face->available_sizes + strike_index;
+
+ metrics->x_ppem = (FT_UShort)( ( bsize->x_ppem + 32 ) >> 6 );
+ metrics->y_ppem = (FT_UShort)( ( bsize->y_ppem + 32 ) >> 6 );
+
+ if ( FT_IS_SCALABLE( face ) )
+ {
+ metrics->x_scale = FT_DivFix( bsize->x_ppem,
+ face->units_per_EM );
+ metrics->y_scale = FT_DivFix( bsize->y_ppem,
+ face->units_per_EM );
+
+ ft_recompute_scaled_metrics( face, metrics );
+ }
+ else
+ {
+ metrics->x_scale = 1L << 16;
+ metrics->y_scale = 1L << 16;
+ metrics->ascender = bsize->y_ppem;
+ metrics->descender = 0;
+ metrics->height = bsize->height << 6;
+ metrics->max_advance = bsize->x_ppem;
+ }
+ }
+
+
+ FT_BASE_DEF( void )
+ FT_Request_Metrics( FT_Face face,
+ FT_Size_Request req )
+ {
+ FT_Size_Metrics* metrics;
+
+
+ metrics = &face->size->metrics;
+
+ if ( FT_IS_SCALABLE( face ) )
+ {
+ FT_Long w = 0, h = 0, scaled_w = 0, scaled_h = 0;
+
+
+ switch ( req->type )
+ {
+ case FT_SIZE_REQUEST_TYPE_NOMINAL:
+ w = h = face->units_per_EM;
+ break;
+
+ case FT_SIZE_REQUEST_TYPE_REAL_DIM:
+ w = h = face->ascender - face->descender;
+ break;
+
+ case FT_SIZE_REQUEST_TYPE_BBOX:
+ w = face->bbox.xMax - face->bbox.xMin;
+ h = face->bbox.yMax - face->bbox.yMin;
+ break;
+
+ case FT_SIZE_REQUEST_TYPE_CELL:
+ w = face->max_advance_width;
+ h = face->ascender - face->descender;
+ break;
+
+ case FT_SIZE_REQUEST_TYPE_SCALES:
+ metrics->x_scale = (FT_Fixed)req->width;
+ metrics->y_scale = (FT_Fixed)req->height;
+ if ( !metrics->x_scale )
+ metrics->x_scale = metrics->y_scale;
+ else if ( !metrics->y_scale )
+ metrics->y_scale = metrics->x_scale;
+ goto Calculate_Ppem;
+
+ case FT_SIZE_REQUEST_TYPE_MAX:
+ break;
+ }
+
+ /* to be on the safe side */
+ if ( w < 0 )
+ w = -w;
+
+ if ( h < 0 )
+ h = -h;
+
+ scaled_w = FT_REQUEST_WIDTH ( req );
+ scaled_h = FT_REQUEST_HEIGHT( req );
+
+ /* determine scales */
+ if ( req->width )
+ {
+ metrics->x_scale = FT_DivFix( scaled_w, w );
+
+ if ( req->height )
+ {
+ metrics->y_scale = FT_DivFix( scaled_h, h );
+
+ if ( req->type == FT_SIZE_REQUEST_TYPE_CELL )
+ {
+ if ( metrics->y_scale > metrics->x_scale )
+ metrics->y_scale = metrics->x_scale;
+ else
+ metrics->x_scale = metrics->y_scale;
+ }
+ }
+ else
+ {
+ metrics->y_scale = metrics->x_scale;
+ scaled_h = FT_MulDiv( scaled_w, h, w );
+ }
+ }
+ else
+ {
+ metrics->x_scale = metrics->y_scale = FT_DivFix( scaled_h, h );
+ scaled_w = FT_MulDiv( scaled_h, w, h );
+ }
+
+ Calculate_Ppem:
+ /* calculate the ppems */
+ if ( req->type != FT_SIZE_REQUEST_TYPE_NOMINAL )
+ {
+ scaled_w = FT_MulFix( face->units_per_EM, metrics->x_scale );
+ scaled_h = FT_MulFix( face->units_per_EM, metrics->y_scale );
+ }
+
+ metrics->x_ppem = (FT_UShort)( ( scaled_w + 32 ) >> 6 );
+ metrics->y_ppem = (FT_UShort)( ( scaled_h + 32 ) >> 6 );
+
+ ft_recompute_scaled_metrics( face, metrics );
+ }
+ else
+ {
+ FT_ZERO( metrics );
+ metrics->x_scale = 1L << 16;
+ metrics->y_scale = 1L << 16;
+ }
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Select_Size( FT_Face face,
+ FT_Int strike_index )
+ {
+ FT_Error error = FT_Err_Ok;
+ FT_Driver_Class clazz;
+
+
+ if ( !face || !FT_HAS_FIXED_SIZES( face ) )
+ return FT_THROW( Invalid_Face_Handle );
+
+ if ( strike_index < 0 || strike_index >= face->num_fixed_sizes )
+ return FT_THROW( Invalid_Argument );
+
+ clazz = face->driver->clazz;
+
+ if ( clazz->select_size )
+ {
+ error = clazz->select_size( face->size, (FT_ULong)strike_index );
+
+ FT_TRACE5(( "FT_Select_Size (%s driver):\n",
+ face->driver->root.clazz->module_name ));
+ }
+ else
+ {
+ FT_Select_Metrics( face, (FT_ULong)strike_index );
+
+ FT_TRACE5(( "FT_Select_Size:\n" ));
+ }
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+ {
+ FT_Size_Metrics* metrics = &face->size->metrics;
+
+
+ FT_TRACE5(( " x scale: %ld (%f)\n",
+ metrics->x_scale, metrics->x_scale / 65536.0 ));
+ FT_TRACE5(( " y scale: %ld (%f)\n",
+ metrics->y_scale, metrics->y_scale / 65536.0 ));
+ FT_TRACE5(( " ascender: %f\n", metrics->ascender / 64.0 ));
+ FT_TRACE5(( " descender: %f\n", metrics->descender / 64.0 ));
+ FT_TRACE5(( " height: %f\n", metrics->height / 64.0 ));
+ FT_TRACE5(( " max advance: %f\n", metrics->max_advance / 64.0 ));
+ FT_TRACE5(( " x ppem: %d\n", metrics->x_ppem ));
+ FT_TRACE5(( " y ppem: %d\n", metrics->y_ppem ));
+ }
+#endif
+
+ return error;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Request_Size( FT_Face face,
+ FT_Size_Request req )
+ {
+ FT_Error error = FT_Err_Ok;
+ FT_Driver_Class clazz;
+ FT_ULong strike_index;
+
+
+ if ( !face )
+ return FT_THROW( Invalid_Face_Handle );
+
+ if ( !req || req->width < 0 || req->height < 0 ||
+ req->type >= FT_SIZE_REQUEST_TYPE_MAX )
+ return FT_THROW( Invalid_Argument );
+
+ /* signal the auto-hinter to recompute its size metrics */
+ /* (if requested) */
+ face->size->internal->autohint_metrics.x_scale = 0;
+
+ clazz = face->driver->clazz;
+
+ if ( clazz->request_size )
+ {
+ error = clazz->request_size( face->size, req );
+
+ FT_TRACE5(( "FT_Request_Size (%s driver):\n",
+ face->driver->root.clazz->module_name ));
+ }
+ else if ( !FT_IS_SCALABLE( face ) && FT_HAS_FIXED_SIZES( face ) )
+ {
+ /*
+ * The reason that a driver doesn't have `request_size' defined is
+ * either that the scaling here suffices or that the supported formats
+ * are bitmap-only and size matching is not implemented.
+ *
+ * In the latter case, a simple size matching is done.
+ */
+ error = FT_Match_Size( face, req, 0, &strike_index );
+ if ( error )
+ return error;
+
+ return FT_Select_Size( face, (FT_Int)strike_index );
+ }
+ else
+ {
+ FT_Request_Metrics( face, req );
+
+ FT_TRACE5(( "FT_Request_Size:\n" ));
+ }
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+ {
+ FT_Size_Metrics* metrics = &face->size->metrics;
+
+
+ FT_TRACE5(( " x scale: %ld (%f)\n",
+ metrics->x_scale, metrics->x_scale / 65536.0 ));
+ FT_TRACE5(( " y scale: %ld (%f)\n",
+ metrics->y_scale, metrics->y_scale / 65536.0 ));
+ FT_TRACE5(( " ascender: %f\n", metrics->ascender / 64.0 ));
+ FT_TRACE5(( " descender: %f\n", metrics->descender / 64.0 ));
+ FT_TRACE5(( " height: %f\n", metrics->height / 64.0 ));
+ FT_TRACE5(( " max advance: %f\n", metrics->max_advance / 64.0 ));
+ FT_TRACE5(( " x ppem: %d\n", metrics->x_ppem ));
+ FT_TRACE5(( " y ppem: %d\n", metrics->y_ppem ));
+ }
+#endif
+
+ return error;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Set_Char_Size( FT_Face face,
+ FT_F26Dot6 char_width,
+ FT_F26Dot6 char_height,
+ FT_UInt horz_resolution,
+ FT_UInt vert_resolution )
+ {
+ FT_Size_RequestRec req;
+
+
+ /* check of `face' delayed to `FT_Request_Size' */
+
+ if ( !char_width )
+ char_width = char_height;
+ else if ( !char_height )
+ char_height = char_width;
+
+ if ( !horz_resolution )
+ horz_resolution = vert_resolution;
+ else if ( !vert_resolution )
+ vert_resolution = horz_resolution;
+
+ if ( char_width < 1 * 64 )
+ char_width = 1 * 64;
+ if ( char_height < 1 * 64 )
+ char_height = 1 * 64;
+
+ if ( !horz_resolution )
+ horz_resolution = vert_resolution = 72;
+
+ req.type = FT_SIZE_REQUEST_TYPE_NOMINAL;
+ req.width = char_width;
+ req.height = char_height;
+ req.horiResolution = horz_resolution;
+ req.vertResolution = vert_resolution;
+
+ return FT_Request_Size( face, &req );
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Set_Pixel_Sizes( FT_Face face,
+ FT_UInt pixel_width,
+ FT_UInt pixel_height )
+ {
+ FT_Size_RequestRec req;
+
+
+ /* check of `face' delayed to `FT_Request_Size' */
+
+ if ( pixel_width == 0 )
+ pixel_width = pixel_height;
+ else if ( pixel_height == 0 )
+ pixel_height = pixel_width;
+
+ if ( pixel_width < 1 )
+ pixel_width = 1;
+ if ( pixel_height < 1 )
+ pixel_height = 1;
+
+ /* use `>=' to avoid potential compiler warning on 16bit platforms */
+ if ( pixel_width >= 0xFFFFU )
+ pixel_width = 0xFFFFU;
+ if ( pixel_height >= 0xFFFFU )
+ pixel_height = 0xFFFFU;
+
+ req.type = FT_SIZE_REQUEST_TYPE_NOMINAL;
+ req.width = (FT_Long)( pixel_width << 6 );
+ req.height = (FT_Long)( pixel_height << 6 );
+ req.horiResolution = 0;
+ req.vertResolution = 0;
+
+ return FT_Request_Size( face, &req );
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Get_Kerning( FT_Face face,
+ FT_UInt left_glyph,
+ FT_UInt right_glyph,
+ FT_UInt kern_mode,
+ FT_Vector *akerning )
+ {
+ FT_Error error = FT_Err_Ok;
+ FT_Driver driver;
+
+
+ if ( !face )
+ return FT_THROW( Invalid_Face_Handle );
+
+ if ( !akerning )
+ return FT_THROW( Invalid_Argument );
+
+ driver = face->driver;
+
+ akerning->x = 0;
+ akerning->y = 0;
+
+ if ( driver->clazz->get_kerning )
+ {
+ error = driver->clazz->get_kerning( face,
+ left_glyph,
+ right_glyph,
+ akerning );
+ if ( !error )
+ {
+ if ( kern_mode != FT_KERNING_UNSCALED )
+ {
+ akerning->x = FT_MulFix( akerning->x, face->size->metrics.x_scale );
+ akerning->y = FT_MulFix( akerning->y, face->size->metrics.y_scale );
+
+ if ( kern_mode != FT_KERNING_UNFITTED )
+ {
+ FT_Pos orig_x = akerning->x;
+ FT_Pos orig_y = akerning->y;
+
+
+ /* we scale down kerning values for small ppem values */
+ /* to avoid that rounding makes them too big. */
+ /* `25' has been determined heuristically. */
+ if ( face->size->metrics.x_ppem < 25 )
+ akerning->x = FT_MulDiv( orig_x,
+ face->size->metrics.x_ppem, 25 );
+ if ( face->size->metrics.y_ppem < 25 )
+ akerning->y = FT_MulDiv( orig_y,
+ face->size->metrics.y_ppem, 25 );
+
+ akerning->x = FT_PIX_ROUND( akerning->x );
+ akerning->y = FT_PIX_ROUND( akerning->y );
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+ {
+ FT_Pos orig_x_rounded = FT_PIX_ROUND( orig_x );
+ FT_Pos orig_y_rounded = FT_PIX_ROUND( orig_y );
+
+
+ if ( akerning->x != orig_x_rounded ||
+ akerning->y != orig_y_rounded )
+ FT_TRACE5(( "FT_Get_Kerning: horizontal kerning"
+ " (%ld, %ld) scaled down to (%ld, %ld) pixels\n",
+ orig_x_rounded / 64, orig_y_rounded / 64,
+ akerning->x / 64, akerning->y / 64 ));
+ }
+#endif
+ }
+ }
+ }
+ }
+
+ return error;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Get_Track_Kerning( FT_Face face,
+ FT_Fixed point_size,
+ FT_Int degree,
+ FT_Fixed* akerning )
+ {
+ FT_Service_Kerning service;
+ FT_Error error = FT_Err_Ok;
+
+
+ if ( !face )
+ return FT_THROW( Invalid_Face_Handle );
+
+ if ( !akerning )
+ return FT_THROW( Invalid_Argument );
+
+ FT_FACE_FIND_SERVICE( face, service, KERNING );
+ if ( !service )
+ return FT_THROW( Unimplemented_Feature );
+
+ error = service->get_track( face,
+ point_size,
+ degree,
+ akerning );
+
+ return error;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Select_Charmap( FT_Face face,
+ FT_Encoding encoding )
+ {
+ FT_CharMap* cur;
+ FT_CharMap* limit;
+
+
+ if ( !face )
+ return FT_THROW( Invalid_Face_Handle );
+
+ /* FT_ENCODING_NONE is a valid encoding for BDF, PCF, and Windows FNT */
+ if ( encoding == FT_ENCODING_NONE && !face->num_charmaps )
+ return FT_THROW( Invalid_Argument );
+
+ /* FT_ENCODING_UNICODE is special. We try to find the `best' Unicode */
+ /* charmap available, i.e., one with UCS-4 characters, if possible. */
+ /* */
+ /* This is done by find_unicode_charmap() above, to share code. */
+ if ( encoding == FT_ENCODING_UNICODE )
+ return find_unicode_charmap( face );
+
+ cur = face->charmaps;
+ if ( !cur )
+ return FT_THROW( Invalid_CharMap_Handle );
+
+ limit = cur + face->num_charmaps;
+
+ for ( ; cur < limit; cur++ )
+ {
+ if ( cur[0]->encoding == encoding )
+ {
+ face->charmap = cur[0];
+ return FT_Err_Ok;
+ }
+ }
+
+ return FT_THROW( Invalid_Argument );
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Set_Charmap( FT_Face face,
+ FT_CharMap charmap )
+ {
+ FT_CharMap* cur;
+ FT_CharMap* limit;
+
+
+ if ( !face )
+ return FT_THROW( Invalid_Face_Handle );
+
+ cur = face->charmaps;
+ if ( !cur || !charmap )
+ return FT_THROW( Invalid_CharMap_Handle );
+
+ limit = cur + face->num_charmaps;
+
+ for ( ; cur < limit; cur++ )
+ {
+ if ( cur[0] == charmap &&
+ FT_Get_CMap_Format ( charmap ) != 14 )
+ {
+ face->charmap = cur[0];
+ return FT_Err_Ok;
+ }
+ }
+
+ return FT_THROW( Invalid_Argument );
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Int )
+ FT_Get_Charmap_Index( FT_CharMap charmap )
+ {
+ FT_Int i;
+
+
+ if ( !charmap || !charmap->face )
+ return -1;
+
+ for ( i = 0; i < charmap->face->num_charmaps; i++ )
+ if ( charmap->face->charmaps[i] == charmap )
+ break;
+
+ FT_ASSERT( i < charmap->face->num_charmaps );
+
+ return i;
+ }
+
+
+ static void
+ ft_cmap_done_internal( FT_CMap cmap )
+ {
+ FT_CMap_Class clazz = cmap->clazz;
+ FT_Face face = cmap->charmap.face;
+ FT_Memory memory = FT_FACE_MEMORY( face );
+
+
+ if ( clazz->done )
+ clazz->done( cmap );
+
+ FT_FREE( cmap );
+ }
+
+
+ FT_BASE_DEF( void )
+ FT_CMap_Done( FT_CMap cmap )
+ {
+ if ( cmap )
+ {
+ FT_Face face = cmap->charmap.face;
+ FT_Memory memory = FT_FACE_MEMORY( face );
+ FT_Error error;
+ FT_Int i, j;
+
+
+ for ( i = 0; i < face->num_charmaps; i++ )
+ {
+ if ( (FT_CMap)face->charmaps[i] == cmap )
+ {
+ FT_CharMap last_charmap = face->charmaps[face->num_charmaps - 1];
+
+
+ if ( FT_RENEW_ARRAY( face->charmaps,
+ face->num_charmaps,
+ face->num_charmaps - 1 ) )
+ return;
+
+ /* remove it from our list of charmaps */
+ for ( j = i + 1; j < face->num_charmaps; j++ )
+ {
+ if ( j == face->num_charmaps - 1 )
+ face->charmaps[j - 1] = last_charmap;
+ else
+ face->charmaps[j - 1] = face->charmaps[j];
+ }
+
+ face->num_charmaps--;
+
+ if ( (FT_CMap)face->charmap == cmap )
+ face->charmap = NULL;
+
+ ft_cmap_done_internal( cmap );
+
+ break;
+ }
+ }
+ }
+ }
+
+
+ FT_BASE_DEF( FT_Error )
+ FT_CMap_New( FT_CMap_Class clazz,
+ FT_Pointer init_data,
+ FT_CharMap charmap,
+ FT_CMap *acmap )
+ {
+ FT_Error error = FT_Err_Ok;
+ FT_Face face;
+ FT_Memory memory;
+ FT_CMap cmap = NULL;
+
+
+ if ( !clazz || !charmap || !charmap->face )
+ return FT_THROW( Invalid_Argument );
+
+ face = charmap->face;
+ memory = FT_FACE_MEMORY( face );
+
+ if ( !FT_ALLOC( cmap, clazz->size ) )
+ {
+ cmap->charmap = *charmap;
+ cmap->clazz = clazz;
+
+ if ( clazz->init )
+ {
+ error = clazz->init( cmap, init_data );
+ if ( error )
+ goto Fail;
+ }
+
+ /* add it to our list of charmaps */
+ if ( FT_RENEW_ARRAY( face->charmaps,
+ face->num_charmaps,
+ face->num_charmaps + 1 ) )
+ goto Fail;
+
+ face->charmaps[face->num_charmaps++] = (FT_CharMap)cmap;
+ }
+
+ Exit:
+ if ( acmap )
+ *acmap = cmap;
+
+ return error;
+
+ Fail:
+ ft_cmap_done_internal( cmap );
+ cmap = NULL;
+ goto Exit;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_UInt )
+ FT_Get_Char_Index( FT_Face face,
+ FT_ULong charcode )
+ {
+ FT_UInt result = 0;
+
+
+ if ( face && face->charmap )
+ {
+ FT_CMap cmap = FT_CMAP( face->charmap );
+
+
+ if ( charcode > 0xFFFFFFFFUL )
+ {
+ FT_TRACE1(( "FT_Get_Char_Index: too large charcode" ));
+ FT_TRACE1(( " 0x%lx is truncated\n", charcode ));
+ }
+
+ result = cmap->clazz->char_index( cmap, (FT_UInt32)charcode );
+ if ( result >= (FT_UInt)face->num_glyphs )
+ result = 0;
+ }
+
+ return result;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_ULong )
+ FT_Get_First_Char( FT_Face face,
+ FT_UInt *agindex )
+ {
+ FT_ULong result = 0;
+ FT_UInt gindex = 0;
+
+
+ /* only do something if we have a charmap, and we have glyphs at all */
+ if ( face && face->charmap && face->num_glyphs )
+ {
+ gindex = FT_Get_Char_Index( face, 0 );
+ if ( gindex == 0 )
+ result = FT_Get_Next_Char( face, 0, &gindex );
+ }
+
+ if ( agindex )
+ *agindex = gindex;
+
+ return result;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_ULong )
+ FT_Get_Next_Char( FT_Face face,
+ FT_ULong charcode,
+ FT_UInt *agindex )
+ {
+ FT_ULong result = 0;
+ FT_UInt gindex = 0;
+
+
+ if ( face && face->charmap && face->num_glyphs )
+ {
+ FT_UInt32 code = (FT_UInt32)charcode;
+ FT_CMap cmap = FT_CMAP( face->charmap );
+
+
+ do
+ {
+ gindex = cmap->clazz->char_next( cmap, &code );
+
+ } while ( gindex >= (FT_UInt)face->num_glyphs );
+
+ result = ( gindex == 0 ) ? 0 : code;
+ }
+
+ if ( agindex )
+ *agindex = gindex;
+
+ return result;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Face_Properties( FT_Face face,
+ FT_UInt num_properties,
+ FT_Parameter* properties )
+ {
+ FT_Error error = FT_Err_Ok;
+
+
+ if ( num_properties > 0 && !properties )
+ {
+ error = FT_THROW( Invalid_Argument );
+ goto Exit;
+ }
+
+ for ( ; num_properties > 0; num_properties-- )
+ {
+ if ( properties->tag == FT_PARAM_TAG_STEM_DARKENING )
+ {
+ if ( properties->data )
+ {
+ if ( *( (FT_Bool*)properties->data ) == TRUE )
+ face->internal->no_stem_darkening = FALSE;
+ else
+ face->internal->no_stem_darkening = TRUE;
+ }
+ else
+ {
+ /* use module default */
+ face->internal->no_stem_darkening = -1;
+ }
+ }
+ else if ( properties->tag == FT_PARAM_TAG_LCD_FILTER_WEIGHTS )
+ {
+#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
+ if ( properties->data )
+ {
+ ft_memcpy( face->internal->lcd_weights,
+ properties->data,
+ FT_LCD_FILTER_FIVE_TAPS );
+ face->internal->lcd_filter_func = ft_lcd_filter_fir;
+ }
+#else
+ error = FT_THROW( Unimplemented_Feature );
+ goto Exit;
+#endif
+ }
+ else if ( properties->tag == FT_PARAM_TAG_RANDOM_SEED )
+ {
+ if ( properties->data )
+ {
+ face->internal->random_seed = *( (FT_Int32*)properties->data );
+ if ( face->internal->random_seed < 0 )
+ face->internal->random_seed = 0;
+ }
+ else
+ {
+ /* use module default */
+ face->internal->random_seed = -1;
+ }
+ }
+ else
+ {
+ error = FT_THROW( Invalid_Argument );
+ goto Exit;
+ }
+
+ if ( error )
+ break;
+
+ properties++;
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_UInt )
+ FT_Face_GetCharVariantIndex( FT_Face face,
+ FT_ULong charcode,
+ FT_ULong variantSelector )
+ {
+ FT_UInt result = 0;
+
+
+ if ( face &&
+ face->charmap &&
+ face->charmap->encoding == FT_ENCODING_UNICODE )
+ {
+ FT_CharMap charmap = find_variant_selector_charmap( face );
+ FT_CMap ucmap = FT_CMAP( face->charmap );
+
+
+ if ( charmap )
+ {
+ FT_CMap vcmap = FT_CMAP( charmap );
+
+
+ if ( charcode > 0xFFFFFFFFUL )
+ {
+ FT_TRACE1(( "FT_Face_GetCharVariantIndex:"
+ " too large charcode" ));
+ FT_TRACE1(( " 0x%lx is truncated\n", charcode ));
+ }
+ if ( variantSelector > 0xFFFFFFFFUL )
+ {
+ FT_TRACE1(( "FT_Face_GetCharVariantIndex:"
+ " too large variantSelector" ));
+ FT_TRACE1(( " 0x%lx is truncated\n", variantSelector ));
+ }
+
+ result = vcmap->clazz->char_var_index( vcmap, ucmap,
+ (FT_UInt32)charcode,
+ (FT_UInt32)variantSelector );
+ }
+ }
+
+ return result;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Int )
+ FT_Face_GetCharVariantIsDefault( FT_Face face,
+ FT_ULong charcode,
+ FT_ULong variantSelector )
+ {
+ FT_Int result = -1;
+
+
+ if ( face )
+ {
+ FT_CharMap charmap = find_variant_selector_charmap( face );
+
+
+ if ( charmap )
+ {
+ FT_CMap vcmap = FT_CMAP( charmap );
+
+
+ if ( charcode > 0xFFFFFFFFUL )
+ {
+ FT_TRACE1(( "FT_Face_GetCharVariantIsDefault:"
+ " too large charcode" ));
+ FT_TRACE1(( " 0x%lx is truncated\n", charcode ));
+ }
+ if ( variantSelector > 0xFFFFFFFFUL )
+ {
+ FT_TRACE1(( "FT_Face_GetCharVariantIsDefault:"
+ " too large variantSelector" ));
+ FT_TRACE1(( " 0x%lx is truncated\n", variantSelector ));
+ }
+
+ result = vcmap->clazz->char_var_default( vcmap,
+ (FT_UInt32)charcode,
+ (FT_UInt32)variantSelector );
+ }
+ }
+
+ return result;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_UInt32* )
+ FT_Face_GetVariantSelectors( FT_Face face )
+ {
+ FT_UInt32 *result = NULL;
+
+
+ if ( face )
+ {
+ FT_CharMap charmap = find_variant_selector_charmap( face );
+
+
+ if ( charmap )
+ {
+ FT_CMap vcmap = FT_CMAP( charmap );
+ FT_Memory memory = FT_FACE_MEMORY( face );
+
+
+ result = vcmap->clazz->variant_list( vcmap, memory );
+ }
+ }
+
+ return result;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_UInt32* )
+ FT_Face_GetVariantsOfChar( FT_Face face,
+ FT_ULong charcode )
+ {
+ FT_UInt32 *result = NULL;
+
+
+ if ( face )
+ {
+ FT_CharMap charmap = find_variant_selector_charmap( face );
+
+
+ if ( charmap )
+ {
+ FT_CMap vcmap = FT_CMAP( charmap );
+ FT_Memory memory = FT_FACE_MEMORY( face );
+
+
+ if ( charcode > 0xFFFFFFFFUL )
+ {
+ FT_TRACE1(( "FT_Face_GetVariantsOfChar: too large charcode" ));
+ FT_TRACE1(( " 0x%lx is truncated\n", charcode ));
+ }
+
+ result = vcmap->clazz->charvariant_list( vcmap, memory,
+ (FT_UInt32)charcode );
+ }
+ }
+ return result;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_UInt32* )
+ FT_Face_GetCharsOfVariant( FT_Face face,
+ FT_ULong variantSelector )
+ {
+ FT_UInt32 *result = NULL;
+
+
+ if ( face )
+ {
+ FT_CharMap charmap = find_variant_selector_charmap( face );
+
+
+ if ( charmap )
+ {
+ FT_CMap vcmap = FT_CMAP( charmap );
+ FT_Memory memory = FT_FACE_MEMORY( face );
+
+
+ if ( variantSelector > 0xFFFFFFFFUL )
+ {
+ FT_TRACE1(( "FT_Get_Char_Index: too large variantSelector" ));
+ FT_TRACE1(( " 0x%lx is truncated\n", variantSelector ));
+ }
+
+ result = vcmap->clazz->variantchar_list( vcmap, memory,
+ (FT_UInt32)variantSelector );
+ }
+ }
+
+ return result;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_UInt )
+ FT_Get_Name_Index( FT_Face face,
+ const FT_String* glyph_name )
+ {
+ FT_UInt result = 0;
+
+
+ if ( face &&
+ FT_HAS_GLYPH_NAMES( face ) &&
+ glyph_name )
+ {
+ FT_Service_GlyphDict service;
+
+
+ FT_FACE_LOOKUP_SERVICE( face,
+ service,
+ GLYPH_DICT );
+
+ if ( service && service->name_index )
+ result = service->name_index( face, glyph_name );
+ }
+
+ return result;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Get_Glyph_Name( FT_Face face,
+ FT_UInt glyph_index,
+ FT_Pointer buffer,
+ FT_UInt buffer_max )
+ {
+ FT_Error error;
+ FT_Service_GlyphDict service;
+
+
+ if ( !face )
+ return FT_THROW( Invalid_Face_Handle );
+
+ if ( !buffer || buffer_max == 0 )
+ return FT_THROW( Invalid_Argument );
+
+ /* clean up buffer */
+ ((FT_Byte*)buffer)[0] = '\0';
+
+ if ( (FT_Long)glyph_index >= face->num_glyphs )
+ return FT_THROW( Invalid_Glyph_Index );
+
+ if ( !FT_HAS_GLYPH_NAMES( face ) )
+ return FT_THROW( Invalid_Argument );
+
+ FT_FACE_LOOKUP_SERVICE( face, service, GLYPH_DICT );
+ if ( service && service->get_name )
+ error = service->get_name( face, glyph_index, buffer, buffer_max );
+ else
+ error = FT_THROW( Invalid_Argument );
+
+ return error;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( const char* )
+ FT_Get_Postscript_Name( FT_Face face )
+ {
+ const char* result = NULL;
+
+
+ if ( !face )
+ goto Exit;
+
+ if ( !result )
+ {
+ FT_Service_PsFontName service;
+
+
+ FT_FACE_LOOKUP_SERVICE( face,
+ service,
+ POSTSCRIPT_FONT_NAME );
+
+ if ( service && service->get_ps_font_name )
+ result = service->get_ps_font_name( face );
+ }
+
+ Exit:
+ return result;
+ }
+
+
+ /* documentation is in tttables.h */
+
+ FT_EXPORT_DEF( void* )
+ FT_Get_Sfnt_Table( FT_Face face,
+ FT_Sfnt_Tag tag )
+ {
+ void* table = NULL;
+ FT_Service_SFNT_Table service;
+
+
+ if ( face && FT_IS_SFNT( face ) )
+ {
+ FT_FACE_FIND_SERVICE( face, service, SFNT_TABLE );
+ if ( service )
+ table = service->get_table( face, tag );
+ }
+
+ return table;
+ }
+
+
+ /* documentation is in tttables.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Load_Sfnt_Table( FT_Face face,
+ FT_ULong tag,
+ FT_Long offset,
+ FT_Byte* buffer,
+ FT_ULong* length )
+ {
+ FT_Service_SFNT_Table service;
+
+
+ if ( !face || !FT_IS_SFNT( face ) )
+ return FT_THROW( Invalid_Face_Handle );
+
+ FT_FACE_FIND_SERVICE( face, service, SFNT_TABLE );
+ if ( !service )
+ return FT_THROW( Unimplemented_Feature );
+
+ return service->load_table( face, tag, offset, buffer, length );
+ }
+
+
+ /* documentation is in tttables.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Sfnt_Table_Info( FT_Face face,
+ FT_UInt table_index,
+ FT_ULong *tag,
+ FT_ULong *length )
+ {
+ FT_Service_SFNT_Table service;
+ FT_ULong offset;
+
+
+ /* test for valid `length' delayed to `service->table_info' */
+
+ if ( !face || !FT_IS_SFNT( face ) )
+ return FT_THROW( Invalid_Face_Handle );
+
+ FT_FACE_FIND_SERVICE( face, service, SFNT_TABLE );
+ if ( !service )
+ return FT_THROW( Unimplemented_Feature );
+
+ return service->table_info( face, table_index, tag, &offset, length );
+ }
+
+
+ /* documentation is in tttables.h */
+
+ FT_EXPORT_DEF( FT_ULong )
+ FT_Get_CMap_Language_ID( FT_CharMap charmap )
+ {
+ FT_Service_TTCMaps service;
+ FT_Face face;
+ TT_CMapInfo cmap_info;
+
+
+ if ( !charmap || !charmap->face )
+ return 0;
+
+ face = charmap->face;
+ FT_FACE_FIND_SERVICE( face, service, TT_CMAP );
+ if ( !service )
+ return 0;
+ if ( service->get_cmap_info( charmap, &cmap_info ))
+ return 0;
+
+ return cmap_info.language;
+ }
+
+
+ /* documentation is in tttables.h */
+
+ FT_EXPORT_DEF( FT_Long )
+ FT_Get_CMap_Format( FT_CharMap charmap )
+ {
+ FT_Service_TTCMaps service;
+ FT_Face face;
+ TT_CMapInfo cmap_info;
+
+
+ if ( !charmap || !charmap->face )
+ return -1;
+
+ face = charmap->face;
+ FT_FACE_FIND_SERVICE( face, service, TT_CMAP );
+ if ( !service )
+ return -1;
+ if ( service->get_cmap_info( charmap, &cmap_info ))
+ return -1;
+
+ return cmap_info.format;
+ }
+
+
+ /* documentation is in ftsizes.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Activate_Size( FT_Size size )
+ {
+ FT_Face face;
+
+
+ if ( !size )
+ return FT_THROW( Invalid_Size_Handle );
+
+ face = size->face;
+ if ( !face || !face->driver )
+ return FT_THROW( Invalid_Face_Handle );
+
+ /* we don't need anything more complex than that; all size objects */
+ /* are already listed by the face */
+ face->size = size;
+
+ return FT_Err_Ok;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** ****/
+ /**** R E N D E R E R S ****/
+ /**** ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /* lookup a renderer by glyph format in the library's list */
+ FT_BASE_DEF( FT_Renderer )
+ FT_Lookup_Renderer( FT_Library library,
+ FT_Glyph_Format format,
+ FT_ListNode* node )
+ {
+ FT_ListNode cur;
+ FT_Renderer result = NULL;
+
+
+ if ( !library )
+ goto Exit;
+
+ cur = library->renderers.head;
+
+ if ( node )
+ {
+ if ( *node )
+ cur = (*node)->next;
+ *node = NULL;
+ }
+
+ while ( cur )
+ {
+ FT_Renderer renderer = FT_RENDERER( cur->data );
+
+
+ if ( renderer->glyph_format == format )
+ {
+ if ( node )
+ *node = cur;
+
+ result = renderer;
+ break;
+ }
+ cur = cur->next;
+ }
+
+ Exit:
+ return result;
+ }
+
+
+ static FT_Renderer
+ ft_lookup_glyph_renderer( FT_GlyphSlot slot )
+ {
+ FT_Face face = slot->face;
+ FT_Library library = FT_FACE_LIBRARY( face );
+ FT_Renderer result = library->cur_renderer;
+
+
+ if ( !result || result->glyph_format != slot->format )
+ result = FT_Lookup_Renderer( library, slot->format, 0 );
+
+ return result;
+ }
+
+
+ static void
+ ft_set_current_renderer( FT_Library library )
+ {
+ FT_Renderer renderer;
+
+
+ renderer = FT_Lookup_Renderer( library, FT_GLYPH_FORMAT_OUTLINE, 0 );
+ library->cur_renderer = renderer;
+ }
+
+
+ static FT_Error
+ ft_add_renderer( FT_Module module )
+ {
+ FT_Library library = module->library;
+ FT_Memory memory = library->memory;
+ FT_Error error;
+ FT_ListNode node = NULL;
+
+
+ if ( FT_NEW( node ) )
+ goto Exit;
+
+ {
+ FT_Renderer render = FT_RENDERER( module );
+ FT_Renderer_Class* clazz = (FT_Renderer_Class*)module->clazz;
+
+
+ render->clazz = clazz;
+ render->glyph_format = clazz->glyph_format;
+
+ /* allocate raster object if needed */
+ if ( clazz->raster_class->raster_new )
+ {
+ error = clazz->raster_class->raster_new( memory, &render->raster );
+ if ( error )
+ goto Fail;
+
+ render->raster_render = clazz->raster_class->raster_render;
+ render->render = clazz->render_glyph;
+ }
+
+ /* add to list */
+ node->data = module;
+ FT_List_Add( &library->renderers, node );
+
+ ft_set_current_renderer( library );
+ }
+
+ Fail:
+ if ( error )
+ FT_FREE( node );
+
+ Exit:
+ return error;
+ }
+
+
+ static void
+ ft_remove_renderer( FT_Module module )
+ {
+ FT_Library library;
+ FT_Memory memory;
+ FT_ListNode node;
+
+
+ library = module->library;
+ if ( !library )
+ return;
+
+ memory = library->memory;
+
+ node = FT_List_Find( &library->renderers, module );
+ if ( node )
+ {
+ FT_Renderer render = FT_RENDERER( module );
+
+
+ /* release raster object, if any */
+ if ( render->raster )
+ render->clazz->raster_class->raster_done( render->raster );
+
+ /* remove from list */
+ FT_List_Remove( &library->renderers, node );
+ FT_FREE( node );
+
+ ft_set_current_renderer( library );
+ }
+ }
+
+
+ /* documentation is in ftrender.h */
+
+ FT_EXPORT_DEF( FT_Renderer )
+ FT_Get_Renderer( FT_Library library,
+ FT_Glyph_Format format )
+ {
+ /* test for valid `library' delayed to `FT_Lookup_Renderer' */
+
+ return FT_Lookup_Renderer( library, format, 0 );
+ }
+
+
+ /* documentation is in ftrender.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Set_Renderer( FT_Library library,
+ FT_Renderer renderer,
+ FT_UInt num_params,
+ FT_Parameter* parameters )
+ {
+ FT_ListNode node;
+ FT_Error error = FT_Err_Ok;
+
+ FT_Renderer_SetModeFunc set_mode;
+
+
+ if ( !library )
+ {
+ error = FT_THROW( Invalid_Library_Handle );
+ goto Exit;
+ }
+
+ if ( !renderer )
+ {
+ error = FT_THROW( Invalid_Argument );
+ goto Exit;
+ }
+
+ if ( num_params > 0 && !parameters )
+ {
+ error = FT_THROW( Invalid_Argument );
+ goto Exit;
+ }
+
+ node = FT_List_Find( &library->renderers, renderer );
+ if ( !node )
+ {
+ error = FT_THROW( Invalid_Argument );
+ goto Exit;
+ }
+
+ FT_List_Up( &library->renderers, node );
+
+ if ( renderer->glyph_format == FT_GLYPH_FORMAT_OUTLINE )
+ library->cur_renderer = renderer;
+
+ set_mode = renderer->clazz->set_mode;
+
+ for ( ; num_params > 0; num_params-- )
+ {
+ error = set_mode( renderer, parameters->tag, parameters->data );
+ if ( error )
+ break;
+ parameters++;
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ FT_BASE_DEF( FT_Error )
+ FT_Render_Glyph_Internal( FT_Library library,
+ FT_GlyphSlot slot,
+ FT_Render_Mode render_mode )
+ {
+ FT_Error error = FT_Err_Ok;
+ FT_Face face = slot->face;
+ FT_Renderer renderer;
+
+
+ switch ( slot->format )
+ {
+ default:
+ if ( slot->internal->load_flags & FT_LOAD_COLOR )
+ {
+ FT_LayerIterator iterator;
+
+ FT_UInt base_glyph = slot->glyph_index;
+
+ FT_Bool have_layers;
+ FT_UInt glyph_index;
+ FT_UInt color_index;
+
+
+ /* check whether we have colored glyph layers */
+ iterator.p = NULL;
+ have_layers = FT_Get_Color_Glyph_Layer( face,
+ base_glyph,
+ &glyph_index,
+ &color_index,
+ &iterator );
+ if ( have_layers )
+ {
+ error = FT_New_GlyphSlot( face, NULL );
+ if ( !error )
+ {
+ TT_Face ttface = (TT_Face)face;
+ SFNT_Service sfnt = (SFNT_Service)ttface->sfnt;
+
+
+ do
+ {
+ FT_Int32 load_flags = slot->internal->load_flags;
+
+
+ /* disable the `FT_LOAD_COLOR' flag to avoid recursion */
+ /* right here in this function */
+ load_flags &= ~FT_LOAD_COLOR;
+
+ /* render into the new `face->glyph' glyph slot */
+ load_flags |= FT_LOAD_RENDER;
+
+ error = FT_Load_Glyph( face, glyph_index, load_flags );
+ if ( error )
+ break;
+
+ /* blend new `face->glyph' into old `slot'; */
+ /* at the first call, `slot' is still empty */
+ error = sfnt->colr_blend( ttface,
+ color_index,
+ slot,
+ face->glyph );
+ if ( error )
+ break;
+
+ } while ( FT_Get_Color_Glyph_Layer( face,
+ base_glyph,
+ &glyph_index,
+ &color_index,
+ &iterator ) );
+
+ if ( !error )
+ slot->format = FT_GLYPH_FORMAT_BITMAP;
+
+ /* this call also restores `slot' as the glyph slot */
+ FT_Done_GlyphSlot( face->glyph );
+ }
+
+ if ( !error )
+ return error;
+
+ /* Failed to do the colored layer. Draw outline instead. */
+ slot->format = FT_GLYPH_FORMAT_OUTLINE;
+ }
+ }
+
+ {
+ FT_ListNode node = NULL;
+
+
+ /* small shortcut for the very common case */
+ if ( slot->format == FT_GLYPH_FORMAT_OUTLINE )
+ {
+ renderer = library->cur_renderer;
+ node = library->renderers.head;
+ }
+ else
+ renderer = FT_Lookup_Renderer( library, slot->format, &node );
+
+ error = FT_ERR( Cannot_Render_Glyph );
+ while ( renderer )
+ {
+ error = renderer->render( renderer, slot, render_mode, NULL );
+ if ( !error ||
+ FT_ERR_NEQ( error, Cannot_Render_Glyph ) )
+ break;
+
+ /* FT_Err_Cannot_Render_Glyph is returned if the render mode */
+ /* is unsupported by the current renderer for this glyph image */
+ /* format. */
+
+ /* now, look for another renderer that supports the same */
+ /* format. */
+ renderer = FT_Lookup_Renderer( library, slot->format, &node );
+ }
+
+ /* it is not an error if we cannot render a bitmat glyph */
+ if ( FT_ERR_EQ( error, Cannot_Render_Glyph ) &&
+ slot->format == FT_GLYPH_FORMAT_BITMAP )
+ error = FT_Err_Ok;
+ }
+ }
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+
+#undef FT_COMPONENT
+#define FT_COMPONENT checksum
+
+ /*
+ * Computing the MD5 checksum is expensive, unnecessarily distorting a
+ * possible profiling of FreeType if compiled with tracing support. For
+ * this reason, we execute the following code only if explicitly
+ * requested.
+ */
+
+ /* we use FT_TRACE3 in this block */
+ if ( !error &&
+ ft_trace_levels[trace_checksum] >= 3 &&
+ slot->bitmap.buffer )
+ {
+ FT_Bitmap bitmap;
+ FT_Error err;
+
+
+ FT_Bitmap_Init( &bitmap );
+
+ /* we convert to a single bitmap format for computing the checksum */
+ /* this also converts the bitmap flow to `down' (i.e., pitch > 0) */
+ err = FT_Bitmap_Convert( library, &slot->bitmap, &bitmap, 1 );
+ if ( !err )
+ {
+ MD5_CTX ctx;
+ unsigned char md5[16];
+ unsigned long coverage = 0;
+ int i, j;
+ int rows = (int)bitmap.rows;
+ int pitch = bitmap.pitch;
+
+
+ FT_TRACE3(( "FT_Render_Glyph: bitmap %dx%d, %s (mode %d)\n",
+ pitch,
+ rows,
+ pixel_modes[slot->bitmap.pixel_mode],
+ slot->bitmap.pixel_mode ));
+
+ for ( i = 0; i < rows; i++ )
+ for ( j = 0; j < pitch; j++ )
+ coverage += bitmap.buffer[i * pitch + j];
+
+ FT_TRACE3(( " Total coverage: %lu\n", coverage ));
+
+ MD5_Init( &ctx );
+ if ( bitmap.buffer )
+ MD5_Update( &ctx, bitmap.buffer,
+ (unsigned long)rows * (unsigned long)pitch );
+ MD5_Final( md5, &ctx );
+
+ FT_TRACE3(( " MD5 checksum: " ));
+ for ( i = 0; i < 16; i++ )
+ FT_TRACE3(( "%02X", md5[i] ));
+ FT_TRACE3(( "\n" ));
+ }
+
+ FT_Bitmap_Done( library, &bitmap );
+ }
+
+ /*
+ * Dump bitmap in Netpbm format (PBM or PGM).
+ */
+
+ /* we use FT_TRACE7 in this block */
+ if ( !error &&
+ ft_trace_levels[trace_checksum] >= 7 &&
+ slot->bitmap.buffer )
+ {
+ if ( slot->bitmap.rows < 128U &&
+ slot->bitmap.width < 128U )
+ {
+ int rows = (int)slot->bitmap.rows;
+ int width = (int)slot->bitmap.width;
+ int pitch = slot->bitmap.pitch;
+ int i, j, m;
+
+ unsigned char* topleft = slot->bitmap.buffer;
+
+
+ if ( pitch < 0 )
+ topleft -= pitch * ( rows - 1 );
+
+ FT_TRACE7(( "Netpbm image: start\n" ));
+ switch ( slot->bitmap.pixel_mode )
+ {
+ case FT_PIXEL_MODE_MONO:
+ FT_TRACE7(( "P1 %d %d\n", width, rows ));
+ for ( i = 0; i < rows; i++ )
+ {
+ for ( j = 0; j < width; )
+ for ( m = 128; m > 0 && j < width; m >>= 1, j++ )
+ FT_TRACE7(( " %d",
+ ( topleft[i * pitch + j / 8] & m ) != 0 ));
+ FT_TRACE7(( "\n" ));
+ }
+ break;
+
+ default:
+ FT_TRACE7(( "P2 %d %d 255\n", width, rows ));
+ for ( i = 0; i < rows; i++ )
+ {
+ for ( j = 0; j < width; j += 1 )
+ FT_TRACE7(( " %3u", topleft[i * pitch + j] ));
+ FT_TRACE7(( "\n" ));
+ }
+ }
+ FT_TRACE7(( "Netpbm image: end\n" ));
+ }
+ else
+ FT_TRACE7(( "Netpbm image: too large, omitted\n" ));
+ }
+
+#undef FT_COMPONENT
+#define FT_COMPONENT objs
+
+#endif /* FT_DEBUG_LEVEL_TRACE */
+
+ return error;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Render_Glyph( FT_GlyphSlot slot,
+ FT_Render_Mode render_mode )
+ {
+ FT_Library library;
+
+
+ if ( !slot || !slot->face )
+ return FT_THROW( Invalid_Argument );
+
+ library = FT_FACE_LIBRARY( slot->face );
+
+ return FT_Render_Glyph_Internal( library, slot, render_mode );
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** ****/
+ /**** M O D U L E S ****/
+ /**** ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /**************************************************************************
+ *
+ * @Function:
+ * Destroy_Module
+ *
+ * @Description:
+ * Destroys a given module object. For drivers, this also destroys
+ * all child faces.
+ *
+ * @InOut:
+ * module ::
+ * A handle to the target driver object.
+ *
+ * @Note:
+ * The driver _must_ be LOCKED!
+ */
+ static void
+ Destroy_Module( FT_Module module )
+ {
+ FT_Memory memory = module->memory;
+ FT_Module_Class* clazz = module->clazz;
+ FT_Library library = module->library;
+
+
+ if ( library && library->auto_hinter == module )
+ library->auto_hinter = NULL;
+
+ /* if the module is a renderer */
+ if ( FT_MODULE_IS_RENDERER( module ) )
+ ft_remove_renderer( module );
+
+ /* if the module is a font driver, add some steps */
+ if ( FT_MODULE_IS_DRIVER( module ) )
+ Destroy_Driver( FT_DRIVER( module ) );
+
+ /* finalize the module object */
+ if ( clazz->module_done )
+ clazz->module_done( module );
+
+ /* discard it */
+ FT_FREE( module );
+ }
+
+
+ /* documentation is in ftmodapi.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Add_Module( FT_Library library,
+ const FT_Module_Class* clazz )
+ {
+ FT_Error error;
+ FT_Memory memory;
+ FT_Module module = NULL;
+ FT_UInt nn;
+
+
+#define FREETYPE_VER_FIXED ( ( (FT_Long)FREETYPE_MAJOR << 16 ) | \
+ FREETYPE_MINOR )
+
+ if ( !library )
+ return FT_THROW( Invalid_Library_Handle );
+
+ if ( !clazz )
+ return FT_THROW( Invalid_Argument );
+
+ /* check FreeType version */
+ if ( clazz->module_requires > FREETYPE_VER_FIXED )
+ return FT_THROW( Invalid_Version );
+
+ /* look for a module with the same name in the library's table */
+ for ( nn = 0; nn < library->num_modules; nn++ )
+ {
+ module = library->modules[nn];
+ if ( ft_strcmp( module->clazz->module_name, clazz->module_name ) == 0 )
+ {
+ /* this installed module has the same name, compare their versions */
+ if ( clazz->module_version <= module->clazz->module_version )
+ return FT_THROW( Lower_Module_Version );
+
+ /* remove the module from our list, then exit the loop to replace */
+ /* it by our new version.. */
+ FT_Remove_Module( library, module );
+ break;
+ }
+ }
+
+ memory = library->memory;
+ error = FT_Err_Ok;
+
+ if ( library->num_modules >= FT_MAX_MODULES )
+ {
+ error = FT_THROW( Too_Many_Drivers );
+ goto Exit;
+ }
+
+ /* allocate module object */
+ if ( FT_ALLOC( module, clazz->module_size ) )
+ goto Exit;
+
+ /* base initialization */
+ module->library = library;
+ module->memory = memory;
+ module->clazz = (FT_Module_Class*)clazz;
+
+ /* check whether the module is a renderer - this must be performed */
+ /* before the normal module initialization */
+ if ( FT_MODULE_IS_RENDERER( module ) )
+ {
+ /* add to the renderers list */
+ error = ft_add_renderer( module );
+ if ( error )
+ goto Fail;
+ }
+
+ /* is the module a auto-hinter? */
+ if ( FT_MODULE_IS_HINTER( module ) )
+ library->auto_hinter = module;
+
+ /* if the module is a font driver */
+ if ( FT_MODULE_IS_DRIVER( module ) )
+ {
+ FT_Driver driver = FT_DRIVER( module );
+
+
+ driver->clazz = (FT_Driver_Class)module->clazz;
+ }
+
+ if ( clazz->module_init )
+ {
+ error = clazz->module_init( module );
+ if ( error )
+ goto Fail;
+ }
+
+ /* add module to the library's table */
+ library->modules[library->num_modules++] = module;
+
+ Exit:
+ return error;
+
+ Fail:
+ if ( FT_MODULE_IS_RENDERER( module ) )
+ {
+ FT_Renderer renderer = FT_RENDERER( module );
+
+
+ if ( renderer->clazz &&
+ renderer->clazz->glyph_format == FT_GLYPH_FORMAT_OUTLINE &&
+ renderer->raster )
+ renderer->clazz->raster_class->raster_done( renderer->raster );
+ }
+
+ FT_FREE( module );
+ goto Exit;
+ }
+
+
+ /* documentation is in ftmodapi.h */
+
+ FT_EXPORT_DEF( FT_Module )
+ FT_Get_Module( FT_Library library,
+ const char* module_name )
+ {
+ FT_Module result = NULL;
+ FT_Module* cur;
+ FT_Module* limit;
+
+
+ if ( !library || !module_name )
+ return result;
+
+ cur = library->modules;
+ limit = cur + library->num_modules;
+
+ for ( ; cur < limit; cur++ )
+ if ( ft_strcmp( cur[0]->clazz->module_name, module_name ) == 0 )
+ {
+ result = cur[0];
+ break;
+ }
+
+ return result;
+ }
+
+
+ /* documentation is in ftobjs.h */
+
+ FT_BASE_DEF( const void* )
+ FT_Get_Module_Interface( FT_Library library,
+ const char* mod_name )
+ {
+ FT_Module module;
+
+
+ /* test for valid `library' delayed to FT_Get_Module() */
+
+ module = FT_Get_Module( library, mod_name );
+
+ return module ? module->clazz->module_interface : 0;
+ }
+
+
+ FT_BASE_DEF( FT_Pointer )
+ ft_module_get_service( FT_Module module,
+ const char* service_id,
+ FT_Bool global )
+ {
+ FT_Pointer result = NULL;
+
+
+ if ( module )
+ {
+ FT_ASSERT( module->clazz && module->clazz->get_interface );
+
+ /* first, look for the service in the module */
+ if ( module->clazz->get_interface )
+ result = module->clazz->get_interface( module, service_id );
+
+ if ( global && !result )
+ {
+ /* we didn't find it, look in all other modules then */
+ FT_Library library = module->library;
+ FT_Module* cur = library->modules;
+ FT_Module* limit = cur + library->num_modules;
+
+
+ for ( ; cur < limit; cur++ )
+ {
+ if ( cur[0] != module )
+ {
+ FT_ASSERT( cur[0]->clazz );
+
+ if ( cur[0]->clazz->get_interface )
+ {
+ result = cur[0]->clazz->get_interface( cur[0], service_id );
+ if ( result )
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
+
+ /* documentation is in ftmodapi.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Remove_Module( FT_Library library,
+ FT_Module module )
+ {
+ /* try to find the module from the table, then remove it from there */
+
+ if ( !library )
+ return FT_THROW( Invalid_Library_Handle );
+
+ if ( module )
+ {
+ FT_Module* cur = library->modules;
+ FT_Module* limit = cur + library->num_modules;
+
+
+ for ( ; cur < limit; cur++ )
+ {
+ if ( cur[0] == module )
+ {
+ /* remove it from the table */
+ library->num_modules--;
+ limit--;
+ while ( cur < limit )
+ {
+ cur[0] = cur[1];
+ cur++;
+ }
+ limit[0] = NULL;
+
+ /* destroy the module */
+ Destroy_Module( module );
+
+ return FT_Err_Ok;
+ }
+ }
+ }
+ return FT_THROW( Invalid_Driver_Handle );
+ }
+
+
+ static FT_Error
+ ft_property_do( FT_Library library,
+ const FT_String* module_name,
+ const FT_String* property_name,
+ void* value,
+ FT_Bool set,
+ FT_Bool value_is_string )
+ {
+ FT_Module* cur;
+ FT_Module* limit;
+ FT_Module_Interface interface;
+
+ FT_Service_Properties service;
+
+#ifdef FT_DEBUG_LEVEL_ERROR
+ const FT_String* set_name = "FT_Property_Set";
+ const FT_String* get_name = "FT_Property_Get";
+ const FT_String* func_name = set ? set_name : get_name;
+#endif
+
+ FT_Bool missing_func;
+
+
+ if ( !library )
+ return FT_THROW( Invalid_Library_Handle );
+
+ if ( !module_name || !property_name || !value )
+ return FT_THROW( Invalid_Argument );
+
+ cur = library->modules;
+ limit = cur + library->num_modules;
+
+ /* search module */
+ for ( ; cur < limit; cur++ )
+ if ( !ft_strcmp( cur[0]->clazz->module_name, module_name ) )
+ break;
+
+ if ( cur == limit )
+ {
+ FT_TRACE2(( "%s: can't find module `%s'\n",
+ func_name, module_name ));
+ return FT_THROW( Missing_Module );
+ }
+
+ /* check whether we have a service interface */
+ if ( !cur[0]->clazz->get_interface )
+ {
+ FT_TRACE2(( "%s: module `%s' doesn't support properties\n",
+ func_name, module_name ));
+ return FT_THROW( Unimplemented_Feature );
+ }
+
+ /* search property service */
+ interface = cur[0]->clazz->get_interface( cur[0],
+ FT_SERVICE_ID_PROPERTIES );
+ if ( !interface )
+ {
+ FT_TRACE2(( "%s: module `%s' doesn't support properties\n",
+ func_name, module_name ));
+ return FT_THROW( Unimplemented_Feature );
+ }
+
+ service = (FT_Service_Properties)interface;
+
+ if ( set )
+ missing_func = FT_BOOL( !service->set_property );
+ else
+ missing_func = FT_BOOL( !service->get_property );
+
+ if ( missing_func )
+ {
+ FT_TRACE2(( "%s: property service of module `%s' is broken\n",
+ func_name, module_name ));
+ return FT_THROW( Unimplemented_Feature );
+ }
+
+ return set ? service->set_property( cur[0],
+ property_name,
+ value,
+ value_is_string )
+ : service->get_property( cur[0],
+ property_name,
+ value );
+ }
+
+
+ /* documentation is in ftmodapi.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Property_Set( FT_Library library,
+ const FT_String* module_name,
+ const FT_String* property_name,
+ const void* value )
+ {
+ return ft_property_do( library,
+ module_name,
+ property_name,
+ (void*)value,
+ TRUE,
+ FALSE );
+ }
+
+
+ /* documentation is in ftmodapi.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Property_Get( FT_Library library,
+ const FT_String* module_name,
+ const FT_String* property_name,
+ void* value )
+ {
+ return ft_property_do( library,
+ module_name,
+ property_name,
+ value,
+ FALSE,
+ FALSE );
+ }
+
+
+#ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES
+
+ /* this variant is used for handling the FREETYPE_PROPERTIES */
+ /* environment variable */
+
+ FT_BASE_DEF( FT_Error )
+ ft_property_string_set( FT_Library library,
+ const FT_String* module_name,
+ const FT_String* property_name,
+ FT_String* value )
+ {
+ return ft_property_do( library,
+ module_name,
+ property_name,
+ (void*)value,
+ TRUE,
+ TRUE );
+ }
+
+#endif
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** ****/
+ /**** L I B R A R Y ****/
+ /**** ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /* documentation is in ftmodapi.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Reference_Library( FT_Library library )
+ {
+ if ( !library )
+ return FT_THROW( Invalid_Library_Handle );
+
+ library->refcount++;
+
+ return FT_Err_Ok;
+ }
+
+
+ /* documentation is in ftmodapi.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_New_Library( FT_Memory memory,
+ FT_Library *alibrary )
+ {
+ FT_Library library = NULL;
+ FT_Error error;
+
+
+ if ( !memory || !alibrary )
+ return FT_THROW( Invalid_Argument );
+
+#ifndef FT_DEBUG_LOGGING
+#ifdef FT_DEBUG_LEVEL_ERROR
+ /* init debugging support */
+ ft_debug_init();
+#endif /* FT_DEBUG_LEVEL_ERROR */
+#endif /* !FT_DEBUG_LOGGING */
+
+ /* first of all, allocate the library object */
+ if ( FT_NEW( library ) )
+ return error;
+
+ library->memory = memory;
+
+ library->version_major = FREETYPE_MAJOR;
+ library->version_minor = FREETYPE_MINOR;
+ library->version_patch = FREETYPE_PATCH;
+
+ library->refcount = 1;
+
+ /* That's ok now */
+ *alibrary = library;
+
+ return FT_Err_Ok;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( void )
+ FT_Library_Version( FT_Library library,
+ FT_Int *amajor,
+ FT_Int *aminor,
+ FT_Int *apatch )
+ {
+ FT_Int major = 0;
+ FT_Int minor = 0;
+ FT_Int patch = 0;
+
+
+ if ( library )
+ {
+ major = library->version_major;
+ minor = library->version_minor;
+ patch = library->version_patch;
+ }
+
+ if ( amajor )
+ *amajor = major;
+
+ if ( aminor )
+ *aminor = minor;
+
+ if ( apatch )
+ *apatch = patch;
+ }
+
+
+ /* documentation is in ftmodapi.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Done_Library( FT_Library library )
+ {
+ FT_Memory memory;
+
+
+ if ( !library )
+ return FT_THROW( Invalid_Library_Handle );
+
+ library->refcount--;
+ if ( library->refcount > 0 )
+ goto Exit;
+
+ memory = library->memory;
+
+ /*
+ * Close all faces in the library. If we don't do this, we can have
+ * some subtle memory leaks.
+ *
+ * Example:
+ *
+ * - the cff font driver uses the pshinter module in cff_size_done
+ * - if the pshinter module is destroyed before the cff font driver,
+ * opened FT_Face objects managed by the driver are not properly
+ * destroyed, resulting in a memory leak
+ *
+ * Some faces are dependent on other faces, like Type42 faces that
+ * depend on TrueType faces synthesized internally.
+ *
+ * The order of drivers should be specified in driver_name[].
+ */
+ {
+ FT_UInt m, n;
+ const char* driver_name[] = { "type42", NULL };
+
+
+ for ( m = 0;
+ m < sizeof ( driver_name ) / sizeof ( driver_name[0] );
+ m++ )
+ {
+ for ( n = 0; n < library->num_modules; n++ )
+ {
+ FT_Module module = library->modules[n];
+ const char* module_name = module->clazz->module_name;
+ FT_List faces;
+
+
+ if ( driver_name[m] &&
+ ft_strcmp( module_name, driver_name[m] ) != 0 )
+ continue;
+
+ if ( ( module->clazz->module_flags & FT_MODULE_FONT_DRIVER ) == 0 )
+ continue;
+
+ FT_TRACE7(( "FT_Done_Library: close faces for %s\n", module_name ));
+
+ faces = &FT_DRIVER( module )->faces_list;
+ while ( faces->head )
+ {
+ FT_Done_Face( FT_FACE( faces->head->data ) );
+ if ( faces->head )
+ FT_TRACE0(( "FT_Done_Library: failed to free some faces\n" ));
+ }
+ }
+ }
+ }
+
+ /* Close all other modules in the library */
+#if 1
+ /* XXX Modules are removed in the reversed order so that */
+ /* type42 module is removed before truetype module. This */
+ /* avoids double free in some occasions. It is a hack. */
+ while ( library->num_modules > 0 )
+ FT_Remove_Module( library,
+ library->modules[library->num_modules - 1] );
+#else
+ {
+ FT_UInt n;
+
+
+ for ( n = 0; n < library->num_modules; n++ )
+ {
+ FT_Module module = library->modules[n];
+
+
+ if ( module )
+ {
+ Destroy_Module( module );
+ library->modules[n] = NULL;
+ }
+ }
+ }
+#endif
+
+ FT_FREE( library );
+
+ Exit:
+ return FT_Err_Ok;
+ }
+
+
+ /* documentation is in ftmodapi.h */
+
+ FT_EXPORT_DEF( void )
+ FT_Set_Debug_Hook( FT_Library library,
+ FT_UInt hook_index,
+ FT_DebugHook_Func debug_hook )
+ {
+ if ( library && debug_hook &&
+ hook_index <
+ ( sizeof ( library->debug_hooks ) / sizeof ( void* ) ) )
+ library->debug_hooks[hook_index] = debug_hook;
+ }
+
+
+ /* documentation is in ftmodapi.h */
+
+ FT_EXPORT_DEF( FT_TrueTypeEngineType )
+ FT_Get_TrueType_Engine_Type( FT_Library library )
+ {
+ FT_TrueTypeEngineType result = FT_TRUETYPE_ENGINE_TYPE_NONE;
+
+
+ if ( library )
+ {
+ FT_Module module = FT_Get_Module( library, "truetype" );
+
+
+ if ( module )
+ {
+ FT_Service_TrueTypeEngine service;
+
+
+ service = (FT_Service_TrueTypeEngine)
+ ft_module_get_service( module,
+ FT_SERVICE_ID_TRUETYPE_ENGINE,
+ 0 );
+ if ( service )
+ result = service->engine_type;
+ }
+ }
+
+ return result;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Get_SubGlyph_Info( FT_GlyphSlot glyph,
+ FT_UInt sub_index,
+ FT_Int *p_index,
+ FT_UInt *p_flags,
+ FT_Int *p_arg1,
+ FT_Int *p_arg2,
+ FT_Matrix *p_transform )
+ {
+ FT_Error error = FT_ERR( Invalid_Argument );
+
+
+ if ( glyph &&
+ glyph->subglyphs &&
+ glyph->format == FT_GLYPH_FORMAT_COMPOSITE &&
+ sub_index < glyph->num_subglyphs )
+ {
+ FT_SubGlyph subg = glyph->subglyphs + sub_index;
+
+
+ *p_index = subg->index;
+ *p_flags = subg->flags;
+ *p_arg1 = subg->arg1;
+ *p_arg2 = subg->arg2;
+ *p_transform = subg->transform;
+
+ error = FT_Err_Ok;
+ }
+
+ return error;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Bool )
+ FT_Get_Color_Glyph_Layer( FT_Face face,
+ FT_UInt base_glyph,
+ FT_UInt *aglyph_index,
+ FT_UInt *acolor_index,
+ FT_LayerIterator* iterator )
+ {
+ TT_Face ttface;
+ SFNT_Service sfnt;
+
+
+ if ( !face ||
+ !aglyph_index ||
+ !acolor_index ||
+ !iterator ||
+ base_glyph >= (FT_UInt)face->num_glyphs )
+ return 0;
+
+ if ( !FT_IS_SFNT( face ) )
+ return 0;
+
+ ttface = (TT_Face)face;
+ sfnt = (SFNT_Service)ttface->sfnt;
+
+ if ( sfnt->get_colr_layer )
+ return sfnt->get_colr_layer( ttface,
+ base_glyph,
+ aglyph_index,
+ acolor_index,
+ iterator );
+ else
+ return 0;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Bool )
+ FT_Get_Color_Glyph_Paint( FT_Face face,
+ FT_UInt base_glyph,
+ FT_Color_Root_Transform root_transform,
+ FT_OpaquePaint* paint )
+ {
+ TT_Face ttface;
+ SFNT_Service sfnt;
+
+
+ if ( !face || !paint )
+ return 0;
+
+ if ( !FT_IS_SFNT( face ) )
+ return 0;
+
+ ttface = (TT_Face)face;
+ sfnt = (SFNT_Service)ttface->sfnt;
+
+ if ( sfnt->get_colr_layer )
+ return sfnt->get_colr_glyph_paint( ttface,
+ base_glyph,
+ root_transform,
+ paint );
+ else
+ return 0;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Bool )
+ FT_Get_Paint_Layers( FT_Face face,
+ FT_LayerIterator* layer_iterator,
+ FT_OpaquePaint* paint )
+ {
+ TT_Face ttface;
+ SFNT_Service sfnt;
+
+
+ if ( !face || !paint || !layer_iterator )
+ return 0;
+
+ if ( !FT_IS_SFNT( face ) )
+ return 0;
+
+ ttface = (TT_Face)face;
+ sfnt = (SFNT_Service)ttface->sfnt;
+
+ if ( sfnt->get_paint_layers )
+ return sfnt->get_paint_layers( ttface, layer_iterator, paint );
+ else
+ return 0;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Bool )
+ FT_Get_Paint( FT_Face face,
+ FT_OpaquePaint opaque_paint,
+ FT_COLR_Paint* paint )
+ {
+ TT_Face ttface;
+ SFNT_Service sfnt;
+
+
+ if ( !face || !paint || !paint )
+ return 0;
+
+ if ( !FT_IS_SFNT( face ) )
+ return 0;
+
+ ttface = (TT_Face)face;
+ sfnt = (SFNT_Service)ttface->sfnt;
+
+ if ( sfnt->get_paint )
+ return sfnt->get_paint( ttface, opaque_paint, paint );
+ else
+ return 0;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Bool )
+ FT_Get_Colorline_Stops ( FT_Face face,
+ FT_ColorStop * color_stop,
+ FT_ColorStopIterator *iterator )
+ {
+ TT_Face ttface;
+ SFNT_Service sfnt;
+
+
+ if ( !face || !color_stop || !iterator )
+ return 0;
+
+ if ( !FT_IS_SFNT( face ) )
+ return 0;
+
+ ttface = (TT_Face)face;
+ sfnt = (SFNT_Service)ttface->sfnt;
+
+ if ( sfnt->get_colorline_stops )
+ return sfnt->get_colorline_stops ( ttface, color_stop, iterator );
+ else
+ return 0;
+ }
+
+
+/* END */
diff -Naur a/src/sdf/ftsdfrend.c b/src/sdf/ftsdfrend.c
--- a/src/sdf/ftsdfrend.c 2021-06-30 09:57:51.000000000 +0200
+++ b/src/sdf/ftsdfrend.c 2021-09-27 18:42:06.336661956 +0200
@@ -494,8 +494,11 @@
/* check whether render mode is correct */
if ( mode != FT_RENDER_MODE_SDF )
{
- error = FT_THROW( Cannot_Render_Glyph );
- goto Exit;
+ FT_TRACE0(( "ft_bsdf_render: trying to render bitmap\n" ));
+
+ /* return OK since the slot is already a bitmap */
+ error = FT_Err_Ok;
+ return error;
}
if ( origin )
diff -Naur a/src/sfnt/ttcolr.c.orig b/src/sfnt/ttcolr.c.orig
--- a/src/sfnt/ttcolr.c.orig 1970-01-01 01:00:00.000000000 +0100
+++ b/src/sfnt/ttcolr.c.orig 2021-09-27 18:42:28.369995183 +0200
@@ -0,0 +1,1253 @@
+/****************************************************************************
+ *
+ * ttcolr.c
+ *
+ * TrueType and OpenType colored glyph layer support (body).
+ *
+ * Copyright (C) 2018-2021 by
+ * David Turner, Robert Wilhelm, Dominik Röttsches, and Werner Lemberg.
+ *
+ * Originally written by Shao Yu Zhang <shaozhang@fb.com>.
+ *
+ * This file is part of the FreeType project, and may only be used,
+ * modified, and distributed under the terms of the FreeType project
+ * license, LICENSE.TXT. By continuing to use, modify, or distribute
+ * this file you indicate that you have read the license and
+ * understand and accept it fully.
+ *
+ */
+
+
+ /**************************************************************************
+ *
+ * `COLR' table specification:
+ *
+ * https://www.microsoft.com/typography/otspec/colr.htm
+ *
+ */
+
+
+#include <freetype/internal/ftdebug.h>
+#include <freetype/internal/ftstream.h>
+#include <freetype/tttags.h>
+#include <freetype/ftcolor.h>
+#include <freetype/config/integer-types.h>
+
+
+#ifdef TT_CONFIG_OPTION_COLOR_LAYERS
+
+#include "ttcolr.h"
+
+
+ /* NOTE: These are the table sizes calculated through the specs. */
+#define BASE_GLYPH_SIZE 6U
+#define BASE_GLYPH_PAINT_RECORD_SIZE 6U
+#define LAYER_V1_LIST_PAINT_OFFSET_SIZE 4U
+#define LAYER_V1_LIST_NUM_LAYERS_SIZE 4U
+#define COLOR_STOP_SIZE 6U
+#define LAYER_SIZE 4U
+#define COLR_HEADER_SIZE 14U
+
+
+ typedef enum FT_PaintFormat_Internal_
+ {
+ FT_COLR_PAINTFORMAT_INTERNAL_SCALE_CENTER = 18,
+ FT_COLR_PAINTFORMAT_INTERNAL_SCALE_UNIFORM = 20,
+ FT_COLR_PAINTFORMAT_INTERNAL_SCALE_UNIFORM_CENTER = 22,
+ FT_COLR_PAINTFORMAT_INTERNAL_ROTATE_CENTER = 26,
+ FT_COLR_PAINTFORMAT_INTERNAL_SKEW_CENTER = 30
+
+ } FT_PaintFormat_Internal;
+
+
+ typedef struct BaseGlyphRecord_
+ {
+ FT_UShort gid;
+ FT_UShort first_layer_index;
+ FT_UShort num_layers;
+
+ } BaseGlyphRecord;
+
+
+ typedef struct BaseGlyphV1Record_
+ {
+ FT_UShort gid;
+ /* Offset from start of BaseGlyphV1List, i.e., from base_glyphs_v1. */
+ FT_ULong paint_offset;
+
+ } BaseGlyphV1Record;
+
+
+ typedef struct Colr_
+ {
+ FT_UShort version;
+ FT_UShort num_base_glyphs;
+ FT_UShort num_layers;
+
+ FT_Byte* base_glyphs;
+ FT_Byte* layers;
+
+ FT_ULong num_base_glyphs_v1;
+ /* Points at beginning of BaseGlyphV1List. */
+ FT_Byte* base_glyphs_v1;
+
+ FT_ULong num_layers_v1;
+ FT_Byte* layers_v1;
+
+ FT_Byte* clip_list;
+
+ /*
+ * Paint tables start at the minimum of the end of the LayerList and the
+ * end of the BaseGlyphList. Record this location in a field here for
+ * safety checks when accessing paint tables.
+ */
+ FT_Byte* paints_start_v1;
+
+ /* The memory that backs up the `COLR' table. */
+ void* table;
+ FT_ULong table_size;
+
+ } Colr;
+
+
+ /**************************************************************************
+ *
+ * The macro FT_COMPONENT is used in trace mode. It is an implicit
+ * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
+ * messages during execution.
+ */
+#undef FT_COMPONENT
+#define FT_COMPONENT ttcolr
+
+
+ FT_LOCAL_DEF( FT_Error )
+ tt_face_load_colr( TT_Face face,
+ FT_Stream stream )
+ {
+ FT_Error error;
+ FT_Memory memory = face->root.memory;
+
+ FT_Byte* table = NULL;
+ FT_Byte* p = NULL;
+ /* Needed for reading array lengths in referenced tables. */
+ FT_Byte* p1 = NULL;
+
+ Colr* colr = NULL;
+
+ FT_ULong base_glyph_offset, layer_offset;
+ FT_ULong base_glyphs_offset_v1, num_base_glyphs_v1;
+ FT_ULong layer_offset_v1, num_layers_v1, clip_list_offset;
+ FT_ULong table_size;
+
+
+ /* `COLR' always needs `CPAL' */
+ if ( !face->cpal )
+ return FT_THROW( Invalid_File_Format );
+
+ error = face->goto_table( face, TTAG_COLR, stream, &table_size );
+ if ( error )
+ goto NoColr;
+
+ if ( table_size < COLR_HEADER_SIZE )
+ goto InvalidTable;
+
+ if ( FT_FRAME_EXTRACT( table_size, table ) )
+ goto NoColr;
+
+ p = table;
+
+ if ( FT_NEW( colr ) )
+ goto NoColr;
+
+ colr->version = FT_NEXT_USHORT( p );
+ if ( colr->version != 0 && colr->version != 1 )
+ goto InvalidTable;
+
+ colr->num_base_glyphs = FT_NEXT_USHORT( p );
+ base_glyph_offset = FT_NEXT_ULONG( p );
+
+ if ( base_glyph_offset >= table_size )
+ goto InvalidTable;
+ if ( colr->num_base_glyphs * BASE_GLYPH_SIZE >
+ table_size - base_glyph_offset )
+ goto InvalidTable;
+
+ layer_offset = FT_NEXT_ULONG( p );
+ colr->num_layers = FT_NEXT_USHORT( p );
+
+ if ( layer_offset >= table_size )
+ goto InvalidTable;
+ if ( colr->num_layers * LAYER_SIZE > table_size - layer_offset )
+ goto InvalidTable;
+
+ if ( colr->version == 1 )
+ {
+ base_glyphs_offset_v1 = FT_NEXT_ULONG( p );
+
+ if ( base_glyphs_offset_v1 >= table_size )
+ goto InvalidTable;
+
+ p1 = (FT_Byte*)( table + base_glyphs_offset_v1 );
+ num_base_glyphs_v1 = FT_PEEK_ULONG( p1 );
+
+ if ( num_base_glyphs_v1 * BASE_GLYPH_PAINT_RECORD_SIZE >
+ table_size - base_glyphs_offset_v1 )
+ goto InvalidTable;
+
+ colr->num_base_glyphs_v1 = num_base_glyphs_v1;
+ colr->base_glyphs_v1 = p1;
+
+ layer_offset_v1 = FT_NEXT_ULONG( p );
+
+ if ( layer_offset_v1 >= table_size )
+ goto InvalidTable;
+
+ if ( layer_offset_v1 )
+ {
+ p1 = (FT_Byte*)( table + layer_offset_v1 );
+ num_layers_v1 = FT_PEEK_ULONG( p1 );
+
+ if ( num_layers_v1 * LAYER_V1_LIST_PAINT_OFFSET_SIZE >
+ table_size - layer_offset_v1 )
+ goto InvalidTable;
+
+ colr->num_layers_v1 = num_layers_v1;
+ colr->layers_v1 = p1;
+
+ colr->paints_start_v1 =
+ FT_MIN( colr->base_glyphs_v1 +
+ colr->num_base_glyphs_v1 * BASE_GLYPH_PAINT_RECORD_SIZE,
+ colr->layers_v1 +
+ colr->num_layers_v1 * LAYER_V1_LIST_PAINT_OFFSET_SIZE );
+ }
+ else
+ {
+ colr->num_layers_v1 = 0;
+ colr->layers_v1 = 0;
+ colr->paints_start_v1 =
+ colr->base_glyphs_v1 +
+ colr->num_base_glyphs_v1 * BASE_GLYPH_PAINT_RECORD_SIZE;
+ }
+
+ clip_list_offset = FT_NEXT_ULONG( p );
+
+ if ( clip_list_offset >= table_size )
+ goto InvalidTable;
+
+ if ( clip_list_offset )
+ colr->clip_list = (FT_Byte*)( table + clip_list_offset );
+ else
+ colr->clip_list = 0;
+ }
+
+ colr->base_glyphs = (FT_Byte*)( table + base_glyph_offset );
+ colr->layers = (FT_Byte*)( table + layer_offset );
+ colr->table = table;
+ colr->table_size = table_size;
+
+ face->colr = colr;
+
+ return FT_Err_Ok;
+
+ InvalidTable:
+ error = FT_THROW( Invalid_Table );
+
+ NoColr:
+ FT_FRAME_RELEASE( table );
+ FT_FREE( colr );
+
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ tt_face_free_colr( TT_Face face )
+ {
+ FT_Stream stream = face->root.stream;
+ FT_Memory memory = face->root.memory;
+
+ Colr* colr = (Colr*)face->colr;
+
+
+ if ( colr )
+ {
+ FT_FRAME_RELEASE( colr->table );
+ FT_FREE( colr );
+ }
+ }
+
+
+ static FT_Bool
+ find_base_glyph_record( FT_Byte* base_glyph_begin,
+ FT_UInt num_base_glyph,
+ FT_UInt glyph_id,
+ BaseGlyphRecord* record )
+ {
+ FT_UInt min = 0;
+ FT_UInt max = num_base_glyph;
+
+
+ while ( min < max )
+ {
+ FT_UInt mid = min + ( max - min ) / 2;
+ FT_Byte* p = base_glyph_begin + mid * BASE_GLYPH_SIZE;
+
+ FT_UShort gid = FT_NEXT_USHORT( p );
+
+
+ if ( gid < glyph_id )
+ min = mid + 1;
+ else if (gid > glyph_id )
+ max = mid;
+ else
+ {
+ record->gid = gid;
+ record->first_layer_index = FT_NEXT_USHORT( p );
+ record->num_layers = FT_NEXT_USHORT( p );
+
+ return 1;
+ }
+ }
+
+ return 0;
+ }
+
+
+ FT_LOCAL_DEF( FT_Bool )
+ tt_face_get_colr_layer( TT_Face face,
+ FT_UInt base_glyph,
+ FT_UInt *aglyph_index,
+ FT_UInt *acolor_index,
+ FT_LayerIterator* iterator )
+ {
+ Colr* colr = (Colr*)face->colr;
+ BaseGlyphRecord glyph_record;
+
+
+ if ( !colr )
+ return 0;
+
+ if ( !iterator->p )
+ {
+ FT_ULong offset;
+
+
+ /* first call to function */
+ iterator->layer = 0;
+
+ if ( !find_base_glyph_record( colr->base_glyphs,
+ colr->num_base_glyphs,
+ base_glyph,
+ &glyph_record ) )
+ return 0;
+
+ if ( glyph_record.num_layers )
+ iterator->num_layers = glyph_record.num_layers;
+ else
+ return 0;
+
+ offset = LAYER_SIZE * glyph_record.first_layer_index;
+ if ( offset + LAYER_SIZE * glyph_record.num_layers > colr->table_size )
+ return 0;
+
+ iterator->p = colr->layers + offset;
+ }
+
+ if ( iterator->layer >= iterator->num_layers )
+ return 0;
+
+ *aglyph_index = FT_NEXT_USHORT( iterator->p );
+ *acolor_index = FT_NEXT_USHORT( iterator->p );
+
+ if ( *aglyph_index >= (FT_UInt)( FT_FACE( face )->num_glyphs ) ||
+ ( *acolor_index != 0xFFFF &&
+ *acolor_index >= face->palette_data.num_palette_entries ) )
+ return 0;
+
+ iterator->layer++;
+
+ return 1;
+ }
+
+
+ static FT_Bool
+ read_color_line( FT_Byte* color_line_p,
+ FT_ColorLine *colorline )
+ {
+ FT_Byte* p = color_line_p;
+ FT_PaintExtend paint_extend;
+
+
+ paint_extend = (FT_PaintExtend)FT_NEXT_BYTE( p );
+ if ( paint_extend > FT_COLR_PAINT_EXTEND_REFLECT )
+ return 0;
+
+ colorline->extend = paint_extend;
+
+ colorline->color_stop_iterator.num_color_stops = FT_NEXT_USHORT( p );
+ colorline->color_stop_iterator.p = p;
+ colorline->color_stop_iterator.current_color_stop = 0;
+
+ return 1;
+ }
+
+
+ /*
+ * Read a paint offset for `FT_Paint*` objects that have them and check
+ * whether it is within reasonable limits within the font and the COLR
+ * table.
+ *
+ * Return 1 on success, 0 on failure.
+ */
+ static FT_Bool
+ get_child_table_pointer ( Colr* colr,
+ FT_Byte* paint_base,
+ FT_Byte** p,
+ FT_Byte** child_table_pointer )
+ {
+ FT_UInt32 paint_offset;
+ FT_Byte* child_table_p;
+
+
+ if ( !child_table_pointer )
+ return 0;
+
+ paint_offset = FT_NEXT_UOFF3( *p );
+ if ( !paint_offset )
+ return 0;
+
+ child_table_p = (FT_Byte*)( paint_base + paint_offset );
+
+ if ( child_table_p < colr->paints_start_v1 ||
+ child_table_p >= ( (FT_Byte*)colr->table + colr->table_size ) )
+ return 0;
+
+ *child_table_pointer = child_table_p;
+ return 1;
+ }
+
+
+ static FT_Bool
+ read_paint( Colr* colr,
+ FT_Byte* p,
+ FT_COLR_Paint* apaint )
+ {
+ FT_Byte* paint_base = p;
+ FT_Byte* child_table_p = NULL;
+
+
+ if ( !p || !colr || !colr->table )
+ return 0;
+
+ if ( p < colr->paints_start_v1 ||
+ p >= ( (FT_Byte*)colr->table + colr->table_size ) )
+ return 0;
+
+ apaint->format = (FT_PaintFormat)FT_NEXT_BYTE( p );
+
+ if ( apaint->format >= FT_COLR_PAINT_FORMAT_MAX )
+ return 0;
+
+ if ( apaint->format == FT_COLR_PAINTFORMAT_COLR_LAYERS )
+ {
+ /* Initialize layer iterator/ */
+ FT_Byte num_layers;
+ FT_UInt32 first_layer_index;
+
+
+ num_layers = FT_NEXT_BYTE( p );
+ if ( num_layers > colr->num_layers_v1 )
+ return 0;
+
+ first_layer_index = FT_NEXT_ULONG( p );
+ if ( first_layer_index + num_layers > colr->num_layers_v1 )
+ return 0;
+
+ apaint->u.colr_layers.layer_iterator.num_layers = num_layers;
+ apaint->u.colr_layers.layer_iterator.layer = 0;
+ /* TODO: Check whether pointer is outside colr? */
+ apaint->u.colr_layers.layer_iterator.p =
+ colr->layers_v1 +
+ LAYER_V1_LIST_NUM_LAYERS_SIZE +
+ LAYER_V1_LIST_PAINT_OFFSET_SIZE * first_layer_index;
+
+ return 1;
+ }
+
+ else if ( apaint->format == FT_COLR_PAINTFORMAT_SOLID )
+ {
+ apaint->u.solid.color.palette_index = FT_NEXT_USHORT( p );
+ apaint->u.solid.color.alpha = FT_NEXT_SHORT( p );
+
+ return 1;
+ }
+
+ else if ( apaint->format == FT_COLR_PAINTFORMAT_COLR_GLYPH )
+ {
+ apaint->u.colr_glyph.glyphID = FT_NEXT_USHORT( p );
+
+ return 1;
+ }
+
+ /*
+ * Grouped below here are all paint formats that have an offset to a
+ * child paint table as the first entry (for example, a color line or a
+ * child paint table). Retrieve that and determine whether that paint
+ * offset is valid first.
+ */
+
+ if ( !get_child_table_pointer( colr, paint_base, &p, &child_table_p ) )
+ return 0;
+
+ if ( apaint->format == FT_COLR_PAINTFORMAT_LINEAR_GRADIENT )
+ {
+ if ( !read_color_line( child_table_p,
+ &apaint->u.linear_gradient.colorline ) )
+ return 0;
+
+ apaint->u.linear_gradient.p0.x = FT_NEXT_SHORT( p );
+ apaint->u.linear_gradient.p0.y = FT_NEXT_SHORT( p );
+ apaint->u.linear_gradient.p1.x = FT_NEXT_SHORT( p );
+ apaint->u.linear_gradient.p1.y = FT_NEXT_SHORT( p );
+ apaint->u.linear_gradient.p2.x = FT_NEXT_SHORT( p );
+ apaint->u.linear_gradient.p2.y = FT_NEXT_SHORT( p );
+
+ return 1;
+ }
+
+ else if ( apaint->format == FT_COLR_PAINTFORMAT_RADIAL_GRADIENT )
+ {
+ if ( !read_color_line( child_table_p,
+ &apaint->u.radial_gradient.colorline ) )
+ return 0;
+
+ apaint->u.radial_gradient.c0.x = FT_NEXT_SHORT( p );
+ apaint->u.radial_gradient.c0.y = FT_NEXT_SHORT( p );
+
+ apaint->u.radial_gradient.r0 = FT_NEXT_USHORT( p );
+
+ apaint->u.radial_gradient.c1.x = FT_NEXT_SHORT( p );
+ apaint->u.radial_gradient.c1.y = FT_NEXT_SHORT( p );
+
+ apaint->u.radial_gradient.r1 = FT_NEXT_USHORT( p );
+
+ return 1;
+ }
+
+ else if ( apaint->format == FT_COLR_PAINTFORMAT_SWEEP_GRADIENT )
+ {
+ if ( !read_color_line( child_table_p,
+ &apaint->u.sweep_gradient.colorline ) )
+ return 0;
+
+ apaint->u.sweep_gradient.center.x = FT_NEXT_SHORT( p );
+ apaint->u.sweep_gradient.center.y = FT_NEXT_SHORT( p );
+
+ apaint->u.sweep_gradient.start_angle = FT_NEXT_LONG( p );
+ apaint->u.sweep_gradient.end_angle = FT_NEXT_LONG( p );
+
+ return 1;
+ }
+
+ if ( apaint->format == FT_COLR_PAINTFORMAT_GLYPH )
+ {
+ apaint->u.glyph.paint.p = child_table_p;
+ apaint->u.glyph.paint.insert_root_transform = 0;
+ apaint->u.glyph.glyphID = FT_NEXT_USHORT( p );
+
+ return 1;
+ }
+
+ else if ( apaint->format == FT_COLR_PAINTFORMAT_TRANSFORM )
+ {
+ apaint->u.transform.paint.p = child_table_p;
+ apaint->u.transform.paint.insert_root_transform = 0;
+
+ apaint->u.transform.affine.xx = FT_NEXT_LONG( p );
+ apaint->u.transform.affine.yx = FT_NEXT_LONG( p );
+ apaint->u.transform.affine.xy = FT_NEXT_LONG( p );
+ apaint->u.transform.affine.yy = FT_NEXT_LONG( p );
+ apaint->u.transform.affine.dx = FT_NEXT_LONG( p );
+ apaint->u.transform.affine.dy = FT_NEXT_LONG( p );
+
+ return 1;
+ }
+
+ else if ( apaint->format == FT_COLR_PAINTFORMAT_TRANSLATE )
+ {
+ apaint->u.translate.paint.p = child_table_p;
+ apaint->u.translate.paint.insert_root_transform = 0;
+
+ apaint->u.translate.dx = FT_NEXT_LONG( p );
+ apaint->u.translate.dy = FT_NEXT_LONG( p );
+
+ return 1;
+ }
+
+ else if ( apaint->format ==
+ FT_COLR_PAINTFORMAT_SCALE ||
+ (FT_PaintFormat_Internal)apaint->format ==
+ FT_COLR_PAINTFORMAT_INTERNAL_SCALE_CENTER ||
+ (FT_PaintFormat_Internal)apaint->format ==
+ FT_COLR_PAINTFORMAT_INTERNAL_SCALE_UNIFORM ||
+ (FT_PaintFormat_Internal)apaint->format ==
+ FT_COLR_PAINTFORMAT_INTERNAL_SCALE_UNIFORM_CENTER )
+ {
+ apaint->u.scale.paint.p = child_table_p;
+ apaint->u.scale.paint.insert_root_transform = 0;
+
+ /* All scale paints get at least one scale value. */
+ apaint->u.scale.scale_x = FT_NEXT_LONG( p );
+
+ /* Non-uniform ones read an extra y value. */
+ if ( apaint->format ==
+ FT_COLR_PAINTFORMAT_SCALE ||
+ (FT_PaintFormat_Internal)apaint->format ==
+ FT_COLR_PAINTFORMAT_INTERNAL_SCALE_CENTER )
+ apaint->u.scale.scale_y = FT_NEXT_LONG( p );
+ else
+ apaint->u.scale.scale_y = apaint->u.scale.scale_x;
+
+ /* Scale paints that have a center read center coordinates, */
+ /* otherwise the center is (0,0). */
+ if ( (FT_PaintFormat_Internal)apaint->format ==
+ FT_COLR_PAINTFORMAT_INTERNAL_SCALE_CENTER ||
+ (FT_PaintFormat_Internal)apaint->format ==
+ FT_COLR_PAINTFORMAT_INTERNAL_SCALE_UNIFORM_CENTER )
+ {
+ apaint->u.scale.center_x = FT_NEXT_LONG ( p );
+ apaint->u.scale.center_y = FT_NEXT_LONG ( p );
+ }
+ else
+ {
+ apaint->u.scale.center_x = 0;
+ apaint->u.scale.center_y = 0;
+ }
+
+ /* FT 'COLR' v1 API output format always returns fully defined */
+ /* structs; we thus set the format to the public API value. */
+ apaint->format = FT_COLR_PAINTFORMAT_SCALE;
+
+ return 1;
+ }
+
+ else if ( apaint->format == FT_COLR_PAINTFORMAT_ROTATE )
+ {
+ apaint->u.rotate.paint.p = child_table_p;
+ apaint->u.rotate.paint.insert_root_transform = 0;
+
+ apaint->u.rotate.angle = FT_NEXT_LONG( p );
+
+ apaint->u.rotate.center_x = FT_NEXT_LONG( p );
+ apaint->u.rotate.center_y = FT_NEXT_LONG( p );
+
+ return 1;
+ }
+
+ else if ( apaint->format == FT_COLR_PAINTFORMAT_SKEW )
+ {
+ apaint->u.skew.paint.p = child_table_p;
+ apaint->u.skew.paint.insert_root_transform = 0;
+
+ apaint->u.skew.x_skew_angle = FT_NEXT_LONG( p );
+ apaint->u.skew.y_skew_angle = FT_NEXT_LONG( p );
+
+ apaint->u.skew.center_x = FT_NEXT_LONG( p );
+ apaint->u.skew.center_y = FT_NEXT_LONG( p );
+
+ return 1;
+ }
+
+ else if ( apaint->format == FT_COLR_PAINTFORMAT_COMPOSITE )
+ {
+ FT_UInt composite_mode;
+
+
+ apaint->u.composite.source_paint.p = child_table_p;
+ apaint->u.composite.source_paint.insert_root_transform = 0;
+
+ composite_mode = FT_NEXT_BYTE( p );
+ if ( composite_mode >= FT_COLR_COMPOSITE_MAX )
+ return 0;
+
+ apaint->u.composite.composite_mode = (FT_Composite_Mode)composite_mode;
+
+ if ( !get_child_table_pointer( colr, paint_base, &p, &child_table_p ) )
+ return 0;
+
+ apaint->u.composite.backdrop_paint.p =
+ child_table_p;
+ apaint->u.composite.backdrop_paint.insert_root_transform =
+ 0;
+
+ return 1;
+ }
+
+ return 0;
+ }
+
+
+ static FT_Bool
+ find_base_glyph_v1_record( FT_Byte * base_glyph_begin,
+ FT_UInt num_base_glyph,
+ FT_UInt glyph_id,
+ BaseGlyphV1Record *record )
+ {
+ FT_UInt min = 0;
+ FT_UInt max = num_base_glyph;
+
+
+ while ( min < max )
+ {
+ FT_UInt mid = min + ( max - min ) / 2;
+
+ /*
+ * `base_glyph_begin` is the beginning of `BaseGlyphV1List`;
+ * skip `numBaseGlyphV1Records` by adding 4 to start binary search
+ * in the array of `BaseGlyphV1Record`.
+ */
+ FT_Byte *p = base_glyph_begin + 4 + mid * BASE_GLYPH_PAINT_RECORD_SIZE;
+
+ FT_UShort gid = FT_NEXT_USHORT( p );
+
+
+ if ( gid < glyph_id )
+ min = mid + 1;
+ else if (gid > glyph_id )
+ max = mid;
+ else
+ {
+ record->gid = gid;
+ record->paint_offset = FT_NEXT_ULONG ( p );
+ return 1;
+ }
+ }
+
+ return 0;
+ }
+
+
+ FT_LOCAL_DEF( FT_Bool )
+ tt_face_get_colr_glyph_paint( TT_Face face,
+ FT_UInt base_glyph,
+ FT_Color_Root_Transform root_transform,
+ FT_OpaquePaint* opaque_paint )
+ {
+ Colr* colr = (Colr*)face->colr;
+ BaseGlyphV1Record base_glyph_v1_record;
+ FT_Byte* p;
+
+ if ( !colr || !colr->table )
+ return 0;
+
+ if ( colr->version < 1 || !colr->num_base_glyphs_v1 ||
+ !colr->base_glyphs_v1 )
+ return 0;
+
+ if ( opaque_paint->p )
+ return 0;
+
+ if ( !find_base_glyph_v1_record( colr->base_glyphs_v1,
+ colr->num_base_glyphs_v1,
+ base_glyph,
+ &base_glyph_v1_record ) )
+ return 0;
+
+ if ( !base_glyph_v1_record.paint_offset ||
+ base_glyph_v1_record.paint_offset > colr->table_size )
+ return 0;
+
+ p = (FT_Byte*)( colr->base_glyphs_v1 +
+ base_glyph_v1_record.paint_offset );
+ if ( p >= ( (FT_Byte*)colr->table + colr->table_size ) )
+ return 0;
+
+ opaque_paint->p = p;
+
+ if ( root_transform == FT_COLOR_INCLUDE_ROOT_TRANSFORM )
+ opaque_paint->insert_root_transform = 1;
+ else
+ opaque_paint->insert_root_transform = 0;
+
+ return 1;
+ }
+
+
+ FT_LOCAL_DEF( FT_Bool )
+ tt_face_get_color_glyph_clipbox( TT_Face face,
+ FT_UInt base_glyph,
+ FT_ClipBox* clip_box )
+ {
+ Colr* colr;
+
+ FT_Byte *p, *p1, *clip_base;
+
+ FT_Byte clip_list_format;
+ FT_ULong num_clip_boxes, i;
+ FT_UShort gid_start, gid_end;
+ FT_UInt32 clip_box_offset;
+ FT_Byte format;
+
+ const FT_Byte num_corners = 4;
+ FT_Vector corners[4];
+ FT_Byte j;
+ FT_BBox font_clip_box;
+
+
+ colr = (Colr*)face->colr;
+ if ( !colr )
+ return 0;
+
+ if ( !colr->clip_list )
+ return 0;
+
+ p = colr->clip_list;
+
+ clip_base = p;
+ clip_list_format = FT_NEXT_BYTE ( p );
+
+ /* Format byte used here to be able to upgrade ClipList for >16bit */
+ /* glyph ids; for now we can expect it to be 0. */
+ if ( !( clip_list_format == 0 ) )
+ return 0;
+
+ num_clip_boxes = FT_NEXT_ULONG( p );
+
+ for ( i = 0; i < num_clip_boxes; ++i )
+ {
+ gid_start = FT_NEXT_USHORT( p );
+ gid_end = FT_NEXT_USHORT( p );
+ clip_box_offset = FT_NEXT_UOFF3( p );
+
+ if ( base_glyph >= gid_start && base_glyph <= gid_end )
+ {
+ p1 = (FT_Byte*)( clip_base + clip_box_offset );
+
+ if ( p1 >= ( (FT_Byte*)colr->table + colr->table_size ) )
+ return 0;
+
+ format = FT_NEXT_BYTE( p1 );
+
+ if ( format < 0 || format > 1 )
+ return 0;
+
+ /* `face->root.size->metrics.x_scale` and `y_scale` are factors */
+ /* that scale a font unit value in integers to a 26.6 fixed value */
+ /* according to the requested size, see for example */
+ /* `ft_recompute_scaled_metrics`. */
+ font_clip_box.xMin = FT_MulFix( FT_NEXT_SHORT( p1 ),
+ face->root.size->metrics.x_scale );
+ font_clip_box.yMin = FT_MulFix( FT_NEXT_SHORT( p1 ),
+ face->root.size->metrics.x_scale );
+ font_clip_box.xMax = FT_MulFix( FT_NEXT_SHORT( p1 ),
+ face->root.size->metrics.x_scale );
+ font_clip_box.yMax = FT_MulFix( FT_NEXT_SHORT( p1 ),
+ face->root.size->metrics.x_scale );
+
+ /* Make 4 corner points (xMin, yMin), (xMax, yMax) and transform */
+ /* them. If we we would only transform two corner points and */
+ /* span a rectangle based on those, the rectangle may become too */
+ /* small to cover the glyph. */
+ corners[0].x = font_clip_box.xMin;
+ corners[1].x = font_clip_box.xMin;
+ corners[2].x = font_clip_box.xMax;
+ corners[3].x = font_clip_box.xMax;
+
+ corners[0].y = font_clip_box.yMin;
+ corners[1].y = font_clip_box.yMax;
+ corners[2].y = font_clip_box.yMax;
+ corners[3].y = font_clip_box.yMin;
+
+ for ( j = 0; j < num_corners; ++j )
+ {
+ if ( face->root.internal->transform_flags & 1 )
+ FT_Vector_Transform( &corners[j],
+ &face->root.internal->transform_matrix );
+
+ if ( face->root.internal->transform_flags & 2 )
+ {
+ corners[j].x += face->root.internal->transform_delta.x;
+ corners[j].y += face->root.internal->transform_delta.y;
+ }
+ }
+
+ clip_box->bottom_left = corners[0];
+ clip_box->top_left = corners[1];
+ clip_box->top_right = corners[2];
+ clip_box->bottom_right = corners[3];
+
+ return 1;
+ }
+ }
+
+ return 0;
+ }
+
+
+ FT_LOCAL_DEF( FT_Bool )
+ tt_face_get_paint_layers( TT_Face face,
+ FT_LayerIterator* iterator,
+ FT_OpaquePaint* opaque_paint )
+ {
+ FT_Byte* p = NULL;
+ FT_Byte* p_first_layer = NULL;
+ FT_Byte* p_paint = NULL;
+ FT_UInt32 paint_offset;
+
+ Colr* colr;
+
+
+ if ( iterator->layer == iterator->num_layers )
+ return 0;
+
+ colr = (Colr*)face->colr;
+ if ( !colr )
+ return 0;
+
+ /*
+ * We have an iterator pointing at a paint offset as part of the
+ * `paintOffset` array in `LayerV1List`.
+ */
+ p = iterator->p;
+
+ /*
+ * First ensure that p is within COLRv1.
+ */
+ if ( p < colr->layers_v1 ||
+ p >= ( (FT_Byte*)colr->table + colr->table_size ) )
+ return 0;
+
+ /*
+ * Do a cursor sanity check of the iterator. Counting backwards from
+ * where it stands, we need to end up at a position after the beginning
+ * of the `LayerV1List` table and not after the end of the
+ * `LayerV1List`.
+ */
+ p_first_layer = p -
+ iterator->layer * LAYER_V1_LIST_PAINT_OFFSET_SIZE -
+ LAYER_V1_LIST_NUM_LAYERS_SIZE;
+ if ( p_first_layer < (FT_Byte*)colr->layers_v1 )
+ return 0;
+ if ( p_first_layer >= (FT_Byte*)(
+ colr->layers_v1 + LAYER_V1_LIST_NUM_LAYERS_SIZE +
+ colr->num_layers_v1 * LAYER_V1_LIST_PAINT_OFFSET_SIZE ) )
+ return 0;
+
+ paint_offset =
+ FT_NEXT_ULONG( p );
+ opaque_paint->insert_root_transform =
+ 0;
+
+ p_paint = (FT_Byte*)( colr->layers_v1 + paint_offset );
+
+ if ( p_paint < colr->paints_start_v1 ||
+ p_paint >= ( (FT_Byte*)colr->table + colr->table_size ) )
+ return 0;
+
+ opaque_paint->p = p_paint;
+
+ iterator->p = p;
+
+ iterator->layer++;
+
+ return 1;
+ }
+
+
+ FT_LOCAL_DEF( FT_Bool )
+ tt_face_get_colorline_stops( TT_Face face,
+ FT_ColorStop* color_stop,
+ FT_ColorStopIterator *iterator )
+ {
+ Colr* colr = (Colr*)face->colr;
+
+ FT_Byte* p;
+
+
+ if ( !colr || !colr->table )
+ return 0;
+
+ if ( iterator->current_color_stop >= iterator->num_color_stops )
+ return 0;
+
+ if ( iterator->p +
+ ( ( iterator->num_color_stops - iterator->current_color_stop ) *
+ COLOR_STOP_SIZE ) >
+ ( (FT_Byte *)colr->table + colr->table_size ) )
+ return 0;
+
+ /* Iterator points at first `ColorStop` of `ColorLine`. */
+ p = iterator->p;
+
+ color_stop->stop_offset = FT_NEXT_SHORT( p );
+
+ color_stop->color.palette_index = FT_NEXT_USHORT( p );
+
+ color_stop->color.alpha = FT_NEXT_SHORT( p );
+
+ iterator->p = p;
+ iterator->current_color_stop++;
+
+ return 1;
+ }
+
+
+ FT_LOCAL_DEF( FT_Bool )
+ tt_face_get_paint( TT_Face face,
+ FT_OpaquePaint opaque_paint,
+ FT_COLR_Paint* paint )
+ {
+ Colr* colr = (Colr*)face->colr;
+ FT_OpaquePaint next_paint;
+ FT_Matrix ft_root_scale;
+
+ if ( !colr || !colr->base_glyphs_v1 || !colr->table )
+ return 0;
+
+ if ( opaque_paint.insert_root_transform )
+ {
+ /* 'COLR' v1 glyph information is returned in unscaled coordinates,
+ * i.e., `FT_Size` is not applied or multiplied into the values. When
+ * client applications draw color glyphs, they can request to include
+ * a top-level transform, which includes the active `x_scale` and
+ * `y_scale` information for scaling the glyph, as well the additional
+ * transform and translate configured through `FT_Set_Transform`.
+ * This allows client applications to apply this top-level transform
+ * to the graphics context first and only once, then have gradient and
+ * contour scaling applied correctly when performing the additional
+ * drawing operations for subsequenct paints. Prepare this initial
+ * transform here.
+ */
+ paint->format = FT_COLR_PAINTFORMAT_TRANSFORM;
+
+ next_paint.p = opaque_paint.p;
+ next_paint.insert_root_transform = 0;
+ paint->u.transform.paint = next_paint;
+
+ /* `x_scale` and `y_scale` are in 26.6 format, representing the scale
+ * factor to get from font units to requested size. However, expected
+ * return values are in 16.16, so we shift accordingly with rounding.
+ */
+ ft_root_scale.xx = ( face->root.size->metrics.x_scale + 32 ) >> 6;
+ ft_root_scale.xy = 0;
+ ft_root_scale.yx = 0;
+ ft_root_scale.yy = ( face->root.size->metrics.y_scale + 32 ) >> 6;
+
+ if ( face->root.internal->transform_flags & 1 )
+ FT_Matrix_Multiply( &face->root.internal->transform_matrix,
+ &ft_root_scale );
+
+ paint->u.transform.affine.xx = ft_root_scale.xx;
+ paint->u.transform.affine.xy = ft_root_scale.xy;
+ paint->u.transform.affine.yx = ft_root_scale.yx;
+ paint->u.transform.affine.yy = ft_root_scale.yy;
+
+ /* The translation is specified in 26.6 format and, according to the
+ * documentation of `FT_Set_Translate`, is performed on the character
+ * size given in the last call to `FT_Set_Char_Size`. The
+ * 'PaintTransform' paint table's `FT_Affine23` format expects
+ * values in 16.16 format, thus we need to shift by 10 bits.
+ */
+ if ( face->root.internal->transform_flags & 2 )
+ {
+ paint->u.transform.affine.dx =
+ face->root.internal->transform_delta.x << 10;
+ paint->u.transform.affine.dy =
+ face->root.internal->transform_delta.y << 10;
+ }
+ else
+ {
+ paint->u.transform.affine.dx = 0;
+ paint->u.transform.affine.dy = 0;
+ }
+
+ return 1;
+ }
+
+ return read_paint( colr, opaque_paint.p, paint );
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ tt_face_colr_blend_layer( TT_Face face,
+ FT_UInt color_index,
+ FT_GlyphSlot dstSlot,
+ FT_GlyphSlot srcSlot )
+ {
+ FT_Error error;
+
+ FT_UInt x, y;
+ FT_Byte b, g, r, alpha;
+
+ FT_ULong size;
+ FT_Byte* src;
+ FT_Byte* dst;
+
+
+ if ( !dstSlot->bitmap.buffer )
+ {
+ /* Initialize destination of color bitmap */
+ /* with the size of first component. */
+ dstSlot->bitmap_left = srcSlot->bitmap_left;
+ dstSlot->bitmap_top = srcSlot->bitmap_top;
+
+ dstSlot->bitmap.width = srcSlot->bitmap.width;
+ dstSlot->bitmap.rows = srcSlot->bitmap.rows;
+ dstSlot->bitmap.pixel_mode = FT_PIXEL_MODE_BGRA;
+ dstSlot->bitmap.pitch = (int)dstSlot->bitmap.width * 4;
+ dstSlot->bitmap.num_grays = 256;
+
+ size = dstSlot->bitmap.rows * (unsigned int)dstSlot->bitmap.pitch;
+
+ error = ft_glyphslot_alloc_bitmap( dstSlot, size );
+ if ( error )
+ return error;
+
+ FT_MEM_ZERO( dstSlot->bitmap.buffer, size );
+ }
+ else
+ {
+ /* Resize destination if needed such that new component fits. */
+ FT_Int x_min, x_max, y_min, y_max;
+
+
+ x_min = FT_MIN( dstSlot->bitmap_left, srcSlot->bitmap_left );
+ x_max = FT_MAX( dstSlot->bitmap_left + (FT_Int)dstSlot->bitmap.width,
+ srcSlot->bitmap_left + (FT_Int)srcSlot->bitmap.width );
+
+ y_min = FT_MIN( dstSlot->bitmap_top - (FT_Int)dstSlot->bitmap.rows,
+ srcSlot->bitmap_top - (FT_Int)srcSlot->bitmap.rows );
+ y_max = FT_MAX( dstSlot->bitmap_top, srcSlot->bitmap_top );
+
+ if ( x_min != dstSlot->bitmap_left ||
+ x_max != dstSlot->bitmap_left + (FT_Int)dstSlot->bitmap.width ||
+ y_min != dstSlot->bitmap_top - (FT_Int)dstSlot->bitmap.rows ||
+ y_max != dstSlot->bitmap_top )
+ {
+ FT_Memory memory = face->root.memory;
+
+ FT_UInt width = (FT_UInt)( x_max - x_min );
+ FT_UInt rows = (FT_UInt)( y_max - y_min );
+ FT_UInt pitch = width * 4;
+
+ FT_Byte* buf = NULL;
+ FT_Byte* p;
+ FT_Byte* q;
+
+
+ size = rows * pitch;
+ if ( FT_ALLOC( buf, size ) )
+ return error;
+
+ p = dstSlot->bitmap.buffer;
+ q = buf +
+ (int)pitch * ( y_max - dstSlot->bitmap_top ) +
+ 4 * ( dstSlot->bitmap_left - x_min );
+
+ for ( y = 0; y < dstSlot->bitmap.rows; y++ )
+ {
+ FT_MEM_COPY( q, p, dstSlot->bitmap.width * 4 );
+
+ p += dstSlot->bitmap.pitch;
+ q += pitch;
+ }
+
+ ft_glyphslot_set_bitmap( dstSlot, buf );
+
+ dstSlot->bitmap_top = y_max;
+ dstSlot->bitmap_left = x_min;
+
+ dstSlot->bitmap.width = width;
+ dstSlot->bitmap.rows = rows;
+ dstSlot->bitmap.pitch = (int)pitch;
+
+ dstSlot->internal->flags |= FT_GLYPH_OWN_BITMAP;
+ dstSlot->format = FT_GLYPH_FORMAT_BITMAP;
+ }
+ }
+
+ if ( color_index == 0xFFFF )
+ {
+ if ( face->have_foreground_color )
+ {
+ b = face->foreground_color.blue;
+ g = face->foreground_color.green;
+ r = face->foreground_color.red;
+ alpha = face->foreground_color.alpha;
+ }
+ else
+ {
+ if ( face->palette_data.palette_flags &&
+ ( face->palette_data.palette_flags[face->palette_index] &
+ FT_PALETTE_FOR_DARK_BACKGROUND ) )
+ {
+ /* white opaque */
+ b = 0xFF;
+ g = 0xFF;
+ r = 0xFF;
+ alpha = 0xFF;
+ }
+ else
+ {
+ /* black opaque */
+ b = 0x00;
+ g = 0x00;
+ r = 0x00;
+ alpha = 0xFF;
+ }
+ }
+ }
+ else
+ {
+ b = face->palette[color_index].blue;
+ g = face->palette[color_index].green;
+ r = face->palette[color_index].red;
+ alpha = face->palette[color_index].alpha;
+ }
+
+ /* XXX Convert if srcSlot.bitmap is not grey? */
+ src = srcSlot->bitmap.buffer;
+ dst = dstSlot->bitmap.buffer +
+ dstSlot->bitmap.pitch * ( dstSlot->bitmap_top - srcSlot->bitmap_top ) +
+ 4 * ( srcSlot->bitmap_left - dstSlot->bitmap_left );
+
+ for ( y = 0; y < srcSlot->bitmap.rows; y++ )
+ {
+ for ( x = 0; x < srcSlot->bitmap.width; x++ )
+ {
+ int aa = src[x];
+ int fa = alpha * aa / 255;
+
+ int fb = b * fa / 255;
+ int fg = g * fa / 255;
+ int fr = r * fa / 255;
+
+ int ba2 = 255 - fa;
+
+ int bb = dst[4 * x + 0];
+ int bg = dst[4 * x + 1];
+ int br = dst[4 * x + 2];
+ int ba = dst[4 * x + 3];
+
+
+ dst[4 * x + 0] = (FT_Byte)( bb * ba2 / 255 + fb );
+ dst[4 * x + 1] = (FT_Byte)( bg * ba2 / 255 + fg );
+ dst[4 * x + 2] = (FT_Byte)( br * ba2 / 255 + fr );
+ dst[4 * x + 3] = (FT_Byte)( ba * ba2 / 255 + fa );
+ }
+
+ src += srcSlot->bitmap.pitch;
+ dst += dstSlot->bitmap.pitch;
+ }
+
+ return FT_Err_Ok;
+ }
+
+#else /* !TT_CONFIG_OPTION_COLOR_LAYERS */
+
+ /* ANSI C doesn't like empty source files */
+ typedef int _tt_colr_dummy;
+
+#endif /* !TT_CONFIG_OPTION_COLOR_LAYERS */
+
+/* EOF */