__init__.py 112 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830
  1. """cffLib: read/write Adobe CFF fonts
  2. OpenType fonts with PostScript outlines contain a completely independent
  3. font file, Adobe's *Compact Font Format*. So dealing with OpenType fonts
  4. requires also dealing with CFF. This module allows you to read and write
  5. fonts written in the CFF format.
  6. In 2016, OpenType 1.8 introduced the `CFF2 <https://docs.microsoft.com/en-us/typography/opentype/spec/cff2>`_
  7. format which, along with other changes, extended the CFF format to deal with
  8. the demands of variable fonts. This module parses both original CFF and CFF2.
  9. """
  10. from fontTools.misc import sstruct
  11. from fontTools.misc import psCharStrings
  12. from fontTools.misc.arrayTools import unionRect, intRect
  13. from fontTools.misc.textTools import (
  14. bytechr,
  15. byteord,
  16. bytesjoin,
  17. tobytes,
  18. tostr,
  19. safeEval,
  20. )
  21. from fontTools.ttLib import TTFont
  22. from fontTools.ttLib.tables.otBase import OTTableWriter
  23. from fontTools.ttLib.tables.otBase import OTTableReader
  24. from fontTools.ttLib.tables import otTables as ot
  25. from io import BytesIO
  26. import struct
  27. import logging
  28. import re
  29. # mute cffLib debug messages when running ttx in verbose mode
  30. DEBUG = logging.DEBUG - 1
  31. log = logging.getLogger(__name__)
  32. cffHeaderFormat = """
  33. major: B
  34. minor: B
  35. hdrSize: B
  36. """
  37. maxStackLimit = 513
  38. # maxstack operator has been deprecated. max stack is now always 513.
  39. class StopHintCountEvent(Exception):
  40. pass
  41. class _DesubroutinizingT2Decompiler(psCharStrings.SimpleT2Decompiler):
  42. stop_hintcount_ops = (
  43. "op_hintmask",
  44. "op_cntrmask",
  45. "op_rmoveto",
  46. "op_hmoveto",
  47. "op_vmoveto",
  48. )
  49. def __init__(self, localSubrs, globalSubrs, private=None):
  50. psCharStrings.SimpleT2Decompiler.__init__(
  51. self, localSubrs, globalSubrs, private
  52. )
  53. def execute(self, charString):
  54. self.need_hintcount = True # until proven otherwise
  55. for op_name in self.stop_hintcount_ops:
  56. setattr(self, op_name, self.stop_hint_count)
  57. if hasattr(charString, "_desubroutinized"):
  58. # If a charstring has already been desubroutinized, we will still
  59. # need to execute it if we need to count hints in order to
  60. # compute the byte length for mask arguments, and haven't finished
  61. # counting hints pairs.
  62. if self.need_hintcount and self.callingStack:
  63. try:
  64. psCharStrings.SimpleT2Decompiler.execute(self, charString)
  65. except StopHintCountEvent:
  66. del self.callingStack[-1]
  67. return
  68. charString._patches = []
  69. psCharStrings.SimpleT2Decompiler.execute(self, charString)
  70. desubroutinized = charString.program[:]
  71. for idx, expansion in reversed(charString._patches):
  72. assert idx >= 2
  73. assert desubroutinized[idx - 1] in [
  74. "callsubr",
  75. "callgsubr",
  76. ], desubroutinized[idx - 1]
  77. assert type(desubroutinized[idx - 2]) == int
  78. if expansion[-1] == "return":
  79. expansion = expansion[:-1]
  80. desubroutinized[idx - 2 : idx] = expansion
  81. if not self.private.in_cff2:
  82. if "endchar" in desubroutinized:
  83. # Cut off after first endchar
  84. desubroutinized = desubroutinized[
  85. : desubroutinized.index("endchar") + 1
  86. ]
  87. else:
  88. if not len(desubroutinized) or desubroutinized[-1] != "return":
  89. desubroutinized.append("return")
  90. charString._desubroutinized = desubroutinized
  91. del charString._patches
  92. def op_callsubr(self, index):
  93. subr = self.localSubrs[self.operandStack[-1] + self.localBias]
  94. psCharStrings.SimpleT2Decompiler.op_callsubr(self, index)
  95. self.processSubr(index, subr)
  96. def op_callgsubr(self, index):
  97. subr = self.globalSubrs[self.operandStack[-1] + self.globalBias]
  98. psCharStrings.SimpleT2Decompiler.op_callgsubr(self, index)
  99. self.processSubr(index, subr)
  100. def stop_hint_count(self, *args):
  101. self.need_hintcount = False
  102. for op_name in self.stop_hintcount_ops:
  103. setattr(self, op_name, None)
  104. cs = self.callingStack[-1]
  105. if hasattr(cs, "_desubroutinized"):
  106. raise StopHintCountEvent()
  107. def op_hintmask(self, index):
  108. psCharStrings.SimpleT2Decompiler.op_hintmask(self, index)
  109. if self.need_hintcount:
  110. self.stop_hint_count()
  111. def processSubr(self, index, subr):
  112. cs = self.callingStack[-1]
  113. if not hasattr(cs, "_desubroutinized"):
  114. cs._patches.append((index, subr._desubroutinized))
  115. class CFFFontSet(object):
  116. """A CFF font "file" can contain more than one font, although this is
  117. extremely rare (and not allowed within OpenType fonts).
  118. This class is the entry point for parsing a CFF table. To actually
  119. manipulate the data inside the CFF font, you will want to access the
  120. ``CFFFontSet``'s :class:`TopDict` object. To do this, a ``CFFFontSet``
  121. object can either be treated as a dictionary (with appropriate
  122. ``keys()`` and ``values()`` methods) mapping font names to :class:`TopDict`
  123. objects, or as a list.
  124. .. code:: python
  125. from fontTools import ttLib
  126. tt = ttLib.TTFont("Tests/cffLib/data/LinLibertine_RBI.otf")
  127. tt["CFF "].cff
  128. # <fontTools.cffLib.CFFFontSet object at 0x101e24c90>
  129. tt["CFF "].cff[0] # Here's your actual font data
  130. # <fontTools.cffLib.TopDict object at 0x1020f1fd0>
  131. """
  132. def decompile(self, file, otFont, isCFF2=None):
  133. """Parse a binary CFF file into an internal representation. ``file``
  134. should be a file handle object. ``otFont`` is the top-level
  135. :py:class:`fontTools.ttLib.ttFont.TTFont` object containing this CFF file.
  136. If ``isCFF2`` is passed and set to ``True`` or ``False``, then the
  137. library makes an assertion that the CFF header is of the appropriate
  138. version.
  139. """
  140. self.otFont = otFont
  141. sstruct.unpack(cffHeaderFormat, file.read(3), self)
  142. if isCFF2 is not None:
  143. # called from ttLib: assert 'major' as read from file matches the
  144. # expected version
  145. expected_major = 2 if isCFF2 else 1
  146. if self.major != expected_major:
  147. raise ValueError(
  148. "Invalid CFF 'major' version: expected %d, found %d"
  149. % (expected_major, self.major)
  150. )
  151. else:
  152. # use 'major' version from file to determine if isCFF2
  153. assert self.major in (1, 2), "Unknown CFF format"
  154. isCFF2 = self.major == 2
  155. if not isCFF2:
  156. self.offSize = struct.unpack("B", file.read(1))[0]
  157. file.seek(self.hdrSize)
  158. self.fontNames = list(tostr(s) for s in Index(file, isCFF2=isCFF2))
  159. self.topDictIndex = TopDictIndex(file, isCFF2=isCFF2)
  160. self.strings = IndexedStrings(file)
  161. else: # isCFF2
  162. self.topDictSize = struct.unpack(">H", file.read(2))[0]
  163. file.seek(self.hdrSize)
  164. self.fontNames = ["CFF2Font"]
  165. cff2GetGlyphOrder = otFont.getGlyphOrder
  166. # in CFF2, offsetSize is the size of the TopDict data.
  167. self.topDictIndex = TopDictIndex(
  168. file, cff2GetGlyphOrder, self.topDictSize, isCFF2=isCFF2
  169. )
  170. self.strings = None
  171. self.GlobalSubrs = GlobalSubrsIndex(file, isCFF2=isCFF2)
  172. self.topDictIndex.strings = self.strings
  173. self.topDictIndex.GlobalSubrs = self.GlobalSubrs
  174. def __len__(self):
  175. return len(self.fontNames)
  176. def keys(self):
  177. return list(self.fontNames)
  178. def values(self):
  179. return self.topDictIndex
  180. def __getitem__(self, nameOrIndex):
  181. """Return TopDict instance identified by name (str) or index (int
  182. or any object that implements `__index__`).
  183. """
  184. if hasattr(nameOrIndex, "__index__"):
  185. index = nameOrIndex.__index__()
  186. elif isinstance(nameOrIndex, str):
  187. name = nameOrIndex
  188. try:
  189. index = self.fontNames.index(name)
  190. except ValueError:
  191. raise KeyError(nameOrIndex)
  192. else:
  193. raise TypeError(nameOrIndex)
  194. return self.topDictIndex[index]
  195. def compile(self, file, otFont, isCFF2=None):
  196. """Write the object back into binary representation onto the given file.
  197. ``file`` should be a file handle object. ``otFont`` is the top-level
  198. :py:class:`fontTools.ttLib.ttFont.TTFont` object containing this CFF file.
  199. If ``isCFF2`` is passed and set to ``True`` or ``False``, then the
  200. library makes an assertion that the CFF header is of the appropriate
  201. version.
  202. """
  203. self.otFont = otFont
  204. if isCFF2 is not None:
  205. # called from ttLib: assert 'major' value matches expected version
  206. expected_major = 2 if isCFF2 else 1
  207. if self.major != expected_major:
  208. raise ValueError(
  209. "Invalid CFF 'major' version: expected %d, found %d"
  210. % (expected_major, self.major)
  211. )
  212. else:
  213. # use current 'major' value to determine output format
  214. assert self.major in (1, 2), "Unknown CFF format"
  215. isCFF2 = self.major == 2
  216. if otFont.recalcBBoxes and not isCFF2:
  217. for topDict in self.topDictIndex:
  218. topDict.recalcFontBBox()
  219. if not isCFF2:
  220. strings = IndexedStrings()
  221. else:
  222. strings = None
  223. writer = CFFWriter(isCFF2)
  224. topCompiler = self.topDictIndex.getCompiler(strings, self, isCFF2=isCFF2)
  225. if isCFF2:
  226. self.hdrSize = 5
  227. writer.add(sstruct.pack(cffHeaderFormat, self))
  228. # Note: topDictSize will most likely change in CFFWriter.toFile().
  229. self.topDictSize = topCompiler.getDataLength()
  230. writer.add(struct.pack(">H", self.topDictSize))
  231. else:
  232. self.hdrSize = 4
  233. self.offSize = 4 # will most likely change in CFFWriter.toFile().
  234. writer.add(sstruct.pack(cffHeaderFormat, self))
  235. writer.add(struct.pack("B", self.offSize))
  236. if not isCFF2:
  237. fontNames = Index()
  238. for name in self.fontNames:
  239. fontNames.append(name)
  240. writer.add(fontNames.getCompiler(strings, self, isCFF2=isCFF2))
  241. writer.add(topCompiler)
  242. if not isCFF2:
  243. writer.add(strings.getCompiler())
  244. writer.add(self.GlobalSubrs.getCompiler(strings, self, isCFF2=isCFF2))
  245. for topDict in self.topDictIndex:
  246. if not hasattr(topDict, "charset") or topDict.charset is None:
  247. charset = otFont.getGlyphOrder()
  248. topDict.charset = charset
  249. children = topCompiler.getChildren(strings)
  250. for child in children:
  251. writer.add(child)
  252. writer.toFile(file)
  253. def toXML(self, xmlWriter):
  254. """Write the object into XML representation onto the given
  255. :class:`fontTools.misc.xmlWriter.XMLWriter`.
  256. .. code:: python
  257. writer = xmlWriter.XMLWriter(sys.stdout)
  258. tt["CFF "].cff.toXML(writer)
  259. """
  260. xmlWriter.simpletag("major", value=self.major)
  261. xmlWriter.newline()
  262. xmlWriter.simpletag("minor", value=self.minor)
  263. xmlWriter.newline()
  264. for fontName in self.fontNames:
  265. xmlWriter.begintag("CFFFont", name=tostr(fontName))
  266. xmlWriter.newline()
  267. font = self[fontName]
  268. font.toXML(xmlWriter)
  269. xmlWriter.endtag("CFFFont")
  270. xmlWriter.newline()
  271. xmlWriter.newline()
  272. xmlWriter.begintag("GlobalSubrs")
  273. xmlWriter.newline()
  274. self.GlobalSubrs.toXML(xmlWriter)
  275. xmlWriter.endtag("GlobalSubrs")
  276. xmlWriter.newline()
  277. def fromXML(self, name, attrs, content, otFont=None):
  278. """Reads data from the XML element into the ``CFFFontSet`` object."""
  279. self.otFont = otFont
  280. # set defaults. These will be replaced if there are entries for them
  281. # in the XML file.
  282. if not hasattr(self, "major"):
  283. self.major = 1
  284. if not hasattr(self, "minor"):
  285. self.minor = 0
  286. if name == "CFFFont":
  287. if self.major == 1:
  288. if not hasattr(self, "offSize"):
  289. # this will be recalculated when the cff is compiled.
  290. self.offSize = 4
  291. if not hasattr(self, "hdrSize"):
  292. self.hdrSize = 4
  293. if not hasattr(self, "GlobalSubrs"):
  294. self.GlobalSubrs = GlobalSubrsIndex()
  295. if not hasattr(self, "fontNames"):
  296. self.fontNames = []
  297. self.topDictIndex = TopDictIndex()
  298. fontName = attrs["name"]
  299. self.fontNames.append(fontName)
  300. topDict = TopDict(GlobalSubrs=self.GlobalSubrs)
  301. topDict.charset = None # gets filled in later
  302. elif self.major == 2:
  303. if not hasattr(self, "hdrSize"):
  304. self.hdrSize = 5
  305. if not hasattr(self, "GlobalSubrs"):
  306. self.GlobalSubrs = GlobalSubrsIndex()
  307. if not hasattr(self, "fontNames"):
  308. self.fontNames = ["CFF2Font"]
  309. cff2GetGlyphOrder = self.otFont.getGlyphOrder
  310. topDict = TopDict(
  311. GlobalSubrs=self.GlobalSubrs, cff2GetGlyphOrder=cff2GetGlyphOrder
  312. )
  313. self.topDictIndex = TopDictIndex(None, cff2GetGlyphOrder)
  314. self.topDictIndex.append(topDict)
  315. for element in content:
  316. if isinstance(element, str):
  317. continue
  318. name, attrs, content = element
  319. topDict.fromXML(name, attrs, content)
  320. if hasattr(topDict, "VarStore") and topDict.FDArray[0].vstore is None:
  321. fdArray = topDict.FDArray
  322. for fontDict in fdArray:
  323. if hasattr(fontDict, "Private"):
  324. fontDict.Private.vstore = topDict.VarStore
  325. elif name == "GlobalSubrs":
  326. subrCharStringClass = psCharStrings.T2CharString
  327. if not hasattr(self, "GlobalSubrs"):
  328. self.GlobalSubrs = GlobalSubrsIndex()
  329. for element in content:
  330. if isinstance(element, str):
  331. continue
  332. name, attrs, content = element
  333. subr = subrCharStringClass()
  334. subr.fromXML(name, attrs, content)
  335. self.GlobalSubrs.append(subr)
  336. elif name == "major":
  337. self.major = int(attrs["value"])
  338. elif name == "minor":
  339. self.minor = int(attrs["value"])
  340. def convertCFFToCFF2(self, otFont):
  341. """Converts this object from CFF format to CFF2 format. This conversion
  342. is done 'in-place'. The conversion cannot be reversed.
  343. This assumes a decompiled CFF table. (i.e. that the object has been
  344. filled via :meth:`decompile`.)"""
  345. self.major = 2
  346. cff2GetGlyphOrder = self.otFont.getGlyphOrder
  347. topDictData = TopDictIndex(None, cff2GetGlyphOrder)
  348. topDictData.items = self.topDictIndex.items
  349. self.topDictIndex = topDictData
  350. topDict = topDictData[0]
  351. if hasattr(topDict, "Private"):
  352. privateDict = topDict.Private
  353. else:
  354. privateDict = None
  355. opOrder = buildOrder(topDictOperators2)
  356. topDict.order = opOrder
  357. topDict.cff2GetGlyphOrder = cff2GetGlyphOrder
  358. for entry in topDictOperators:
  359. key = entry[1]
  360. if key not in opOrder:
  361. if key in topDict.rawDict:
  362. del topDict.rawDict[key]
  363. if hasattr(topDict, key):
  364. delattr(topDict, key)
  365. if not hasattr(topDict, "FDArray"):
  366. fdArray = topDict.FDArray = FDArrayIndex()
  367. fdArray.strings = None
  368. fdArray.GlobalSubrs = topDict.GlobalSubrs
  369. topDict.GlobalSubrs.fdArray = fdArray
  370. charStrings = topDict.CharStrings
  371. if charStrings.charStringsAreIndexed:
  372. charStrings.charStringsIndex.fdArray = fdArray
  373. else:
  374. charStrings.fdArray = fdArray
  375. fontDict = FontDict()
  376. fontDict.setCFF2(True)
  377. fdArray.append(fontDict)
  378. fontDict.Private = privateDict
  379. privateOpOrder = buildOrder(privateDictOperators2)
  380. for entry in privateDictOperators:
  381. key = entry[1]
  382. if key not in privateOpOrder:
  383. if key in privateDict.rawDict:
  384. # print "Removing private dict", key
  385. del privateDict.rawDict[key]
  386. if hasattr(privateDict, key):
  387. delattr(privateDict, key)
  388. # print "Removing privateDict attr", key
  389. else:
  390. # clean up the PrivateDicts in the fdArray
  391. fdArray = topDict.FDArray
  392. privateOpOrder = buildOrder(privateDictOperators2)
  393. for fontDict in fdArray:
  394. fontDict.setCFF2(True)
  395. for key in fontDict.rawDict.keys():
  396. if key not in fontDict.order:
  397. del fontDict.rawDict[key]
  398. if hasattr(fontDict, key):
  399. delattr(fontDict, key)
  400. privateDict = fontDict.Private
  401. for entry in privateDictOperators:
  402. key = entry[1]
  403. if key not in privateOpOrder:
  404. if key in privateDict.rawDict:
  405. # print "Removing private dict", key
  406. del privateDict.rawDict[key]
  407. if hasattr(privateDict, key):
  408. delattr(privateDict, key)
  409. # print "Removing privateDict attr", key
  410. # At this point, the Subrs and Charstrings are all still T2Charstring class
  411. # easiest to fix this by compiling, then decompiling again
  412. file = BytesIO()
  413. self.compile(file, otFont, isCFF2=True)
  414. file.seek(0)
  415. self.decompile(file, otFont, isCFF2=True)
  416. def desubroutinize(self):
  417. for fontName in self.fontNames:
  418. font = self[fontName]
  419. cs = font.CharStrings
  420. for g in font.charset:
  421. c, _ = cs.getItemAndSelector(g)
  422. c.decompile()
  423. subrs = getattr(c.private, "Subrs", [])
  424. decompiler = _DesubroutinizingT2Decompiler(
  425. subrs, c.globalSubrs, c.private
  426. )
  427. decompiler.execute(c)
  428. c.program = c._desubroutinized
  429. del c._desubroutinized
  430. # Delete all the local subrs
  431. if hasattr(font, "FDArray"):
  432. for fd in font.FDArray:
  433. pd = fd.Private
  434. if hasattr(pd, "Subrs"):
  435. del pd.Subrs
  436. if "Subrs" in pd.rawDict:
  437. del pd.rawDict["Subrs"]
  438. else:
  439. pd = font.Private
  440. if hasattr(pd, "Subrs"):
  441. del pd.Subrs
  442. if "Subrs" in pd.rawDict:
  443. del pd.rawDict["Subrs"]
  444. # as well as the global subrs
  445. self.GlobalSubrs.clear()
  446. class CFFWriter(object):
  447. """Helper class for serializing CFF data to binary. Used by
  448. :meth:`CFFFontSet.compile`."""
  449. def __init__(self, isCFF2):
  450. self.data = []
  451. self.isCFF2 = isCFF2
  452. def add(self, table):
  453. self.data.append(table)
  454. def toFile(self, file):
  455. lastPosList = None
  456. count = 1
  457. while True:
  458. log.log(DEBUG, "CFFWriter.toFile() iteration: %d", count)
  459. count = count + 1
  460. pos = 0
  461. posList = [pos]
  462. for item in self.data:
  463. if hasattr(item, "getDataLength"):
  464. endPos = pos + item.getDataLength()
  465. if isinstance(item, TopDictIndexCompiler) and item.isCFF2:
  466. self.topDictSize = item.getDataLength()
  467. else:
  468. endPos = pos + len(item)
  469. if hasattr(item, "setPos"):
  470. item.setPos(pos, endPos)
  471. pos = endPos
  472. posList.append(pos)
  473. if posList == lastPosList:
  474. break
  475. lastPosList = posList
  476. log.log(DEBUG, "CFFWriter.toFile() writing to file.")
  477. begin = file.tell()
  478. if self.isCFF2:
  479. self.data[1] = struct.pack(">H", self.topDictSize)
  480. else:
  481. self.offSize = calcOffSize(lastPosList[-1])
  482. self.data[1] = struct.pack("B", self.offSize)
  483. posList = [0]
  484. for item in self.data:
  485. if hasattr(item, "toFile"):
  486. item.toFile(file)
  487. else:
  488. file.write(item)
  489. posList.append(file.tell() - begin)
  490. assert posList == lastPosList
  491. def calcOffSize(largestOffset):
  492. if largestOffset < 0x100:
  493. offSize = 1
  494. elif largestOffset < 0x10000:
  495. offSize = 2
  496. elif largestOffset < 0x1000000:
  497. offSize = 3
  498. else:
  499. offSize = 4
  500. return offSize
  501. class IndexCompiler(object):
  502. """Base class for writing CFF `INDEX data <https://docs.microsoft.com/en-us/typography/opentype/spec/cff2#5-index-data>`_
  503. to binary."""
  504. def __init__(self, items, strings, parent, isCFF2=None):
  505. if isCFF2 is None and hasattr(parent, "isCFF2"):
  506. isCFF2 = parent.isCFF2
  507. assert isCFF2 is not None
  508. self.isCFF2 = isCFF2
  509. self.items = self.getItems(items, strings)
  510. self.parent = parent
  511. def getItems(self, items, strings):
  512. return items
  513. def getOffsets(self):
  514. # An empty INDEX contains only the count field.
  515. if self.items:
  516. pos = 1
  517. offsets = [pos]
  518. for item in self.items:
  519. if hasattr(item, "getDataLength"):
  520. pos = pos + item.getDataLength()
  521. else:
  522. pos = pos + len(item)
  523. offsets.append(pos)
  524. else:
  525. offsets = []
  526. return offsets
  527. def getDataLength(self):
  528. if self.isCFF2:
  529. countSize = 4
  530. else:
  531. countSize = 2
  532. if self.items:
  533. lastOffset = self.getOffsets()[-1]
  534. offSize = calcOffSize(lastOffset)
  535. dataLength = (
  536. countSize
  537. + 1 # count
  538. + (len(self.items) + 1) * offSize # offSize
  539. + lastOffset # the offsets
  540. - 1 # size of object data
  541. )
  542. else:
  543. # count. For empty INDEX tables, this is the only entry.
  544. dataLength = countSize
  545. return dataLength
  546. def toFile(self, file):
  547. offsets = self.getOffsets()
  548. if self.isCFF2:
  549. writeCard32(file, len(self.items))
  550. else:
  551. writeCard16(file, len(self.items))
  552. # An empty INDEX contains only the count field.
  553. if self.items:
  554. offSize = calcOffSize(offsets[-1])
  555. writeCard8(file, offSize)
  556. offSize = -offSize
  557. pack = struct.pack
  558. for offset in offsets:
  559. binOffset = pack(">l", offset)[offSize:]
  560. assert len(binOffset) == -offSize
  561. file.write(binOffset)
  562. for item in self.items:
  563. if hasattr(item, "toFile"):
  564. item.toFile(file)
  565. else:
  566. data = tobytes(item, encoding="latin1")
  567. file.write(data)
  568. class IndexedStringsCompiler(IndexCompiler):
  569. def getItems(self, items, strings):
  570. return items.strings
  571. class TopDictIndexCompiler(IndexCompiler):
  572. """Helper class for writing the TopDict to binary."""
  573. def getItems(self, items, strings):
  574. out = []
  575. for item in items:
  576. out.append(item.getCompiler(strings, self))
  577. return out
  578. def getChildren(self, strings):
  579. children = []
  580. for topDict in self.items:
  581. children.extend(topDict.getChildren(strings))
  582. return children
  583. def getOffsets(self):
  584. if self.isCFF2:
  585. offsets = [0, self.items[0].getDataLength()]
  586. return offsets
  587. else:
  588. return super(TopDictIndexCompiler, self).getOffsets()
  589. def getDataLength(self):
  590. if self.isCFF2:
  591. dataLength = self.items[0].getDataLength()
  592. return dataLength
  593. else:
  594. return super(TopDictIndexCompiler, self).getDataLength()
  595. def toFile(self, file):
  596. if self.isCFF2:
  597. self.items[0].toFile(file)
  598. else:
  599. super(TopDictIndexCompiler, self).toFile(file)
  600. class FDArrayIndexCompiler(IndexCompiler):
  601. """Helper class for writing the
  602. `Font DICT INDEX <https://docs.microsoft.com/en-us/typography/opentype/spec/cff2#10-font-dict-index-font-dicts-and-fdselect>`_
  603. to binary."""
  604. def getItems(self, items, strings):
  605. out = []
  606. for item in items:
  607. out.append(item.getCompiler(strings, self))
  608. return out
  609. def getChildren(self, strings):
  610. children = []
  611. for fontDict in self.items:
  612. children.extend(fontDict.getChildren(strings))
  613. return children
  614. def toFile(self, file):
  615. offsets = self.getOffsets()
  616. if self.isCFF2:
  617. writeCard32(file, len(self.items))
  618. else:
  619. writeCard16(file, len(self.items))
  620. offSize = calcOffSize(offsets[-1])
  621. writeCard8(file, offSize)
  622. offSize = -offSize
  623. pack = struct.pack
  624. for offset in offsets:
  625. binOffset = pack(">l", offset)[offSize:]
  626. assert len(binOffset) == -offSize
  627. file.write(binOffset)
  628. for item in self.items:
  629. if hasattr(item, "toFile"):
  630. item.toFile(file)
  631. else:
  632. file.write(item)
  633. def setPos(self, pos, endPos):
  634. self.parent.rawDict["FDArray"] = pos
  635. class GlobalSubrsCompiler(IndexCompiler):
  636. """Helper class for writing the `global subroutine INDEX <https://docs.microsoft.com/en-us/typography/opentype/spec/cff2#9-local-and-global-subr-indexes>`_
  637. to binary."""
  638. def getItems(self, items, strings):
  639. out = []
  640. for cs in items:
  641. cs.compile(self.isCFF2)
  642. out.append(cs.bytecode)
  643. return out
  644. class SubrsCompiler(GlobalSubrsCompiler):
  645. """Helper class for writing the `local subroutine INDEX <https://docs.microsoft.com/en-us/typography/opentype/spec/cff2#9-local-and-global-subr-indexes>`_
  646. to binary."""
  647. def setPos(self, pos, endPos):
  648. offset = pos - self.parent.pos
  649. self.parent.rawDict["Subrs"] = offset
  650. class CharStringsCompiler(GlobalSubrsCompiler):
  651. """Helper class for writing the `CharStrings INDEX <https://docs.microsoft.com/en-us/typography/opentype/spec/cff2#9-local-and-global-subr-indexes>`_
  652. to binary."""
  653. def getItems(self, items, strings):
  654. out = []
  655. for cs in items:
  656. cs.compile(self.isCFF2)
  657. out.append(cs.bytecode)
  658. return out
  659. def setPos(self, pos, endPos):
  660. self.parent.rawDict["CharStrings"] = pos
  661. class Index(object):
  662. """This class represents what the CFF spec calls an INDEX (an array of
  663. variable-sized objects). `Index` items can be addressed and set using
  664. Python list indexing."""
  665. compilerClass = IndexCompiler
  666. def __init__(self, file=None, isCFF2=None):
  667. assert (isCFF2 is None) == (file is None)
  668. self.items = []
  669. name = self.__class__.__name__
  670. if file is None:
  671. return
  672. self._isCFF2 = isCFF2
  673. log.log(DEBUG, "loading %s at %s", name, file.tell())
  674. self.file = file
  675. if isCFF2:
  676. count = readCard32(file)
  677. else:
  678. count = readCard16(file)
  679. if count == 0:
  680. return
  681. self.items = [None] * count
  682. offSize = readCard8(file)
  683. log.log(DEBUG, " index count: %s offSize: %s", count, offSize)
  684. assert offSize <= 4, "offSize too large: %s" % offSize
  685. self.offsets = offsets = []
  686. pad = b"\0" * (4 - offSize)
  687. for index in range(count + 1):
  688. chunk = file.read(offSize)
  689. chunk = pad + chunk
  690. (offset,) = struct.unpack(">L", chunk)
  691. offsets.append(int(offset))
  692. self.offsetBase = file.tell() - 1
  693. file.seek(self.offsetBase + offsets[-1]) # pretend we've read the whole lot
  694. log.log(DEBUG, " end of %s at %s", name, file.tell())
  695. def __len__(self):
  696. return len(self.items)
  697. def __getitem__(self, index):
  698. item = self.items[index]
  699. if item is not None:
  700. return item
  701. offset = self.offsets[index] + self.offsetBase
  702. size = self.offsets[index + 1] - self.offsets[index]
  703. file = self.file
  704. file.seek(offset)
  705. data = file.read(size)
  706. assert len(data) == size
  707. item = self.produceItem(index, data, file, offset)
  708. self.items[index] = item
  709. return item
  710. def __setitem__(self, index, item):
  711. self.items[index] = item
  712. def produceItem(self, index, data, file, offset):
  713. return data
  714. def append(self, item):
  715. """Add an item to an INDEX."""
  716. self.items.append(item)
  717. def getCompiler(self, strings, parent, isCFF2=None):
  718. return self.compilerClass(self, strings, parent, isCFF2=isCFF2)
  719. def clear(self):
  720. """Empty the INDEX."""
  721. del self.items[:]
  722. class GlobalSubrsIndex(Index):
  723. """This index contains all the global subroutines in the font. A global
  724. subroutine is a set of ``CharString`` data which is accessible to any
  725. glyph in the font, and are used to store repeated instructions - for
  726. example, components may be encoded as global subroutines, but so could
  727. hinting instructions.
  728. Remember that when interpreting a ``callgsubr`` instruction (or indeed
  729. a ``callsubr`` instruction) that you will need to add the "subroutine
  730. number bias" to number given:
  731. .. code:: python
  732. tt = ttLib.TTFont("Almendra-Bold.otf")
  733. u = tt["CFF "].cff[0].CharStrings["udieresis"]
  734. u.decompile()
  735. u.toXML(XMLWriter(sys.stdout))
  736. # <some stuff>
  737. # -64 callgsubr <-- Subroutine which implements the dieresis mark
  738. # <other stuff>
  739. tt["CFF "].cff[0].GlobalSubrs[-64] # <-- WRONG
  740. # <T2CharString (bytecode) at 103451d10>
  741. tt["CFF "].cff[0].GlobalSubrs[-64 + 107] # <-- RIGHT
  742. # <T2CharString (source) at 103451390>
  743. ("The bias applied depends on the number of subrs (gsubrs). If the number of
  744. subrs (gsubrs) is less than 1240, the bias is 107. Otherwise if it is less
  745. than 33900, it is 1131; otherwise it is 32768.",
  746. `Subroutine Operators <https://docs.microsoft.com/en-us/typography/opentype/otspec180/cff2charstr#section4.4>`)
  747. """
  748. compilerClass = GlobalSubrsCompiler
  749. subrClass = psCharStrings.T2CharString
  750. charStringClass = psCharStrings.T2CharString
  751. def __init__(
  752. self,
  753. file=None,
  754. globalSubrs=None,
  755. private=None,
  756. fdSelect=None,
  757. fdArray=None,
  758. isCFF2=None,
  759. ):
  760. super(GlobalSubrsIndex, self).__init__(file, isCFF2=isCFF2)
  761. self.globalSubrs = globalSubrs
  762. self.private = private
  763. if fdSelect:
  764. self.fdSelect = fdSelect
  765. if fdArray:
  766. self.fdArray = fdArray
  767. def produceItem(self, index, data, file, offset):
  768. if self.private is not None:
  769. private = self.private
  770. elif hasattr(self, "fdArray") and self.fdArray is not None:
  771. if hasattr(self, "fdSelect") and self.fdSelect is not None:
  772. fdIndex = self.fdSelect[index]
  773. else:
  774. fdIndex = 0
  775. private = self.fdArray[fdIndex].Private
  776. else:
  777. private = None
  778. return self.subrClass(data, private=private, globalSubrs=self.globalSubrs)
  779. def toXML(self, xmlWriter):
  780. """Write the subroutines index into XML representation onto the given
  781. :class:`fontTools.misc.xmlWriter.XMLWriter`.
  782. .. code:: python
  783. writer = xmlWriter.XMLWriter(sys.stdout)
  784. tt["CFF "].cff[0].GlobalSubrs.toXML(writer)
  785. """
  786. xmlWriter.comment(
  787. "The 'index' attribute is only for humans; " "it is ignored when parsed."
  788. )
  789. xmlWriter.newline()
  790. for i in range(len(self)):
  791. subr = self[i]
  792. if subr.needsDecompilation():
  793. xmlWriter.begintag("CharString", index=i, raw=1)
  794. else:
  795. xmlWriter.begintag("CharString", index=i)
  796. xmlWriter.newline()
  797. subr.toXML(xmlWriter)
  798. xmlWriter.endtag("CharString")
  799. xmlWriter.newline()
  800. def fromXML(self, name, attrs, content):
  801. if name != "CharString":
  802. return
  803. subr = self.subrClass()
  804. subr.fromXML(name, attrs, content)
  805. self.append(subr)
  806. def getItemAndSelector(self, index):
  807. sel = None
  808. if hasattr(self, "fdSelect"):
  809. sel = self.fdSelect[index]
  810. return self[index], sel
  811. class SubrsIndex(GlobalSubrsIndex):
  812. """This index contains a glyph's local subroutines. A local subroutine is a
  813. private set of ``CharString`` data which is accessible only to the glyph to
  814. which the index is attached."""
  815. compilerClass = SubrsCompiler
  816. class TopDictIndex(Index):
  817. """This index represents the array of ``TopDict`` structures in the font
  818. (again, usually only one entry is present). Hence the following calls are
  819. equivalent:
  820. .. code:: python
  821. tt["CFF "].cff[0]
  822. # <fontTools.cffLib.TopDict object at 0x102ed6e50>
  823. tt["CFF "].cff.topDictIndex[0]
  824. # <fontTools.cffLib.TopDict object at 0x102ed6e50>
  825. """
  826. compilerClass = TopDictIndexCompiler
  827. def __init__(self, file=None, cff2GetGlyphOrder=None, topSize=0, isCFF2=None):
  828. assert (isCFF2 is None) == (file is None)
  829. self.cff2GetGlyphOrder = cff2GetGlyphOrder
  830. if file is not None and isCFF2:
  831. self._isCFF2 = isCFF2
  832. self.items = []
  833. name = self.__class__.__name__
  834. log.log(DEBUG, "loading %s at %s", name, file.tell())
  835. self.file = file
  836. count = 1
  837. self.items = [None] * count
  838. self.offsets = [0, topSize]
  839. self.offsetBase = file.tell()
  840. # pretend we've read the whole lot
  841. file.seek(self.offsetBase + topSize)
  842. log.log(DEBUG, " end of %s at %s", name, file.tell())
  843. else:
  844. super(TopDictIndex, self).__init__(file, isCFF2=isCFF2)
  845. def produceItem(self, index, data, file, offset):
  846. top = TopDict(
  847. self.strings,
  848. file,
  849. offset,
  850. self.GlobalSubrs,
  851. self.cff2GetGlyphOrder,
  852. isCFF2=self._isCFF2,
  853. )
  854. top.decompile(data)
  855. return top
  856. def toXML(self, xmlWriter):
  857. for i in range(len(self)):
  858. xmlWriter.begintag("FontDict", index=i)
  859. xmlWriter.newline()
  860. self[i].toXML(xmlWriter)
  861. xmlWriter.endtag("FontDict")
  862. xmlWriter.newline()
  863. class FDArrayIndex(Index):
  864. compilerClass = FDArrayIndexCompiler
  865. def toXML(self, xmlWriter):
  866. for i in range(len(self)):
  867. xmlWriter.begintag("FontDict", index=i)
  868. xmlWriter.newline()
  869. self[i].toXML(xmlWriter)
  870. xmlWriter.endtag("FontDict")
  871. xmlWriter.newline()
  872. def produceItem(self, index, data, file, offset):
  873. fontDict = FontDict(
  874. self.strings,
  875. file,
  876. offset,
  877. self.GlobalSubrs,
  878. isCFF2=self._isCFF2,
  879. vstore=self.vstore,
  880. )
  881. fontDict.decompile(data)
  882. return fontDict
  883. def fromXML(self, name, attrs, content):
  884. if name != "FontDict":
  885. return
  886. fontDict = FontDict()
  887. for element in content:
  888. if isinstance(element, str):
  889. continue
  890. name, attrs, content = element
  891. fontDict.fromXML(name, attrs, content)
  892. self.append(fontDict)
  893. class VarStoreData(object):
  894. def __init__(self, file=None, otVarStore=None):
  895. self.file = file
  896. self.data = None
  897. self.otVarStore = otVarStore
  898. self.font = TTFont() # dummy font for the decompile function.
  899. def decompile(self):
  900. if self.file:
  901. # read data in from file. Assume position is correct.
  902. length = readCard16(self.file)
  903. self.data = self.file.read(length)
  904. globalState = {}
  905. reader = OTTableReader(self.data, globalState)
  906. self.otVarStore = ot.VarStore()
  907. self.otVarStore.decompile(reader, self.font)
  908. return self
  909. def compile(self):
  910. writer = OTTableWriter()
  911. self.otVarStore.compile(writer, self.font)
  912. # Note that this omits the initial Card16 length from the CFF2
  913. # VarStore data block
  914. self.data = writer.getAllData()
  915. def writeXML(self, xmlWriter, name):
  916. self.otVarStore.toXML(xmlWriter, self.font)
  917. def xmlRead(self, name, attrs, content, parent):
  918. self.otVarStore = ot.VarStore()
  919. for element in content:
  920. if isinstance(element, tuple):
  921. name, attrs, content = element
  922. self.otVarStore.fromXML(name, attrs, content, self.font)
  923. else:
  924. pass
  925. return None
  926. def __len__(self):
  927. return len(self.data)
  928. def getNumRegions(self, vsIndex):
  929. if vsIndex is None:
  930. vsIndex = 0
  931. varData = self.otVarStore.VarData[vsIndex]
  932. numRegions = varData.VarRegionCount
  933. return numRegions
  934. class FDSelect(object):
  935. def __init__(self, file=None, numGlyphs=None, format=None):
  936. if file:
  937. # read data in from file
  938. self.format = readCard8(file)
  939. if self.format == 0:
  940. from array import array
  941. self.gidArray = array("B", file.read(numGlyphs)).tolist()
  942. elif self.format == 3:
  943. gidArray = [None] * numGlyphs
  944. nRanges = readCard16(file)
  945. fd = None
  946. prev = None
  947. for i in range(nRanges):
  948. first = readCard16(file)
  949. if prev is not None:
  950. for glyphID in range(prev, first):
  951. gidArray[glyphID] = fd
  952. prev = first
  953. fd = readCard8(file)
  954. if prev is not None:
  955. first = readCard16(file)
  956. for glyphID in range(prev, first):
  957. gidArray[glyphID] = fd
  958. self.gidArray = gidArray
  959. elif self.format == 4:
  960. gidArray = [None] * numGlyphs
  961. nRanges = readCard32(file)
  962. fd = None
  963. prev = None
  964. for i in range(nRanges):
  965. first = readCard32(file)
  966. if prev is not None:
  967. for glyphID in range(prev, first):
  968. gidArray[glyphID] = fd
  969. prev = first
  970. fd = readCard16(file)
  971. if prev is not None:
  972. first = readCard32(file)
  973. for glyphID in range(prev, first):
  974. gidArray[glyphID] = fd
  975. self.gidArray = gidArray
  976. else:
  977. assert False, "unsupported FDSelect format: %s" % format
  978. else:
  979. # reading from XML. Make empty gidArray, and leave format as passed in.
  980. # format is None will result in the smallest representation being used.
  981. self.format = format
  982. self.gidArray = []
  983. def __len__(self):
  984. return len(self.gidArray)
  985. def __getitem__(self, index):
  986. return self.gidArray[index]
  987. def __setitem__(self, index, fdSelectValue):
  988. self.gidArray[index] = fdSelectValue
  989. def append(self, fdSelectValue):
  990. self.gidArray.append(fdSelectValue)
  991. class CharStrings(object):
  992. """The ``CharStrings`` in the font represent the instructions for drawing
  993. each glyph. This object presents a dictionary interface to the font's
  994. CharStrings, indexed by glyph name:
  995. .. code:: python
  996. tt["CFF "].cff[0].CharStrings["a"]
  997. # <T2CharString (bytecode) at 103451e90>
  998. See :class:`fontTools.misc.psCharStrings.T1CharString` and
  999. :class:`fontTools.misc.psCharStrings.T2CharString` for how to decompile,
  1000. compile and interpret the glyph drawing instructions in the returned objects.
  1001. """
  1002. def __init__(
  1003. self,
  1004. file,
  1005. charset,
  1006. globalSubrs,
  1007. private,
  1008. fdSelect,
  1009. fdArray,
  1010. isCFF2=None,
  1011. varStore=None,
  1012. ):
  1013. self.globalSubrs = globalSubrs
  1014. self.varStore = varStore
  1015. if file is not None:
  1016. self.charStringsIndex = SubrsIndex(
  1017. file, globalSubrs, private, fdSelect, fdArray, isCFF2=isCFF2
  1018. )
  1019. self.charStrings = charStrings = {}
  1020. for i in range(len(charset)):
  1021. charStrings[charset[i]] = i
  1022. # read from OTF file: charStrings.values() are indices into
  1023. # charStringsIndex.
  1024. self.charStringsAreIndexed = 1
  1025. else:
  1026. self.charStrings = {}
  1027. # read from ttx file: charStrings.values() are actual charstrings
  1028. self.charStringsAreIndexed = 0
  1029. self.private = private
  1030. if fdSelect is not None:
  1031. self.fdSelect = fdSelect
  1032. if fdArray is not None:
  1033. self.fdArray = fdArray
  1034. def keys(self):
  1035. return list(self.charStrings.keys())
  1036. def values(self):
  1037. if self.charStringsAreIndexed:
  1038. return self.charStringsIndex
  1039. else:
  1040. return list(self.charStrings.values())
  1041. def has_key(self, name):
  1042. return name in self.charStrings
  1043. __contains__ = has_key
  1044. def __len__(self):
  1045. return len(self.charStrings)
  1046. def __getitem__(self, name):
  1047. charString = self.charStrings[name]
  1048. if self.charStringsAreIndexed:
  1049. charString = self.charStringsIndex[charString]
  1050. return charString
  1051. def __setitem__(self, name, charString):
  1052. if self.charStringsAreIndexed:
  1053. index = self.charStrings[name]
  1054. self.charStringsIndex[index] = charString
  1055. else:
  1056. self.charStrings[name] = charString
  1057. def getItemAndSelector(self, name):
  1058. if self.charStringsAreIndexed:
  1059. index = self.charStrings[name]
  1060. return self.charStringsIndex.getItemAndSelector(index)
  1061. else:
  1062. if hasattr(self, "fdArray"):
  1063. if hasattr(self, "fdSelect"):
  1064. sel = self.charStrings[name].fdSelectIndex
  1065. else:
  1066. sel = 0
  1067. else:
  1068. sel = None
  1069. return self.charStrings[name], sel
  1070. def toXML(self, xmlWriter):
  1071. names = sorted(self.keys())
  1072. for name in names:
  1073. charStr, fdSelectIndex = self.getItemAndSelector(name)
  1074. if charStr.needsDecompilation():
  1075. raw = [("raw", 1)]
  1076. else:
  1077. raw = []
  1078. if fdSelectIndex is None:
  1079. xmlWriter.begintag("CharString", [("name", name)] + raw)
  1080. else:
  1081. xmlWriter.begintag(
  1082. "CharString",
  1083. [("name", name), ("fdSelectIndex", fdSelectIndex)] + raw,
  1084. )
  1085. xmlWriter.newline()
  1086. charStr.toXML(xmlWriter)
  1087. xmlWriter.endtag("CharString")
  1088. xmlWriter.newline()
  1089. def fromXML(self, name, attrs, content):
  1090. for element in content:
  1091. if isinstance(element, str):
  1092. continue
  1093. name, attrs, content = element
  1094. if name != "CharString":
  1095. continue
  1096. fdID = -1
  1097. if hasattr(self, "fdArray"):
  1098. try:
  1099. fdID = safeEval(attrs["fdSelectIndex"])
  1100. except KeyError:
  1101. fdID = 0
  1102. private = self.fdArray[fdID].Private
  1103. else:
  1104. private = self.private
  1105. glyphName = attrs["name"]
  1106. charStringClass = psCharStrings.T2CharString
  1107. charString = charStringClass(private=private, globalSubrs=self.globalSubrs)
  1108. charString.fromXML(name, attrs, content)
  1109. if fdID >= 0:
  1110. charString.fdSelectIndex = fdID
  1111. self[glyphName] = charString
  1112. def readCard8(file):
  1113. return byteord(file.read(1))
  1114. def readCard16(file):
  1115. (value,) = struct.unpack(">H", file.read(2))
  1116. return value
  1117. def readCard32(file):
  1118. (value,) = struct.unpack(">L", file.read(4))
  1119. return value
  1120. def writeCard8(file, value):
  1121. file.write(bytechr(value))
  1122. def writeCard16(file, value):
  1123. file.write(struct.pack(">H", value))
  1124. def writeCard32(file, value):
  1125. file.write(struct.pack(">L", value))
  1126. def packCard8(value):
  1127. return bytechr(value)
  1128. def packCard16(value):
  1129. return struct.pack(">H", value)
  1130. def packCard32(value):
  1131. return struct.pack(">L", value)
  1132. def buildOperatorDict(table):
  1133. d = {}
  1134. for op, name, arg, default, conv in table:
  1135. d[op] = (name, arg)
  1136. return d
  1137. def buildOpcodeDict(table):
  1138. d = {}
  1139. for op, name, arg, default, conv in table:
  1140. if isinstance(op, tuple):
  1141. op = bytechr(op[0]) + bytechr(op[1])
  1142. else:
  1143. op = bytechr(op)
  1144. d[name] = (op, arg)
  1145. return d
  1146. def buildOrder(table):
  1147. l = []
  1148. for op, name, arg, default, conv in table:
  1149. l.append(name)
  1150. return l
  1151. def buildDefaults(table):
  1152. d = {}
  1153. for op, name, arg, default, conv in table:
  1154. if default is not None:
  1155. d[name] = default
  1156. return d
  1157. def buildConverters(table):
  1158. d = {}
  1159. for op, name, arg, default, conv in table:
  1160. d[name] = conv
  1161. return d
  1162. class SimpleConverter(object):
  1163. def read(self, parent, value):
  1164. if not hasattr(parent, "file"):
  1165. return self._read(parent, value)
  1166. file = parent.file
  1167. pos = file.tell()
  1168. try:
  1169. return self._read(parent, value)
  1170. finally:
  1171. file.seek(pos)
  1172. def _read(self, parent, value):
  1173. return value
  1174. def write(self, parent, value):
  1175. return value
  1176. def xmlWrite(self, xmlWriter, name, value):
  1177. xmlWriter.simpletag(name, value=value)
  1178. xmlWriter.newline()
  1179. def xmlRead(self, name, attrs, content, parent):
  1180. return attrs["value"]
  1181. class ASCIIConverter(SimpleConverter):
  1182. def _read(self, parent, value):
  1183. return tostr(value, encoding="ascii")
  1184. def write(self, parent, value):
  1185. return tobytes(value, encoding="ascii")
  1186. def xmlWrite(self, xmlWriter, name, value):
  1187. xmlWriter.simpletag(name, value=tostr(value, encoding="ascii"))
  1188. xmlWriter.newline()
  1189. def xmlRead(self, name, attrs, content, parent):
  1190. return tobytes(attrs["value"], encoding=("ascii"))
  1191. class Latin1Converter(SimpleConverter):
  1192. def _read(self, parent, value):
  1193. return tostr(value, encoding="latin1")
  1194. def write(self, parent, value):
  1195. return tobytes(value, encoding="latin1")
  1196. def xmlWrite(self, xmlWriter, name, value):
  1197. value = tostr(value, encoding="latin1")
  1198. if name in ["Notice", "Copyright"]:
  1199. value = re.sub(r"[\r\n]\s+", " ", value)
  1200. xmlWriter.simpletag(name, value=value)
  1201. xmlWriter.newline()
  1202. def xmlRead(self, name, attrs, content, parent):
  1203. return tobytes(attrs["value"], encoding=("latin1"))
  1204. def parseNum(s):
  1205. try:
  1206. value = int(s)
  1207. except:
  1208. value = float(s)
  1209. return value
  1210. def parseBlendList(s):
  1211. valueList = []
  1212. for element in s:
  1213. if isinstance(element, str):
  1214. continue
  1215. name, attrs, content = element
  1216. blendList = attrs["value"].split()
  1217. blendList = [eval(val) for val in blendList]
  1218. valueList.append(blendList)
  1219. if len(valueList) == 1:
  1220. valueList = valueList[0]
  1221. return valueList
  1222. class NumberConverter(SimpleConverter):
  1223. def xmlWrite(self, xmlWriter, name, value):
  1224. if isinstance(value, list):
  1225. xmlWriter.begintag(name)
  1226. xmlWriter.newline()
  1227. xmlWriter.indent()
  1228. blendValue = " ".join([str(val) for val in value])
  1229. xmlWriter.simpletag(kBlendDictOpName, value=blendValue)
  1230. xmlWriter.newline()
  1231. xmlWriter.dedent()
  1232. xmlWriter.endtag(name)
  1233. xmlWriter.newline()
  1234. else:
  1235. xmlWriter.simpletag(name, value=value)
  1236. xmlWriter.newline()
  1237. def xmlRead(self, name, attrs, content, parent):
  1238. valueString = attrs.get("value", None)
  1239. if valueString is None:
  1240. value = parseBlendList(content)
  1241. else:
  1242. value = parseNum(attrs["value"])
  1243. return value
  1244. class ArrayConverter(SimpleConverter):
  1245. def xmlWrite(self, xmlWriter, name, value):
  1246. if value and isinstance(value[0], list):
  1247. xmlWriter.begintag(name)
  1248. xmlWriter.newline()
  1249. xmlWriter.indent()
  1250. for valueList in value:
  1251. blendValue = " ".join([str(val) for val in valueList])
  1252. xmlWriter.simpletag(kBlendDictOpName, value=blendValue)
  1253. xmlWriter.newline()
  1254. xmlWriter.dedent()
  1255. xmlWriter.endtag(name)
  1256. xmlWriter.newline()
  1257. else:
  1258. value = " ".join([str(val) for val in value])
  1259. xmlWriter.simpletag(name, value=value)
  1260. xmlWriter.newline()
  1261. def xmlRead(self, name, attrs, content, parent):
  1262. valueString = attrs.get("value", None)
  1263. if valueString is None:
  1264. valueList = parseBlendList(content)
  1265. else:
  1266. values = valueString.split()
  1267. valueList = [parseNum(value) for value in values]
  1268. return valueList
  1269. class TableConverter(SimpleConverter):
  1270. def xmlWrite(self, xmlWriter, name, value):
  1271. xmlWriter.begintag(name)
  1272. xmlWriter.newline()
  1273. value.toXML(xmlWriter)
  1274. xmlWriter.endtag(name)
  1275. xmlWriter.newline()
  1276. def xmlRead(self, name, attrs, content, parent):
  1277. ob = self.getClass()()
  1278. for element in content:
  1279. if isinstance(element, str):
  1280. continue
  1281. name, attrs, content = element
  1282. ob.fromXML(name, attrs, content)
  1283. return ob
  1284. class PrivateDictConverter(TableConverter):
  1285. def getClass(self):
  1286. return PrivateDict
  1287. def _read(self, parent, value):
  1288. size, offset = value
  1289. file = parent.file
  1290. isCFF2 = parent._isCFF2
  1291. try:
  1292. vstore = parent.vstore
  1293. except AttributeError:
  1294. vstore = None
  1295. priv = PrivateDict(parent.strings, file, offset, isCFF2=isCFF2, vstore=vstore)
  1296. file.seek(offset)
  1297. data = file.read(size)
  1298. assert len(data) == size
  1299. priv.decompile(data)
  1300. return priv
  1301. def write(self, parent, value):
  1302. return (0, 0) # dummy value
  1303. class SubrsConverter(TableConverter):
  1304. def getClass(self):
  1305. return SubrsIndex
  1306. def _read(self, parent, value):
  1307. file = parent.file
  1308. isCFF2 = parent._isCFF2
  1309. file.seek(parent.offset + value) # Offset(self)
  1310. return SubrsIndex(file, isCFF2=isCFF2)
  1311. def write(self, parent, value):
  1312. return 0 # dummy value
  1313. class CharStringsConverter(TableConverter):
  1314. def _read(self, parent, value):
  1315. file = parent.file
  1316. isCFF2 = parent._isCFF2
  1317. charset = parent.charset
  1318. varStore = getattr(parent, "VarStore", None)
  1319. globalSubrs = parent.GlobalSubrs
  1320. if hasattr(parent, "FDArray"):
  1321. fdArray = parent.FDArray
  1322. if hasattr(parent, "FDSelect"):
  1323. fdSelect = parent.FDSelect
  1324. else:
  1325. fdSelect = None
  1326. private = None
  1327. else:
  1328. fdSelect, fdArray = None, None
  1329. private = parent.Private
  1330. file.seek(value) # Offset(0)
  1331. charStrings = CharStrings(
  1332. file,
  1333. charset,
  1334. globalSubrs,
  1335. private,
  1336. fdSelect,
  1337. fdArray,
  1338. isCFF2=isCFF2,
  1339. varStore=varStore,
  1340. )
  1341. return charStrings
  1342. def write(self, parent, value):
  1343. return 0 # dummy value
  1344. def xmlRead(self, name, attrs, content, parent):
  1345. if hasattr(parent, "FDArray"):
  1346. # if it is a CID-keyed font, then the private Dict is extracted from the
  1347. # parent.FDArray
  1348. fdArray = parent.FDArray
  1349. if hasattr(parent, "FDSelect"):
  1350. fdSelect = parent.FDSelect
  1351. else:
  1352. fdSelect = None
  1353. private = None
  1354. else:
  1355. # if it is a name-keyed font, then the private dict is in the top dict,
  1356. # and
  1357. # there is no fdArray.
  1358. private, fdSelect, fdArray = parent.Private, None, None
  1359. charStrings = CharStrings(
  1360. None,
  1361. None,
  1362. parent.GlobalSubrs,
  1363. private,
  1364. fdSelect,
  1365. fdArray,
  1366. varStore=getattr(parent, "VarStore", None),
  1367. )
  1368. charStrings.fromXML(name, attrs, content)
  1369. return charStrings
  1370. class CharsetConverter(SimpleConverter):
  1371. def _read(self, parent, value):
  1372. isCID = hasattr(parent, "ROS")
  1373. if value > 2:
  1374. numGlyphs = parent.numGlyphs
  1375. file = parent.file
  1376. file.seek(value)
  1377. log.log(DEBUG, "loading charset at %s", value)
  1378. format = readCard8(file)
  1379. if format == 0:
  1380. charset = parseCharset0(numGlyphs, file, parent.strings, isCID)
  1381. elif format == 1 or format == 2:
  1382. charset = parseCharset(numGlyphs, file, parent.strings, isCID, format)
  1383. else:
  1384. raise NotImplementedError
  1385. assert len(charset) == numGlyphs
  1386. log.log(DEBUG, " charset end at %s", file.tell())
  1387. # make sure glyph names are unique
  1388. allNames = {}
  1389. newCharset = []
  1390. for glyphName in charset:
  1391. if glyphName in allNames:
  1392. # make up a new glyphName that's unique
  1393. n = allNames[glyphName]
  1394. while (glyphName + "#" + str(n)) in allNames:
  1395. n += 1
  1396. allNames[glyphName] = n + 1
  1397. glyphName = glyphName + "#" + str(n)
  1398. allNames[glyphName] = 1
  1399. newCharset.append(glyphName)
  1400. charset = newCharset
  1401. else: # offset == 0 -> no charset data.
  1402. if isCID or "CharStrings" not in parent.rawDict:
  1403. # We get here only when processing fontDicts from the FDArray of
  1404. # CFF-CID fonts. Only the real topDict references the chrset.
  1405. assert value == 0
  1406. charset = None
  1407. elif value == 0:
  1408. charset = cffISOAdobeStrings
  1409. elif value == 1:
  1410. charset = cffIExpertStrings
  1411. elif value == 2:
  1412. charset = cffExpertSubsetStrings
  1413. if charset and (len(charset) != parent.numGlyphs):
  1414. charset = charset[: parent.numGlyphs]
  1415. return charset
  1416. def write(self, parent, value):
  1417. return 0 # dummy value
  1418. def xmlWrite(self, xmlWriter, name, value):
  1419. # XXX only write charset when not in OT/TTX context, where we
  1420. # dump charset as a separate "GlyphOrder" table.
  1421. # # xmlWriter.simpletag("charset")
  1422. xmlWriter.comment("charset is dumped separately as the 'GlyphOrder' element")
  1423. xmlWriter.newline()
  1424. def xmlRead(self, name, attrs, content, parent):
  1425. pass
  1426. class CharsetCompiler(object):
  1427. def __init__(self, strings, charset, parent):
  1428. assert charset[0] == ".notdef"
  1429. isCID = hasattr(parent.dictObj, "ROS")
  1430. data0 = packCharset0(charset, isCID, strings)
  1431. data = packCharset(charset, isCID, strings)
  1432. if len(data) < len(data0):
  1433. self.data = data
  1434. else:
  1435. self.data = data0
  1436. self.parent = parent
  1437. def setPos(self, pos, endPos):
  1438. self.parent.rawDict["charset"] = pos
  1439. def getDataLength(self):
  1440. return len(self.data)
  1441. def toFile(self, file):
  1442. file.write(self.data)
  1443. def getStdCharSet(charset):
  1444. # check to see if we can use a predefined charset value.
  1445. predefinedCharSetVal = None
  1446. predefinedCharSets = [
  1447. (cffISOAdobeStringCount, cffISOAdobeStrings, 0),
  1448. (cffExpertStringCount, cffIExpertStrings, 1),
  1449. (cffExpertSubsetStringCount, cffExpertSubsetStrings, 2),
  1450. ]
  1451. lcs = len(charset)
  1452. for cnt, pcs, csv in predefinedCharSets:
  1453. if predefinedCharSetVal is not None:
  1454. break
  1455. if lcs > cnt:
  1456. continue
  1457. predefinedCharSetVal = csv
  1458. for i in range(lcs):
  1459. if charset[i] != pcs[i]:
  1460. predefinedCharSetVal = None
  1461. break
  1462. return predefinedCharSetVal
  1463. def getCIDfromName(name, strings):
  1464. return int(name[3:])
  1465. def getSIDfromName(name, strings):
  1466. return strings.getSID(name)
  1467. def packCharset0(charset, isCID, strings):
  1468. fmt = 0
  1469. data = [packCard8(fmt)]
  1470. if isCID:
  1471. getNameID = getCIDfromName
  1472. else:
  1473. getNameID = getSIDfromName
  1474. for name in charset[1:]:
  1475. data.append(packCard16(getNameID(name, strings)))
  1476. return bytesjoin(data)
  1477. def packCharset(charset, isCID, strings):
  1478. fmt = 1
  1479. ranges = []
  1480. first = None
  1481. end = 0
  1482. if isCID:
  1483. getNameID = getCIDfromName
  1484. else:
  1485. getNameID = getSIDfromName
  1486. for name in charset[1:]:
  1487. SID = getNameID(name, strings)
  1488. if first is None:
  1489. first = SID
  1490. elif end + 1 != SID:
  1491. nLeft = end - first
  1492. if nLeft > 255:
  1493. fmt = 2
  1494. ranges.append((first, nLeft))
  1495. first = SID
  1496. end = SID
  1497. if end:
  1498. nLeft = end - first
  1499. if nLeft > 255:
  1500. fmt = 2
  1501. ranges.append((first, nLeft))
  1502. data = [packCard8(fmt)]
  1503. if fmt == 1:
  1504. nLeftFunc = packCard8
  1505. else:
  1506. nLeftFunc = packCard16
  1507. for first, nLeft in ranges:
  1508. data.append(packCard16(first) + nLeftFunc(nLeft))
  1509. return bytesjoin(data)
  1510. def parseCharset0(numGlyphs, file, strings, isCID):
  1511. charset = [".notdef"]
  1512. if isCID:
  1513. for i in range(numGlyphs - 1):
  1514. CID = readCard16(file)
  1515. charset.append("cid" + str(CID).zfill(5))
  1516. else:
  1517. for i in range(numGlyphs - 1):
  1518. SID = readCard16(file)
  1519. charset.append(strings[SID])
  1520. return charset
  1521. def parseCharset(numGlyphs, file, strings, isCID, fmt):
  1522. charset = [".notdef"]
  1523. count = 1
  1524. if fmt == 1:
  1525. nLeftFunc = readCard8
  1526. else:
  1527. nLeftFunc = readCard16
  1528. while count < numGlyphs:
  1529. first = readCard16(file)
  1530. nLeft = nLeftFunc(file)
  1531. if isCID:
  1532. for CID in range(first, first + nLeft + 1):
  1533. charset.append("cid" + str(CID).zfill(5))
  1534. else:
  1535. for SID in range(first, first + nLeft + 1):
  1536. charset.append(strings[SID])
  1537. count = count + nLeft + 1
  1538. return charset
  1539. class EncodingCompiler(object):
  1540. def __init__(self, strings, encoding, parent):
  1541. assert not isinstance(encoding, str)
  1542. data0 = packEncoding0(parent.dictObj.charset, encoding, parent.strings)
  1543. data1 = packEncoding1(parent.dictObj.charset, encoding, parent.strings)
  1544. if len(data0) < len(data1):
  1545. self.data = data0
  1546. else:
  1547. self.data = data1
  1548. self.parent = parent
  1549. def setPos(self, pos, endPos):
  1550. self.parent.rawDict["Encoding"] = pos
  1551. def getDataLength(self):
  1552. return len(self.data)
  1553. def toFile(self, file):
  1554. file.write(self.data)
  1555. class EncodingConverter(SimpleConverter):
  1556. def _read(self, parent, value):
  1557. if value == 0:
  1558. return "StandardEncoding"
  1559. elif value == 1:
  1560. return "ExpertEncoding"
  1561. else:
  1562. assert value > 1
  1563. file = parent.file
  1564. file.seek(value)
  1565. log.log(DEBUG, "loading Encoding at %s", value)
  1566. fmt = readCard8(file)
  1567. haveSupplement = fmt & 0x80
  1568. if haveSupplement:
  1569. raise NotImplementedError("Encoding supplements are not yet supported")
  1570. fmt = fmt & 0x7F
  1571. if fmt == 0:
  1572. encoding = parseEncoding0(
  1573. parent.charset, file, haveSupplement, parent.strings
  1574. )
  1575. elif fmt == 1:
  1576. encoding = parseEncoding1(
  1577. parent.charset, file, haveSupplement, parent.strings
  1578. )
  1579. return encoding
  1580. def write(self, parent, value):
  1581. if value == "StandardEncoding":
  1582. return 0
  1583. elif value == "ExpertEncoding":
  1584. return 1
  1585. return 0 # dummy value
  1586. def xmlWrite(self, xmlWriter, name, value):
  1587. if value in ("StandardEncoding", "ExpertEncoding"):
  1588. xmlWriter.simpletag(name, name=value)
  1589. xmlWriter.newline()
  1590. return
  1591. xmlWriter.begintag(name)
  1592. xmlWriter.newline()
  1593. for code in range(len(value)):
  1594. glyphName = value[code]
  1595. if glyphName != ".notdef":
  1596. xmlWriter.simpletag("map", code=hex(code), name=glyphName)
  1597. xmlWriter.newline()
  1598. xmlWriter.endtag(name)
  1599. xmlWriter.newline()
  1600. def xmlRead(self, name, attrs, content, parent):
  1601. if "name" in attrs:
  1602. return attrs["name"]
  1603. encoding = [".notdef"] * 256
  1604. for element in content:
  1605. if isinstance(element, str):
  1606. continue
  1607. name, attrs, content = element
  1608. code = safeEval(attrs["code"])
  1609. glyphName = attrs["name"]
  1610. encoding[code] = glyphName
  1611. return encoding
  1612. def parseEncoding0(charset, file, haveSupplement, strings):
  1613. nCodes = readCard8(file)
  1614. encoding = [".notdef"] * 256
  1615. for glyphID in range(1, nCodes + 1):
  1616. code = readCard8(file)
  1617. if code != 0:
  1618. encoding[code] = charset[glyphID]
  1619. return encoding
  1620. def parseEncoding1(charset, file, haveSupplement, strings):
  1621. nRanges = readCard8(file)
  1622. encoding = [".notdef"] * 256
  1623. glyphID = 1
  1624. for i in range(nRanges):
  1625. code = readCard8(file)
  1626. nLeft = readCard8(file)
  1627. for glyphID in range(glyphID, glyphID + nLeft + 1):
  1628. encoding[code] = charset[glyphID]
  1629. code = code + 1
  1630. glyphID = glyphID + 1
  1631. return encoding
  1632. def packEncoding0(charset, encoding, strings):
  1633. fmt = 0
  1634. m = {}
  1635. for code in range(len(encoding)):
  1636. name = encoding[code]
  1637. if name != ".notdef":
  1638. m[name] = code
  1639. codes = []
  1640. for name in charset[1:]:
  1641. code = m.get(name)
  1642. codes.append(code)
  1643. while codes and codes[-1] is None:
  1644. codes.pop()
  1645. data = [packCard8(fmt), packCard8(len(codes))]
  1646. for code in codes:
  1647. if code is None:
  1648. code = 0
  1649. data.append(packCard8(code))
  1650. return bytesjoin(data)
  1651. def packEncoding1(charset, encoding, strings):
  1652. fmt = 1
  1653. m = {}
  1654. for code in range(len(encoding)):
  1655. name = encoding[code]
  1656. if name != ".notdef":
  1657. m[name] = code
  1658. ranges = []
  1659. first = None
  1660. end = 0
  1661. for name in charset[1:]:
  1662. code = m.get(name, -1)
  1663. if first is None:
  1664. first = code
  1665. elif end + 1 != code:
  1666. nLeft = end - first
  1667. ranges.append((first, nLeft))
  1668. first = code
  1669. end = code
  1670. nLeft = end - first
  1671. ranges.append((first, nLeft))
  1672. # remove unencoded glyphs at the end.
  1673. while ranges and ranges[-1][0] == -1:
  1674. ranges.pop()
  1675. data = [packCard8(fmt), packCard8(len(ranges))]
  1676. for first, nLeft in ranges:
  1677. if first == -1: # unencoded
  1678. first = 0
  1679. data.append(packCard8(first) + packCard8(nLeft))
  1680. return bytesjoin(data)
  1681. class FDArrayConverter(TableConverter):
  1682. def _read(self, parent, value):
  1683. try:
  1684. vstore = parent.VarStore
  1685. except AttributeError:
  1686. vstore = None
  1687. file = parent.file
  1688. isCFF2 = parent._isCFF2
  1689. file.seek(value)
  1690. fdArray = FDArrayIndex(file, isCFF2=isCFF2)
  1691. fdArray.vstore = vstore
  1692. fdArray.strings = parent.strings
  1693. fdArray.GlobalSubrs = parent.GlobalSubrs
  1694. return fdArray
  1695. def write(self, parent, value):
  1696. return 0 # dummy value
  1697. def xmlRead(self, name, attrs, content, parent):
  1698. fdArray = FDArrayIndex()
  1699. for element in content:
  1700. if isinstance(element, str):
  1701. continue
  1702. name, attrs, content = element
  1703. fdArray.fromXML(name, attrs, content)
  1704. return fdArray
  1705. class FDSelectConverter(SimpleConverter):
  1706. def _read(self, parent, value):
  1707. file = parent.file
  1708. file.seek(value)
  1709. fdSelect = FDSelect(file, parent.numGlyphs)
  1710. return fdSelect
  1711. def write(self, parent, value):
  1712. return 0 # dummy value
  1713. # The FDSelect glyph data is written out to XML in the charstring keys,
  1714. # so we write out only the format selector
  1715. def xmlWrite(self, xmlWriter, name, value):
  1716. xmlWriter.simpletag(name, [("format", value.format)])
  1717. xmlWriter.newline()
  1718. def xmlRead(self, name, attrs, content, parent):
  1719. fmt = safeEval(attrs["format"])
  1720. file = None
  1721. numGlyphs = None
  1722. fdSelect = FDSelect(file, numGlyphs, fmt)
  1723. return fdSelect
  1724. class VarStoreConverter(SimpleConverter):
  1725. def _read(self, parent, value):
  1726. file = parent.file
  1727. file.seek(value)
  1728. varStore = VarStoreData(file)
  1729. varStore.decompile()
  1730. return varStore
  1731. def write(self, parent, value):
  1732. return 0 # dummy value
  1733. def xmlWrite(self, xmlWriter, name, value):
  1734. value.writeXML(xmlWriter, name)
  1735. def xmlRead(self, name, attrs, content, parent):
  1736. varStore = VarStoreData()
  1737. varStore.xmlRead(name, attrs, content, parent)
  1738. return varStore
  1739. def packFDSelect0(fdSelectArray):
  1740. fmt = 0
  1741. data = [packCard8(fmt)]
  1742. for index in fdSelectArray:
  1743. data.append(packCard8(index))
  1744. return bytesjoin(data)
  1745. def packFDSelect3(fdSelectArray):
  1746. fmt = 3
  1747. fdRanges = []
  1748. lenArray = len(fdSelectArray)
  1749. lastFDIndex = -1
  1750. for i in range(lenArray):
  1751. fdIndex = fdSelectArray[i]
  1752. if lastFDIndex != fdIndex:
  1753. fdRanges.append([i, fdIndex])
  1754. lastFDIndex = fdIndex
  1755. sentinelGID = i + 1
  1756. data = [packCard8(fmt)]
  1757. data.append(packCard16(len(fdRanges)))
  1758. for fdRange in fdRanges:
  1759. data.append(packCard16(fdRange[0]))
  1760. data.append(packCard8(fdRange[1]))
  1761. data.append(packCard16(sentinelGID))
  1762. return bytesjoin(data)
  1763. def packFDSelect4(fdSelectArray):
  1764. fmt = 4
  1765. fdRanges = []
  1766. lenArray = len(fdSelectArray)
  1767. lastFDIndex = -1
  1768. for i in range(lenArray):
  1769. fdIndex = fdSelectArray[i]
  1770. if lastFDIndex != fdIndex:
  1771. fdRanges.append([i, fdIndex])
  1772. lastFDIndex = fdIndex
  1773. sentinelGID = i + 1
  1774. data = [packCard8(fmt)]
  1775. data.append(packCard32(len(fdRanges)))
  1776. for fdRange in fdRanges:
  1777. data.append(packCard32(fdRange[0]))
  1778. data.append(packCard16(fdRange[1]))
  1779. data.append(packCard32(sentinelGID))
  1780. return bytesjoin(data)
  1781. class FDSelectCompiler(object):
  1782. def __init__(self, fdSelect, parent):
  1783. fmt = fdSelect.format
  1784. fdSelectArray = fdSelect.gidArray
  1785. if fmt == 0:
  1786. self.data = packFDSelect0(fdSelectArray)
  1787. elif fmt == 3:
  1788. self.data = packFDSelect3(fdSelectArray)
  1789. elif fmt == 4:
  1790. self.data = packFDSelect4(fdSelectArray)
  1791. else:
  1792. # choose smaller of the two formats
  1793. data0 = packFDSelect0(fdSelectArray)
  1794. data3 = packFDSelect3(fdSelectArray)
  1795. if len(data0) < len(data3):
  1796. self.data = data0
  1797. fdSelect.format = 0
  1798. else:
  1799. self.data = data3
  1800. fdSelect.format = 3
  1801. self.parent = parent
  1802. def setPos(self, pos, endPos):
  1803. self.parent.rawDict["FDSelect"] = pos
  1804. def getDataLength(self):
  1805. return len(self.data)
  1806. def toFile(self, file):
  1807. file.write(self.data)
  1808. class VarStoreCompiler(object):
  1809. def __init__(self, varStoreData, parent):
  1810. self.parent = parent
  1811. if not varStoreData.data:
  1812. varStoreData.compile()
  1813. data = [packCard16(len(varStoreData.data)), varStoreData.data]
  1814. self.data = bytesjoin(data)
  1815. def setPos(self, pos, endPos):
  1816. self.parent.rawDict["VarStore"] = pos
  1817. def getDataLength(self):
  1818. return len(self.data)
  1819. def toFile(self, file):
  1820. file.write(self.data)
  1821. class ROSConverter(SimpleConverter):
  1822. def xmlWrite(self, xmlWriter, name, value):
  1823. registry, order, supplement = value
  1824. xmlWriter.simpletag(
  1825. name,
  1826. [
  1827. ("Registry", tostr(registry)),
  1828. ("Order", tostr(order)),
  1829. ("Supplement", supplement),
  1830. ],
  1831. )
  1832. xmlWriter.newline()
  1833. def xmlRead(self, name, attrs, content, parent):
  1834. return (attrs["Registry"], attrs["Order"], safeEval(attrs["Supplement"]))
  1835. topDictOperators = [
  1836. # opcode name argument type default converter
  1837. (25, "maxstack", "number", None, None),
  1838. ((12, 30), "ROS", ("SID", "SID", "number"), None, ROSConverter()),
  1839. ((12, 20), "SyntheticBase", "number", None, None),
  1840. (0, "version", "SID", None, None),
  1841. (1, "Notice", "SID", None, Latin1Converter()),
  1842. ((12, 0), "Copyright", "SID", None, Latin1Converter()),
  1843. (2, "FullName", "SID", None, Latin1Converter()),
  1844. ((12, 38), "FontName", "SID", None, Latin1Converter()),
  1845. (3, "FamilyName", "SID", None, Latin1Converter()),
  1846. (4, "Weight", "SID", None, None),
  1847. ((12, 1), "isFixedPitch", "number", 0, None),
  1848. ((12, 2), "ItalicAngle", "number", 0, None),
  1849. ((12, 3), "UnderlinePosition", "number", -100, None),
  1850. ((12, 4), "UnderlineThickness", "number", 50, None),
  1851. ((12, 5), "PaintType", "number", 0, None),
  1852. ((12, 6), "CharstringType", "number", 2, None),
  1853. ((12, 7), "FontMatrix", "array", [0.001, 0, 0, 0.001, 0, 0], None),
  1854. (13, "UniqueID", "number", None, None),
  1855. (5, "FontBBox", "array", [0, 0, 0, 0], None),
  1856. ((12, 8), "StrokeWidth", "number", 0, None),
  1857. (14, "XUID", "array", None, None),
  1858. ((12, 21), "PostScript", "SID", None, None),
  1859. ((12, 22), "BaseFontName", "SID", None, None),
  1860. ((12, 23), "BaseFontBlend", "delta", None, None),
  1861. ((12, 31), "CIDFontVersion", "number", 0, None),
  1862. ((12, 32), "CIDFontRevision", "number", 0, None),
  1863. ((12, 33), "CIDFontType", "number", 0, None),
  1864. ((12, 34), "CIDCount", "number", 8720, None),
  1865. (15, "charset", "number", None, CharsetConverter()),
  1866. ((12, 35), "UIDBase", "number", None, None),
  1867. (16, "Encoding", "number", 0, EncodingConverter()),
  1868. (18, "Private", ("number", "number"), None, PrivateDictConverter()),
  1869. ((12, 37), "FDSelect", "number", None, FDSelectConverter()),
  1870. ((12, 36), "FDArray", "number", None, FDArrayConverter()),
  1871. (17, "CharStrings", "number", None, CharStringsConverter()),
  1872. (24, "VarStore", "number", None, VarStoreConverter()),
  1873. ]
  1874. topDictOperators2 = [
  1875. # opcode name argument type default converter
  1876. (25, "maxstack", "number", None, None),
  1877. ((12, 7), "FontMatrix", "array", [0.001, 0, 0, 0.001, 0, 0], None),
  1878. ((12, 37), "FDSelect", "number", None, FDSelectConverter()),
  1879. ((12, 36), "FDArray", "number", None, FDArrayConverter()),
  1880. (17, "CharStrings", "number", None, CharStringsConverter()),
  1881. (24, "VarStore", "number", None, VarStoreConverter()),
  1882. ]
  1883. # Note! FDSelect and FDArray must both preceed CharStrings in the output XML build order,
  1884. # in order for the font to compile back from xml.
  1885. kBlendDictOpName = "blend"
  1886. blendOp = 23
  1887. privateDictOperators = [
  1888. # opcode name argument type default converter
  1889. (22, "vsindex", "number", None, None),
  1890. (
  1891. blendOp,
  1892. kBlendDictOpName,
  1893. "blendList",
  1894. None,
  1895. None,
  1896. ), # This is for reading to/from XML: it not written to CFF.
  1897. (6, "BlueValues", "delta", None, None),
  1898. (7, "OtherBlues", "delta", None, None),
  1899. (8, "FamilyBlues", "delta", None, None),
  1900. (9, "FamilyOtherBlues", "delta", None, None),
  1901. ((12, 9), "BlueScale", "number", 0.039625, None),
  1902. ((12, 10), "BlueShift", "number", 7, None),
  1903. ((12, 11), "BlueFuzz", "number", 1, None),
  1904. (10, "StdHW", "number", None, None),
  1905. (11, "StdVW", "number", None, None),
  1906. ((12, 12), "StemSnapH", "delta", None, None),
  1907. ((12, 13), "StemSnapV", "delta", None, None),
  1908. ((12, 14), "ForceBold", "number", 0, None),
  1909. ((12, 15), "ForceBoldThreshold", "number", None, None), # deprecated
  1910. ((12, 16), "lenIV", "number", None, None), # deprecated
  1911. ((12, 17), "LanguageGroup", "number", 0, None),
  1912. ((12, 18), "ExpansionFactor", "number", 0.06, None),
  1913. ((12, 19), "initialRandomSeed", "number", 0, None),
  1914. (20, "defaultWidthX", "number", 0, None),
  1915. (21, "nominalWidthX", "number", 0, None),
  1916. (19, "Subrs", "number", None, SubrsConverter()),
  1917. ]
  1918. privateDictOperators2 = [
  1919. # opcode name argument type default converter
  1920. (22, "vsindex", "number", None, None),
  1921. (
  1922. blendOp,
  1923. kBlendDictOpName,
  1924. "blendList",
  1925. None,
  1926. None,
  1927. ), # This is for reading to/from XML: it not written to CFF.
  1928. (6, "BlueValues", "delta", None, None),
  1929. (7, "OtherBlues", "delta", None, None),
  1930. (8, "FamilyBlues", "delta", None, None),
  1931. (9, "FamilyOtherBlues", "delta", None, None),
  1932. ((12, 9), "BlueScale", "number", 0.039625, None),
  1933. ((12, 10), "BlueShift", "number", 7, None),
  1934. ((12, 11), "BlueFuzz", "number", 1, None),
  1935. (10, "StdHW", "number", None, None),
  1936. (11, "StdVW", "number", None, None),
  1937. ((12, 12), "StemSnapH", "delta", None, None),
  1938. ((12, 13), "StemSnapV", "delta", None, None),
  1939. ((12, 17), "LanguageGroup", "number", 0, None),
  1940. ((12, 18), "ExpansionFactor", "number", 0.06, None),
  1941. (19, "Subrs", "number", None, SubrsConverter()),
  1942. ]
  1943. def addConverters(table):
  1944. for i in range(len(table)):
  1945. op, name, arg, default, conv = table[i]
  1946. if conv is not None:
  1947. continue
  1948. if arg in ("delta", "array"):
  1949. conv = ArrayConverter()
  1950. elif arg == "number":
  1951. conv = NumberConverter()
  1952. elif arg == "SID":
  1953. conv = ASCIIConverter()
  1954. elif arg == "blendList":
  1955. conv = None
  1956. else:
  1957. assert False
  1958. table[i] = op, name, arg, default, conv
  1959. addConverters(privateDictOperators)
  1960. addConverters(topDictOperators)
  1961. class TopDictDecompiler(psCharStrings.DictDecompiler):
  1962. operators = buildOperatorDict(topDictOperators)
  1963. class PrivateDictDecompiler(psCharStrings.DictDecompiler):
  1964. operators = buildOperatorDict(privateDictOperators)
  1965. class DictCompiler(object):
  1966. maxBlendStack = 0
  1967. def __init__(self, dictObj, strings, parent, isCFF2=None):
  1968. if strings:
  1969. assert isinstance(strings, IndexedStrings)
  1970. if isCFF2 is None and hasattr(parent, "isCFF2"):
  1971. isCFF2 = parent.isCFF2
  1972. assert isCFF2 is not None
  1973. self.isCFF2 = isCFF2
  1974. self.dictObj = dictObj
  1975. self.strings = strings
  1976. self.parent = parent
  1977. rawDict = {}
  1978. for name in dictObj.order:
  1979. value = getattr(dictObj, name, None)
  1980. if value is None:
  1981. continue
  1982. conv = dictObj.converters[name]
  1983. value = conv.write(dictObj, value)
  1984. if value == dictObj.defaults.get(name):
  1985. continue
  1986. rawDict[name] = value
  1987. self.rawDict = rawDict
  1988. def setPos(self, pos, endPos):
  1989. pass
  1990. def getDataLength(self):
  1991. return len(self.compile("getDataLength"))
  1992. def compile(self, reason):
  1993. log.log(DEBUG, "-- compiling %s for %s", self.__class__.__name__, reason)
  1994. rawDict = self.rawDict
  1995. data = []
  1996. for name in self.dictObj.order:
  1997. value = rawDict.get(name)
  1998. if value is None:
  1999. continue
  2000. op, argType = self.opcodes[name]
  2001. if isinstance(argType, tuple):
  2002. l = len(argType)
  2003. assert len(value) == l, "value doesn't match arg type"
  2004. for i in range(l):
  2005. arg = argType[i]
  2006. v = value[i]
  2007. arghandler = getattr(self, "arg_" + arg)
  2008. data.append(arghandler(v))
  2009. else:
  2010. arghandler = getattr(self, "arg_" + argType)
  2011. data.append(arghandler(value))
  2012. data.append(op)
  2013. data = bytesjoin(data)
  2014. return data
  2015. def toFile(self, file):
  2016. data = self.compile("toFile")
  2017. file.write(data)
  2018. def arg_number(self, num):
  2019. if isinstance(num, list):
  2020. data = [encodeNumber(val) for val in num]
  2021. data.append(encodeNumber(1))
  2022. data.append(bytechr(blendOp))
  2023. datum = bytesjoin(data)
  2024. else:
  2025. datum = encodeNumber(num)
  2026. return datum
  2027. def arg_SID(self, s):
  2028. return psCharStrings.encodeIntCFF(self.strings.getSID(s))
  2029. def arg_array(self, value):
  2030. data = []
  2031. for num in value:
  2032. data.append(self.arg_number(num))
  2033. return bytesjoin(data)
  2034. def arg_delta(self, value):
  2035. if not value:
  2036. return b""
  2037. val0 = value[0]
  2038. if isinstance(val0, list):
  2039. data = self.arg_delta_blend(value)
  2040. else:
  2041. out = []
  2042. last = 0
  2043. for v in value:
  2044. out.append(v - last)
  2045. last = v
  2046. data = []
  2047. for num in out:
  2048. data.append(encodeNumber(num))
  2049. return bytesjoin(data)
  2050. def arg_delta_blend(self, value):
  2051. """A delta list with blend lists has to be *all* blend lists.
  2052. The value is a list is arranged as follows::
  2053. [
  2054. [V0, d0..dn]
  2055. [V1, d0..dn]
  2056. ...
  2057. [Vm, d0..dn]
  2058. ]
  2059. ``V`` is the absolute coordinate value from the default font, and ``d0-dn``
  2060. are the delta values from the *n* regions. Each ``V`` is an absolute
  2061. coordinate from the default font.
  2062. We want to return a list::
  2063. [
  2064. [v0, v1..vm]
  2065. [d0..dn]
  2066. ...
  2067. [d0..dn]
  2068. numBlends
  2069. blendOp
  2070. ]
  2071. where each ``v`` is relative to the previous default font value.
  2072. """
  2073. numMasters = len(value[0])
  2074. numBlends = len(value)
  2075. numStack = (numBlends * numMasters) + 1
  2076. if numStack > self.maxBlendStack:
  2077. # Figure out the max number of value we can blend
  2078. # and divide this list up into chunks of that size.
  2079. numBlendValues = int((self.maxBlendStack - 1) / numMasters)
  2080. out = []
  2081. while True:
  2082. numVal = min(len(value), numBlendValues)
  2083. if numVal == 0:
  2084. break
  2085. valList = value[0:numVal]
  2086. out1 = self.arg_delta_blend(valList)
  2087. out.extend(out1)
  2088. value = value[numVal:]
  2089. else:
  2090. firstList = [0] * numBlends
  2091. deltaList = [None] * numBlends
  2092. i = 0
  2093. prevVal = 0
  2094. while i < numBlends:
  2095. # For PrivateDict BlueValues, the default font
  2096. # values are absolute, not relative.
  2097. # Must convert these back to relative coordinates
  2098. # befor writing to CFF2.
  2099. defaultValue = value[i][0]
  2100. firstList[i] = defaultValue - prevVal
  2101. prevVal = defaultValue
  2102. deltaList[i] = value[i][1:]
  2103. i += 1
  2104. relValueList = firstList
  2105. for blendList in deltaList:
  2106. relValueList.extend(blendList)
  2107. out = [encodeNumber(val) for val in relValueList]
  2108. out.append(encodeNumber(numBlends))
  2109. out.append(bytechr(blendOp))
  2110. return out
  2111. def encodeNumber(num):
  2112. if isinstance(num, float):
  2113. return psCharStrings.encodeFloat(num)
  2114. else:
  2115. return psCharStrings.encodeIntCFF(num)
  2116. class TopDictCompiler(DictCompiler):
  2117. opcodes = buildOpcodeDict(topDictOperators)
  2118. def getChildren(self, strings):
  2119. isCFF2 = self.isCFF2
  2120. children = []
  2121. if self.dictObj.cff2GetGlyphOrder is None:
  2122. if hasattr(self.dictObj, "charset") and self.dictObj.charset:
  2123. if hasattr(self.dictObj, "ROS"): # aka isCID
  2124. charsetCode = None
  2125. else:
  2126. charsetCode = getStdCharSet(self.dictObj.charset)
  2127. if charsetCode is None:
  2128. children.append(
  2129. CharsetCompiler(strings, self.dictObj.charset, self)
  2130. )
  2131. else:
  2132. self.rawDict["charset"] = charsetCode
  2133. if hasattr(self.dictObj, "Encoding") and self.dictObj.Encoding:
  2134. encoding = self.dictObj.Encoding
  2135. if not isinstance(encoding, str):
  2136. children.append(EncodingCompiler(strings, encoding, self))
  2137. else:
  2138. if hasattr(self.dictObj, "VarStore"):
  2139. varStoreData = self.dictObj.VarStore
  2140. varStoreComp = VarStoreCompiler(varStoreData, self)
  2141. children.append(varStoreComp)
  2142. if hasattr(self.dictObj, "FDSelect"):
  2143. # I have not yet supported merging a ttx CFF-CID font, as there are
  2144. # interesting issues about merging the FDArrays. Here I assume that
  2145. # either the font was read from XML, and the FDSelect indices are all
  2146. # in the charstring data, or the FDSelect array is already fully defined.
  2147. fdSelect = self.dictObj.FDSelect
  2148. # probably read in from XML; assume fdIndex in CharString data
  2149. if len(fdSelect) == 0:
  2150. charStrings = self.dictObj.CharStrings
  2151. for name in self.dictObj.charset:
  2152. fdSelect.append(charStrings[name].fdSelectIndex)
  2153. fdSelectComp = FDSelectCompiler(fdSelect, self)
  2154. children.append(fdSelectComp)
  2155. if hasattr(self.dictObj, "CharStrings"):
  2156. items = []
  2157. charStrings = self.dictObj.CharStrings
  2158. for name in self.dictObj.charset:
  2159. items.append(charStrings[name])
  2160. charStringsComp = CharStringsCompiler(items, strings, self, isCFF2=isCFF2)
  2161. children.append(charStringsComp)
  2162. if hasattr(self.dictObj, "FDArray"):
  2163. # I have not yet supported merging a ttx CFF-CID font, as there are
  2164. # interesting issues about merging the FDArrays. Here I assume that the
  2165. # FDArray info is correct and complete.
  2166. fdArrayIndexComp = self.dictObj.FDArray.getCompiler(strings, self)
  2167. children.append(fdArrayIndexComp)
  2168. children.extend(fdArrayIndexComp.getChildren(strings))
  2169. if hasattr(self.dictObj, "Private"):
  2170. privComp = self.dictObj.Private.getCompiler(strings, self)
  2171. children.append(privComp)
  2172. children.extend(privComp.getChildren(strings))
  2173. return children
  2174. class FontDictCompiler(DictCompiler):
  2175. opcodes = buildOpcodeDict(topDictOperators)
  2176. def __init__(self, dictObj, strings, parent, isCFF2=None):
  2177. super(FontDictCompiler, self).__init__(dictObj, strings, parent, isCFF2=isCFF2)
  2178. #
  2179. # We now take some effort to detect if there were any key/value pairs
  2180. # supplied that were ignored in the FontDict context, and issue a warning
  2181. # for those cases.
  2182. #
  2183. ignoredNames = []
  2184. dictObj = self.dictObj
  2185. for name in sorted(set(dictObj.converters) - set(dictObj.order)):
  2186. if name in dictObj.rawDict:
  2187. # The font was directly read from binary. In this
  2188. # case, we want to report *all* "useless" key/value
  2189. # pairs that are in the font, not just the ones that
  2190. # are different from the default.
  2191. ignoredNames.append(name)
  2192. else:
  2193. # The font was probably read from a TTX file. We only
  2194. # warn about keys whos value is not the default. The
  2195. # ones that have the default value will not be written
  2196. # to binary anyway.
  2197. default = dictObj.defaults.get(name)
  2198. if default is not None:
  2199. conv = dictObj.converters[name]
  2200. default = conv.read(dictObj, default)
  2201. if getattr(dictObj, name, None) != default:
  2202. ignoredNames.append(name)
  2203. if ignoredNames:
  2204. log.warning(
  2205. "Some CFF FDArray/FontDict keys were ignored upon compile: "
  2206. + " ".join(sorted(ignoredNames))
  2207. )
  2208. def getChildren(self, strings):
  2209. children = []
  2210. if hasattr(self.dictObj, "Private"):
  2211. privComp = self.dictObj.Private.getCompiler(strings, self)
  2212. children.append(privComp)
  2213. children.extend(privComp.getChildren(strings))
  2214. return children
  2215. class PrivateDictCompiler(DictCompiler):
  2216. maxBlendStack = maxStackLimit
  2217. opcodes = buildOpcodeDict(privateDictOperators)
  2218. def setPos(self, pos, endPos):
  2219. size = endPos - pos
  2220. self.parent.rawDict["Private"] = size, pos
  2221. self.pos = pos
  2222. def getChildren(self, strings):
  2223. children = []
  2224. if hasattr(self.dictObj, "Subrs"):
  2225. children.append(self.dictObj.Subrs.getCompiler(strings, self))
  2226. return children
  2227. class BaseDict(object):
  2228. def __init__(self, strings=None, file=None, offset=None, isCFF2=None):
  2229. assert (isCFF2 is None) == (file is None)
  2230. self.rawDict = {}
  2231. self.skipNames = []
  2232. self.strings = strings
  2233. if file is None:
  2234. return
  2235. self._isCFF2 = isCFF2
  2236. self.file = file
  2237. if offset is not None:
  2238. log.log(DEBUG, "loading %s at %s", self.__class__.__name__, offset)
  2239. self.offset = offset
  2240. def decompile(self, data):
  2241. log.log(DEBUG, " length %s is %d", self.__class__.__name__, len(data))
  2242. dec = self.decompilerClass(self.strings, self)
  2243. dec.decompile(data)
  2244. self.rawDict = dec.getDict()
  2245. self.postDecompile()
  2246. def postDecompile(self):
  2247. pass
  2248. def getCompiler(self, strings, parent, isCFF2=None):
  2249. return self.compilerClass(self, strings, parent, isCFF2=isCFF2)
  2250. def __getattr__(self, name):
  2251. if name[:2] == name[-2:] == "__":
  2252. # to make deepcopy() and pickle.load() work, we need to signal with
  2253. # AttributeError that dunder methods like '__deepcopy__' or '__getstate__'
  2254. # aren't implemented. For more details, see:
  2255. # https://github.com/fonttools/fonttools/pull/1488
  2256. raise AttributeError(name)
  2257. value = self.rawDict.get(name, None)
  2258. if value is None:
  2259. value = self.defaults.get(name)
  2260. if value is None:
  2261. raise AttributeError(name)
  2262. conv = self.converters[name]
  2263. value = conv.read(self, value)
  2264. setattr(self, name, value)
  2265. return value
  2266. def toXML(self, xmlWriter):
  2267. for name in self.order:
  2268. if name in self.skipNames:
  2269. continue
  2270. value = getattr(self, name, None)
  2271. # XXX For "charset" we never skip calling xmlWrite even if the
  2272. # value is None, so we always write the following XML comment:
  2273. #
  2274. # <!-- charset is dumped separately as the 'GlyphOrder' element -->
  2275. #
  2276. # Charset is None when 'CFF ' table is imported from XML into an
  2277. # empty TTFont(). By writing this comment all the time, we obtain
  2278. # the same XML output whether roundtripping XML-to-XML or
  2279. # dumping binary-to-XML
  2280. if value is None and name != "charset":
  2281. continue
  2282. conv = self.converters[name]
  2283. conv.xmlWrite(xmlWriter, name, value)
  2284. ignoredNames = set(self.rawDict) - set(self.order)
  2285. if ignoredNames:
  2286. xmlWriter.comment(
  2287. "some keys were ignored: %s" % " ".join(sorted(ignoredNames))
  2288. )
  2289. xmlWriter.newline()
  2290. def fromXML(self, name, attrs, content):
  2291. conv = self.converters[name]
  2292. value = conv.xmlRead(name, attrs, content, self)
  2293. setattr(self, name, value)
  2294. class TopDict(BaseDict):
  2295. """The ``TopDict`` represents the top-level dictionary holding font
  2296. information. CFF2 tables contain a restricted set of top-level entries
  2297. as described `here <https://docs.microsoft.com/en-us/typography/opentype/spec/cff2#7-top-dict-data>`_,
  2298. but CFF tables may contain a wider range of information. This information
  2299. can be accessed through attributes or through the dictionary returned
  2300. through the ``rawDict`` property:
  2301. .. code:: python
  2302. font = tt["CFF "].cff[0]
  2303. font.FamilyName
  2304. # 'Linux Libertine O'
  2305. font.rawDict["FamilyName"]
  2306. # 'Linux Libertine O'
  2307. More information is available in the CFF file's private dictionary, accessed
  2308. via the ``Private`` property:
  2309. .. code:: python
  2310. tt["CFF "].cff[0].Private.BlueValues
  2311. # [-15, 0, 515, 515, 666, 666]
  2312. """
  2313. defaults = buildDefaults(topDictOperators)
  2314. converters = buildConverters(topDictOperators)
  2315. compilerClass = TopDictCompiler
  2316. order = buildOrder(topDictOperators)
  2317. decompilerClass = TopDictDecompiler
  2318. def __init__(
  2319. self,
  2320. strings=None,
  2321. file=None,
  2322. offset=None,
  2323. GlobalSubrs=None,
  2324. cff2GetGlyphOrder=None,
  2325. isCFF2=None,
  2326. ):
  2327. super(TopDict, self).__init__(strings, file, offset, isCFF2=isCFF2)
  2328. self.cff2GetGlyphOrder = cff2GetGlyphOrder
  2329. self.GlobalSubrs = GlobalSubrs
  2330. if isCFF2:
  2331. self.defaults = buildDefaults(topDictOperators2)
  2332. self.charset = cff2GetGlyphOrder()
  2333. self.order = buildOrder(topDictOperators2)
  2334. else:
  2335. self.defaults = buildDefaults(topDictOperators)
  2336. self.order = buildOrder(topDictOperators)
  2337. def getGlyphOrder(self):
  2338. """Returns a list of glyph names in the CFF font."""
  2339. return self.charset
  2340. def postDecompile(self):
  2341. offset = self.rawDict.get("CharStrings")
  2342. if offset is None:
  2343. return
  2344. # get the number of glyphs beforehand.
  2345. self.file.seek(offset)
  2346. if self._isCFF2:
  2347. self.numGlyphs = readCard32(self.file)
  2348. else:
  2349. self.numGlyphs = readCard16(self.file)
  2350. def toXML(self, xmlWriter):
  2351. if hasattr(self, "CharStrings"):
  2352. self.decompileAllCharStrings()
  2353. if hasattr(self, "ROS"):
  2354. self.skipNames = ["Encoding"]
  2355. if not hasattr(self, "ROS") or not hasattr(self, "CharStrings"):
  2356. # these values have default values, but I only want them to show up
  2357. # in CID fonts.
  2358. self.skipNames = [
  2359. "CIDFontVersion",
  2360. "CIDFontRevision",
  2361. "CIDFontType",
  2362. "CIDCount",
  2363. ]
  2364. BaseDict.toXML(self, xmlWriter)
  2365. def decompileAllCharStrings(self):
  2366. # Make sure that all the Private Dicts have been instantiated.
  2367. for i, charString in enumerate(self.CharStrings.values()):
  2368. try:
  2369. charString.decompile()
  2370. except:
  2371. log.error("Error in charstring %s", i)
  2372. raise
  2373. def recalcFontBBox(self):
  2374. fontBBox = None
  2375. for charString in self.CharStrings.values():
  2376. bounds = charString.calcBounds(self.CharStrings)
  2377. if bounds is not None:
  2378. if fontBBox is not None:
  2379. fontBBox = unionRect(fontBBox, bounds)
  2380. else:
  2381. fontBBox = bounds
  2382. if fontBBox is None:
  2383. self.FontBBox = self.defaults["FontBBox"][:]
  2384. else:
  2385. self.FontBBox = list(intRect(fontBBox))
  2386. class FontDict(BaseDict):
  2387. #
  2388. # Since fonttools used to pass a lot of fields that are not relevant in the FDArray
  2389. # FontDict, there are 'ttx' files in the wild that contain all these. These got in
  2390. # the ttx files because fonttools writes explicit values for all the TopDict default
  2391. # values. These are not actually illegal in the context of an FDArray FontDict - you
  2392. # can legally, per spec, put any arbitrary key/value pair in a FontDict - but are
  2393. # useless since current major company CFF interpreters ignore anything but the set
  2394. # listed in this file. So, we just silently skip them. An exception is Weight: this
  2395. # is not used by any interpreter, but some foundries have asked that this be
  2396. # supported in FDArray FontDicts just to preserve information about the design when
  2397. # the font is being inspected.
  2398. #
  2399. # On top of that, there are fonts out there that contain such useless FontDict values.
  2400. #
  2401. # By subclassing TopDict, we *allow* all key/values from TopDict, both when reading
  2402. # from binary or when reading from XML, but by overriding `order` with a limited
  2403. # list of names, we ensure that only the useful names ever get exported to XML and
  2404. # ever get compiled into the binary font.
  2405. #
  2406. # We override compilerClass so we can warn about "useless" key/value pairs, either
  2407. # from the original binary font or from TTX input.
  2408. #
  2409. # See:
  2410. # - https://github.com/fonttools/fonttools/issues/740
  2411. # - https://github.com/fonttools/fonttools/issues/601
  2412. # - https://github.com/adobe-type-tools/afdko/issues/137
  2413. #
  2414. defaults = {}
  2415. converters = buildConverters(topDictOperators)
  2416. compilerClass = FontDictCompiler
  2417. orderCFF = ["FontName", "FontMatrix", "Weight", "Private"]
  2418. orderCFF2 = ["Private"]
  2419. decompilerClass = TopDictDecompiler
  2420. def __init__(
  2421. self,
  2422. strings=None,
  2423. file=None,
  2424. offset=None,
  2425. GlobalSubrs=None,
  2426. isCFF2=None,
  2427. vstore=None,
  2428. ):
  2429. super(FontDict, self).__init__(strings, file, offset, isCFF2=isCFF2)
  2430. self.vstore = vstore
  2431. self.setCFF2(isCFF2)
  2432. def setCFF2(self, isCFF2):
  2433. # isCFF2 may be None.
  2434. if isCFF2:
  2435. self.order = self.orderCFF2
  2436. self._isCFF2 = True
  2437. else:
  2438. self.order = self.orderCFF
  2439. self._isCFF2 = False
  2440. class PrivateDict(BaseDict):
  2441. defaults = buildDefaults(privateDictOperators)
  2442. converters = buildConverters(privateDictOperators)
  2443. order = buildOrder(privateDictOperators)
  2444. decompilerClass = PrivateDictDecompiler
  2445. compilerClass = PrivateDictCompiler
  2446. def __init__(self, strings=None, file=None, offset=None, isCFF2=None, vstore=None):
  2447. super(PrivateDict, self).__init__(strings, file, offset, isCFF2=isCFF2)
  2448. self.vstore = vstore
  2449. if isCFF2:
  2450. self.defaults = buildDefaults(privateDictOperators2)
  2451. self.order = buildOrder(privateDictOperators2)
  2452. # Provide dummy values. This avoids needing to provide
  2453. # an isCFF2 state in a lot of places.
  2454. self.nominalWidthX = self.defaultWidthX = None
  2455. else:
  2456. self.defaults = buildDefaults(privateDictOperators)
  2457. self.order = buildOrder(privateDictOperators)
  2458. @property
  2459. def in_cff2(self):
  2460. return self._isCFF2
  2461. def getNumRegions(self, vi=None): # called from misc/psCharStrings.py
  2462. # if getNumRegions is being called, we can assume that VarStore exists.
  2463. if vi is None:
  2464. if hasattr(self, "vsindex"):
  2465. vi = self.vsindex
  2466. else:
  2467. vi = 0
  2468. numRegions = self.vstore.getNumRegions(vi)
  2469. return numRegions
  2470. class IndexedStrings(object):
  2471. """SID -> string mapping."""
  2472. def __init__(self, file=None):
  2473. if file is None:
  2474. strings = []
  2475. else:
  2476. strings = [tostr(s, encoding="latin1") for s in Index(file, isCFF2=False)]
  2477. self.strings = strings
  2478. def getCompiler(self):
  2479. return IndexedStringsCompiler(self, None, self, isCFF2=False)
  2480. def __len__(self):
  2481. return len(self.strings)
  2482. def __getitem__(self, SID):
  2483. if SID < cffStandardStringCount:
  2484. return cffStandardStrings[SID]
  2485. else:
  2486. return self.strings[SID - cffStandardStringCount]
  2487. def getSID(self, s):
  2488. if not hasattr(self, "stringMapping"):
  2489. self.buildStringMapping()
  2490. s = tostr(s, encoding="latin1")
  2491. if s in cffStandardStringMapping:
  2492. SID = cffStandardStringMapping[s]
  2493. elif s in self.stringMapping:
  2494. SID = self.stringMapping[s]
  2495. else:
  2496. SID = len(self.strings) + cffStandardStringCount
  2497. self.strings.append(s)
  2498. self.stringMapping[s] = SID
  2499. return SID
  2500. def getStrings(self):
  2501. return self.strings
  2502. def buildStringMapping(self):
  2503. self.stringMapping = {}
  2504. for index in range(len(self.strings)):
  2505. self.stringMapping[self.strings[index]] = index + cffStandardStringCount
  2506. # The 391 Standard Strings as used in the CFF format.
  2507. # from Adobe Technical None #5176, version 1.0, 18 March 1998
  2508. cffStandardStrings = [
  2509. ".notdef",
  2510. "space",
  2511. "exclam",
  2512. "quotedbl",
  2513. "numbersign",
  2514. "dollar",
  2515. "percent",
  2516. "ampersand",
  2517. "quoteright",
  2518. "parenleft",
  2519. "parenright",
  2520. "asterisk",
  2521. "plus",
  2522. "comma",
  2523. "hyphen",
  2524. "period",
  2525. "slash",
  2526. "zero",
  2527. "one",
  2528. "two",
  2529. "three",
  2530. "four",
  2531. "five",
  2532. "six",
  2533. "seven",
  2534. "eight",
  2535. "nine",
  2536. "colon",
  2537. "semicolon",
  2538. "less",
  2539. "equal",
  2540. "greater",
  2541. "question",
  2542. "at",
  2543. "A",
  2544. "B",
  2545. "C",
  2546. "D",
  2547. "E",
  2548. "F",
  2549. "G",
  2550. "H",
  2551. "I",
  2552. "J",
  2553. "K",
  2554. "L",
  2555. "M",
  2556. "N",
  2557. "O",
  2558. "P",
  2559. "Q",
  2560. "R",
  2561. "S",
  2562. "T",
  2563. "U",
  2564. "V",
  2565. "W",
  2566. "X",
  2567. "Y",
  2568. "Z",
  2569. "bracketleft",
  2570. "backslash",
  2571. "bracketright",
  2572. "asciicircum",
  2573. "underscore",
  2574. "quoteleft",
  2575. "a",
  2576. "b",
  2577. "c",
  2578. "d",
  2579. "e",
  2580. "f",
  2581. "g",
  2582. "h",
  2583. "i",
  2584. "j",
  2585. "k",
  2586. "l",
  2587. "m",
  2588. "n",
  2589. "o",
  2590. "p",
  2591. "q",
  2592. "r",
  2593. "s",
  2594. "t",
  2595. "u",
  2596. "v",
  2597. "w",
  2598. "x",
  2599. "y",
  2600. "z",
  2601. "braceleft",
  2602. "bar",
  2603. "braceright",
  2604. "asciitilde",
  2605. "exclamdown",
  2606. "cent",
  2607. "sterling",
  2608. "fraction",
  2609. "yen",
  2610. "florin",
  2611. "section",
  2612. "currency",
  2613. "quotesingle",
  2614. "quotedblleft",
  2615. "guillemotleft",
  2616. "guilsinglleft",
  2617. "guilsinglright",
  2618. "fi",
  2619. "fl",
  2620. "endash",
  2621. "dagger",
  2622. "daggerdbl",
  2623. "periodcentered",
  2624. "paragraph",
  2625. "bullet",
  2626. "quotesinglbase",
  2627. "quotedblbase",
  2628. "quotedblright",
  2629. "guillemotright",
  2630. "ellipsis",
  2631. "perthousand",
  2632. "questiondown",
  2633. "grave",
  2634. "acute",
  2635. "circumflex",
  2636. "tilde",
  2637. "macron",
  2638. "breve",
  2639. "dotaccent",
  2640. "dieresis",
  2641. "ring",
  2642. "cedilla",
  2643. "hungarumlaut",
  2644. "ogonek",
  2645. "caron",
  2646. "emdash",
  2647. "AE",
  2648. "ordfeminine",
  2649. "Lslash",
  2650. "Oslash",
  2651. "OE",
  2652. "ordmasculine",
  2653. "ae",
  2654. "dotlessi",
  2655. "lslash",
  2656. "oslash",
  2657. "oe",
  2658. "germandbls",
  2659. "onesuperior",
  2660. "logicalnot",
  2661. "mu",
  2662. "trademark",
  2663. "Eth",
  2664. "onehalf",
  2665. "plusminus",
  2666. "Thorn",
  2667. "onequarter",
  2668. "divide",
  2669. "brokenbar",
  2670. "degree",
  2671. "thorn",
  2672. "threequarters",
  2673. "twosuperior",
  2674. "registered",
  2675. "minus",
  2676. "eth",
  2677. "multiply",
  2678. "threesuperior",
  2679. "copyright",
  2680. "Aacute",
  2681. "Acircumflex",
  2682. "Adieresis",
  2683. "Agrave",
  2684. "Aring",
  2685. "Atilde",
  2686. "Ccedilla",
  2687. "Eacute",
  2688. "Ecircumflex",
  2689. "Edieresis",
  2690. "Egrave",
  2691. "Iacute",
  2692. "Icircumflex",
  2693. "Idieresis",
  2694. "Igrave",
  2695. "Ntilde",
  2696. "Oacute",
  2697. "Ocircumflex",
  2698. "Odieresis",
  2699. "Ograve",
  2700. "Otilde",
  2701. "Scaron",
  2702. "Uacute",
  2703. "Ucircumflex",
  2704. "Udieresis",
  2705. "Ugrave",
  2706. "Yacute",
  2707. "Ydieresis",
  2708. "Zcaron",
  2709. "aacute",
  2710. "acircumflex",
  2711. "adieresis",
  2712. "agrave",
  2713. "aring",
  2714. "atilde",
  2715. "ccedilla",
  2716. "eacute",
  2717. "ecircumflex",
  2718. "edieresis",
  2719. "egrave",
  2720. "iacute",
  2721. "icircumflex",
  2722. "idieresis",
  2723. "igrave",
  2724. "ntilde",
  2725. "oacute",
  2726. "ocircumflex",
  2727. "odieresis",
  2728. "ograve",
  2729. "otilde",
  2730. "scaron",
  2731. "uacute",
  2732. "ucircumflex",
  2733. "udieresis",
  2734. "ugrave",
  2735. "yacute",
  2736. "ydieresis",
  2737. "zcaron",
  2738. "exclamsmall",
  2739. "Hungarumlautsmall",
  2740. "dollaroldstyle",
  2741. "dollarsuperior",
  2742. "ampersandsmall",
  2743. "Acutesmall",
  2744. "parenleftsuperior",
  2745. "parenrightsuperior",
  2746. "twodotenleader",
  2747. "onedotenleader",
  2748. "zerooldstyle",
  2749. "oneoldstyle",
  2750. "twooldstyle",
  2751. "threeoldstyle",
  2752. "fouroldstyle",
  2753. "fiveoldstyle",
  2754. "sixoldstyle",
  2755. "sevenoldstyle",
  2756. "eightoldstyle",
  2757. "nineoldstyle",
  2758. "commasuperior",
  2759. "threequartersemdash",
  2760. "periodsuperior",
  2761. "questionsmall",
  2762. "asuperior",
  2763. "bsuperior",
  2764. "centsuperior",
  2765. "dsuperior",
  2766. "esuperior",
  2767. "isuperior",
  2768. "lsuperior",
  2769. "msuperior",
  2770. "nsuperior",
  2771. "osuperior",
  2772. "rsuperior",
  2773. "ssuperior",
  2774. "tsuperior",
  2775. "ff",
  2776. "ffi",
  2777. "ffl",
  2778. "parenleftinferior",
  2779. "parenrightinferior",
  2780. "Circumflexsmall",
  2781. "hyphensuperior",
  2782. "Gravesmall",
  2783. "Asmall",
  2784. "Bsmall",
  2785. "Csmall",
  2786. "Dsmall",
  2787. "Esmall",
  2788. "Fsmall",
  2789. "Gsmall",
  2790. "Hsmall",
  2791. "Ismall",
  2792. "Jsmall",
  2793. "Ksmall",
  2794. "Lsmall",
  2795. "Msmall",
  2796. "Nsmall",
  2797. "Osmall",
  2798. "Psmall",
  2799. "Qsmall",
  2800. "Rsmall",
  2801. "Ssmall",
  2802. "Tsmall",
  2803. "Usmall",
  2804. "Vsmall",
  2805. "Wsmall",
  2806. "Xsmall",
  2807. "Ysmall",
  2808. "Zsmall",
  2809. "colonmonetary",
  2810. "onefitted",
  2811. "rupiah",
  2812. "Tildesmall",
  2813. "exclamdownsmall",
  2814. "centoldstyle",
  2815. "Lslashsmall",
  2816. "Scaronsmall",
  2817. "Zcaronsmall",
  2818. "Dieresissmall",
  2819. "Brevesmall",
  2820. "Caronsmall",
  2821. "Dotaccentsmall",
  2822. "Macronsmall",
  2823. "figuredash",
  2824. "hypheninferior",
  2825. "Ogoneksmall",
  2826. "Ringsmall",
  2827. "Cedillasmall",
  2828. "questiondownsmall",
  2829. "oneeighth",
  2830. "threeeighths",
  2831. "fiveeighths",
  2832. "seveneighths",
  2833. "onethird",
  2834. "twothirds",
  2835. "zerosuperior",
  2836. "foursuperior",
  2837. "fivesuperior",
  2838. "sixsuperior",
  2839. "sevensuperior",
  2840. "eightsuperior",
  2841. "ninesuperior",
  2842. "zeroinferior",
  2843. "oneinferior",
  2844. "twoinferior",
  2845. "threeinferior",
  2846. "fourinferior",
  2847. "fiveinferior",
  2848. "sixinferior",
  2849. "seveninferior",
  2850. "eightinferior",
  2851. "nineinferior",
  2852. "centinferior",
  2853. "dollarinferior",
  2854. "periodinferior",
  2855. "commainferior",
  2856. "Agravesmall",
  2857. "Aacutesmall",
  2858. "Acircumflexsmall",
  2859. "Atildesmall",
  2860. "Adieresissmall",
  2861. "Aringsmall",
  2862. "AEsmall",
  2863. "Ccedillasmall",
  2864. "Egravesmall",
  2865. "Eacutesmall",
  2866. "Ecircumflexsmall",
  2867. "Edieresissmall",
  2868. "Igravesmall",
  2869. "Iacutesmall",
  2870. "Icircumflexsmall",
  2871. "Idieresissmall",
  2872. "Ethsmall",
  2873. "Ntildesmall",
  2874. "Ogravesmall",
  2875. "Oacutesmall",
  2876. "Ocircumflexsmall",
  2877. "Otildesmall",
  2878. "Odieresissmall",
  2879. "OEsmall",
  2880. "Oslashsmall",
  2881. "Ugravesmall",
  2882. "Uacutesmall",
  2883. "Ucircumflexsmall",
  2884. "Udieresissmall",
  2885. "Yacutesmall",
  2886. "Thornsmall",
  2887. "Ydieresissmall",
  2888. "001.000",
  2889. "001.001",
  2890. "001.002",
  2891. "001.003",
  2892. "Black",
  2893. "Bold",
  2894. "Book",
  2895. "Light",
  2896. "Medium",
  2897. "Regular",
  2898. "Roman",
  2899. "Semibold",
  2900. ]
  2901. cffStandardStringCount = 391
  2902. assert len(cffStandardStrings) == cffStandardStringCount
  2903. # build reverse mapping
  2904. cffStandardStringMapping = {}
  2905. for _i in range(cffStandardStringCount):
  2906. cffStandardStringMapping[cffStandardStrings[_i]] = _i
  2907. cffISOAdobeStrings = [
  2908. ".notdef",
  2909. "space",
  2910. "exclam",
  2911. "quotedbl",
  2912. "numbersign",
  2913. "dollar",
  2914. "percent",
  2915. "ampersand",
  2916. "quoteright",
  2917. "parenleft",
  2918. "parenright",
  2919. "asterisk",
  2920. "plus",
  2921. "comma",
  2922. "hyphen",
  2923. "period",
  2924. "slash",
  2925. "zero",
  2926. "one",
  2927. "two",
  2928. "three",
  2929. "four",
  2930. "five",
  2931. "six",
  2932. "seven",
  2933. "eight",
  2934. "nine",
  2935. "colon",
  2936. "semicolon",
  2937. "less",
  2938. "equal",
  2939. "greater",
  2940. "question",
  2941. "at",
  2942. "A",
  2943. "B",
  2944. "C",
  2945. "D",
  2946. "E",
  2947. "F",
  2948. "G",
  2949. "H",
  2950. "I",
  2951. "J",
  2952. "K",
  2953. "L",
  2954. "M",
  2955. "N",
  2956. "O",
  2957. "P",
  2958. "Q",
  2959. "R",
  2960. "S",
  2961. "T",
  2962. "U",
  2963. "V",
  2964. "W",
  2965. "X",
  2966. "Y",
  2967. "Z",
  2968. "bracketleft",
  2969. "backslash",
  2970. "bracketright",
  2971. "asciicircum",
  2972. "underscore",
  2973. "quoteleft",
  2974. "a",
  2975. "b",
  2976. "c",
  2977. "d",
  2978. "e",
  2979. "f",
  2980. "g",
  2981. "h",
  2982. "i",
  2983. "j",
  2984. "k",
  2985. "l",
  2986. "m",
  2987. "n",
  2988. "o",
  2989. "p",
  2990. "q",
  2991. "r",
  2992. "s",
  2993. "t",
  2994. "u",
  2995. "v",
  2996. "w",
  2997. "x",
  2998. "y",
  2999. "z",
  3000. "braceleft",
  3001. "bar",
  3002. "braceright",
  3003. "asciitilde",
  3004. "exclamdown",
  3005. "cent",
  3006. "sterling",
  3007. "fraction",
  3008. "yen",
  3009. "florin",
  3010. "section",
  3011. "currency",
  3012. "quotesingle",
  3013. "quotedblleft",
  3014. "guillemotleft",
  3015. "guilsinglleft",
  3016. "guilsinglright",
  3017. "fi",
  3018. "fl",
  3019. "endash",
  3020. "dagger",
  3021. "daggerdbl",
  3022. "periodcentered",
  3023. "paragraph",
  3024. "bullet",
  3025. "quotesinglbase",
  3026. "quotedblbase",
  3027. "quotedblright",
  3028. "guillemotright",
  3029. "ellipsis",
  3030. "perthousand",
  3031. "questiondown",
  3032. "grave",
  3033. "acute",
  3034. "circumflex",
  3035. "tilde",
  3036. "macron",
  3037. "breve",
  3038. "dotaccent",
  3039. "dieresis",
  3040. "ring",
  3041. "cedilla",
  3042. "hungarumlaut",
  3043. "ogonek",
  3044. "caron",
  3045. "emdash",
  3046. "AE",
  3047. "ordfeminine",
  3048. "Lslash",
  3049. "Oslash",
  3050. "OE",
  3051. "ordmasculine",
  3052. "ae",
  3053. "dotlessi",
  3054. "lslash",
  3055. "oslash",
  3056. "oe",
  3057. "germandbls",
  3058. "onesuperior",
  3059. "logicalnot",
  3060. "mu",
  3061. "trademark",
  3062. "Eth",
  3063. "onehalf",
  3064. "plusminus",
  3065. "Thorn",
  3066. "onequarter",
  3067. "divide",
  3068. "brokenbar",
  3069. "degree",
  3070. "thorn",
  3071. "threequarters",
  3072. "twosuperior",
  3073. "registered",
  3074. "minus",
  3075. "eth",
  3076. "multiply",
  3077. "threesuperior",
  3078. "copyright",
  3079. "Aacute",
  3080. "Acircumflex",
  3081. "Adieresis",
  3082. "Agrave",
  3083. "Aring",
  3084. "Atilde",
  3085. "Ccedilla",
  3086. "Eacute",
  3087. "Ecircumflex",
  3088. "Edieresis",
  3089. "Egrave",
  3090. "Iacute",
  3091. "Icircumflex",
  3092. "Idieresis",
  3093. "Igrave",
  3094. "Ntilde",
  3095. "Oacute",
  3096. "Ocircumflex",
  3097. "Odieresis",
  3098. "Ograve",
  3099. "Otilde",
  3100. "Scaron",
  3101. "Uacute",
  3102. "Ucircumflex",
  3103. "Udieresis",
  3104. "Ugrave",
  3105. "Yacute",
  3106. "Ydieresis",
  3107. "Zcaron",
  3108. "aacute",
  3109. "acircumflex",
  3110. "adieresis",
  3111. "agrave",
  3112. "aring",
  3113. "atilde",
  3114. "ccedilla",
  3115. "eacute",
  3116. "ecircumflex",
  3117. "edieresis",
  3118. "egrave",
  3119. "iacute",
  3120. "icircumflex",
  3121. "idieresis",
  3122. "igrave",
  3123. "ntilde",
  3124. "oacute",
  3125. "ocircumflex",
  3126. "odieresis",
  3127. "ograve",
  3128. "otilde",
  3129. "scaron",
  3130. "uacute",
  3131. "ucircumflex",
  3132. "udieresis",
  3133. "ugrave",
  3134. "yacute",
  3135. "ydieresis",
  3136. "zcaron",
  3137. ]
  3138. cffISOAdobeStringCount = 229
  3139. assert len(cffISOAdobeStrings) == cffISOAdobeStringCount
  3140. cffIExpertStrings = [
  3141. ".notdef",
  3142. "space",
  3143. "exclamsmall",
  3144. "Hungarumlautsmall",
  3145. "dollaroldstyle",
  3146. "dollarsuperior",
  3147. "ampersandsmall",
  3148. "Acutesmall",
  3149. "parenleftsuperior",
  3150. "parenrightsuperior",
  3151. "twodotenleader",
  3152. "onedotenleader",
  3153. "comma",
  3154. "hyphen",
  3155. "period",
  3156. "fraction",
  3157. "zerooldstyle",
  3158. "oneoldstyle",
  3159. "twooldstyle",
  3160. "threeoldstyle",
  3161. "fouroldstyle",
  3162. "fiveoldstyle",
  3163. "sixoldstyle",
  3164. "sevenoldstyle",
  3165. "eightoldstyle",
  3166. "nineoldstyle",
  3167. "colon",
  3168. "semicolon",
  3169. "commasuperior",
  3170. "threequartersemdash",
  3171. "periodsuperior",
  3172. "questionsmall",
  3173. "asuperior",
  3174. "bsuperior",
  3175. "centsuperior",
  3176. "dsuperior",
  3177. "esuperior",
  3178. "isuperior",
  3179. "lsuperior",
  3180. "msuperior",
  3181. "nsuperior",
  3182. "osuperior",
  3183. "rsuperior",
  3184. "ssuperior",
  3185. "tsuperior",
  3186. "ff",
  3187. "fi",
  3188. "fl",
  3189. "ffi",
  3190. "ffl",
  3191. "parenleftinferior",
  3192. "parenrightinferior",
  3193. "Circumflexsmall",
  3194. "hyphensuperior",
  3195. "Gravesmall",
  3196. "Asmall",
  3197. "Bsmall",
  3198. "Csmall",
  3199. "Dsmall",
  3200. "Esmall",
  3201. "Fsmall",
  3202. "Gsmall",
  3203. "Hsmall",
  3204. "Ismall",
  3205. "Jsmall",
  3206. "Ksmall",
  3207. "Lsmall",
  3208. "Msmall",
  3209. "Nsmall",
  3210. "Osmall",
  3211. "Psmall",
  3212. "Qsmall",
  3213. "Rsmall",
  3214. "Ssmall",
  3215. "Tsmall",
  3216. "Usmall",
  3217. "Vsmall",
  3218. "Wsmall",
  3219. "Xsmall",
  3220. "Ysmall",
  3221. "Zsmall",
  3222. "colonmonetary",
  3223. "onefitted",
  3224. "rupiah",
  3225. "Tildesmall",
  3226. "exclamdownsmall",
  3227. "centoldstyle",
  3228. "Lslashsmall",
  3229. "Scaronsmall",
  3230. "Zcaronsmall",
  3231. "Dieresissmall",
  3232. "Brevesmall",
  3233. "Caronsmall",
  3234. "Dotaccentsmall",
  3235. "Macronsmall",
  3236. "figuredash",
  3237. "hypheninferior",
  3238. "Ogoneksmall",
  3239. "Ringsmall",
  3240. "Cedillasmall",
  3241. "onequarter",
  3242. "onehalf",
  3243. "threequarters",
  3244. "questiondownsmall",
  3245. "oneeighth",
  3246. "threeeighths",
  3247. "fiveeighths",
  3248. "seveneighths",
  3249. "onethird",
  3250. "twothirds",
  3251. "zerosuperior",
  3252. "onesuperior",
  3253. "twosuperior",
  3254. "threesuperior",
  3255. "foursuperior",
  3256. "fivesuperior",
  3257. "sixsuperior",
  3258. "sevensuperior",
  3259. "eightsuperior",
  3260. "ninesuperior",
  3261. "zeroinferior",
  3262. "oneinferior",
  3263. "twoinferior",
  3264. "threeinferior",
  3265. "fourinferior",
  3266. "fiveinferior",
  3267. "sixinferior",
  3268. "seveninferior",
  3269. "eightinferior",
  3270. "nineinferior",
  3271. "centinferior",
  3272. "dollarinferior",
  3273. "periodinferior",
  3274. "commainferior",
  3275. "Agravesmall",
  3276. "Aacutesmall",
  3277. "Acircumflexsmall",
  3278. "Atildesmall",
  3279. "Adieresissmall",
  3280. "Aringsmall",
  3281. "AEsmall",
  3282. "Ccedillasmall",
  3283. "Egravesmall",
  3284. "Eacutesmall",
  3285. "Ecircumflexsmall",
  3286. "Edieresissmall",
  3287. "Igravesmall",
  3288. "Iacutesmall",
  3289. "Icircumflexsmall",
  3290. "Idieresissmall",
  3291. "Ethsmall",
  3292. "Ntildesmall",
  3293. "Ogravesmall",
  3294. "Oacutesmall",
  3295. "Ocircumflexsmall",
  3296. "Otildesmall",
  3297. "Odieresissmall",
  3298. "OEsmall",
  3299. "Oslashsmall",
  3300. "Ugravesmall",
  3301. "Uacutesmall",
  3302. "Ucircumflexsmall",
  3303. "Udieresissmall",
  3304. "Yacutesmall",
  3305. "Thornsmall",
  3306. "Ydieresissmall",
  3307. ]
  3308. cffExpertStringCount = 166
  3309. assert len(cffIExpertStrings) == cffExpertStringCount
  3310. cffExpertSubsetStrings = [
  3311. ".notdef",
  3312. "space",
  3313. "dollaroldstyle",
  3314. "dollarsuperior",
  3315. "parenleftsuperior",
  3316. "parenrightsuperior",
  3317. "twodotenleader",
  3318. "onedotenleader",
  3319. "comma",
  3320. "hyphen",
  3321. "period",
  3322. "fraction",
  3323. "zerooldstyle",
  3324. "oneoldstyle",
  3325. "twooldstyle",
  3326. "threeoldstyle",
  3327. "fouroldstyle",
  3328. "fiveoldstyle",
  3329. "sixoldstyle",
  3330. "sevenoldstyle",
  3331. "eightoldstyle",
  3332. "nineoldstyle",
  3333. "colon",
  3334. "semicolon",
  3335. "commasuperior",
  3336. "threequartersemdash",
  3337. "periodsuperior",
  3338. "asuperior",
  3339. "bsuperior",
  3340. "centsuperior",
  3341. "dsuperior",
  3342. "esuperior",
  3343. "isuperior",
  3344. "lsuperior",
  3345. "msuperior",
  3346. "nsuperior",
  3347. "osuperior",
  3348. "rsuperior",
  3349. "ssuperior",
  3350. "tsuperior",
  3351. "ff",
  3352. "fi",
  3353. "fl",
  3354. "ffi",
  3355. "ffl",
  3356. "parenleftinferior",
  3357. "parenrightinferior",
  3358. "hyphensuperior",
  3359. "colonmonetary",
  3360. "onefitted",
  3361. "rupiah",
  3362. "centoldstyle",
  3363. "figuredash",
  3364. "hypheninferior",
  3365. "onequarter",
  3366. "onehalf",
  3367. "threequarters",
  3368. "oneeighth",
  3369. "threeeighths",
  3370. "fiveeighths",
  3371. "seveneighths",
  3372. "onethird",
  3373. "twothirds",
  3374. "zerosuperior",
  3375. "onesuperior",
  3376. "twosuperior",
  3377. "threesuperior",
  3378. "foursuperior",
  3379. "fivesuperior",
  3380. "sixsuperior",
  3381. "sevensuperior",
  3382. "eightsuperior",
  3383. "ninesuperior",
  3384. "zeroinferior",
  3385. "oneinferior",
  3386. "twoinferior",
  3387. "threeinferior",
  3388. "fourinferior",
  3389. "fiveinferior",
  3390. "sixinferior",
  3391. "seveninferior",
  3392. "eightinferior",
  3393. "nineinferior",
  3394. "centinferior",
  3395. "dollarinferior",
  3396. "periodinferior",
  3397. "commainferior",
  3398. ]
  3399. cffExpertSubsetStringCount = 87
  3400. assert len(cffExpertSubsetStrings) == cffExpertSubsetStringCount