)Ej7LUdZddlmZddlZddlmZddlmZmZm Z m Z m Z ddl m Z ddlmcmZddlmZmZddlmZdd lmZmZdd lmZmZdd lmZdd lm Z dd l!m"Z"m#Z#m$Z$ddl%m&Z&m'Z'm(Z(m)Z)m*Z*m+Z+m,Z,er*ddl-m.Z.m/Z/m0Z0ddlm1Z1ddl2m3Z3m4Z4m5Z5m6Z6m7Z7m8Z8m9Z9m:Z:ddl;md<ej?e@ZAde>d<dZBdZCGdde"ZDGddZEGddeZFdd%ZG ddd1ZH ddd8ZI ddd9ZJdd=ZKdd>ZLdd?ZMdd@ZNddCZOddFZPddGZQddHZReSeTe'IeSeSe(IdJZUddMZVddPZWddSZXddTZYddeDZd&fddXZ[ ddd[Z\ ddd^Z]eDj^e\eDj_e]iZ`d_e>d`<ddbZadddZbddfZcddhZdddjZedkhZfdBe>dl<hdmZgdBe>dn<egdkhzZhdBe>do<hdpZidBe>dq<eidkhzZjdBe>dr<dsdthZkdBe>du<hdvZldBe>dw<ddzZmdd}ZnddZoddZpddZqddZrddZsddZtddZu ddZvddZwddZxGddeyZzGddZ{ddZ|Gdde{Z}ddZ~Gdde{ZddZGdde{ZgdZde>d<GddeZe@dkrddlZejdSdS)a~ Generic module for reading and writing the .glif format. More info about the .glif format (GLyphInterchangeFormat) can be found here: http://unifiedfontobject.org The main class in this module is :class:`GlyphSet`. It manages a set of .glif files in a folder. It offers two ways to read glyph data, and one way to write glyph data. See the class doc string for details. ) annotationsN) OrderedDict) TYPE_CHECKINGAnyOptionalUnioncast)warn)etreeplistlib)tobytes)AbstractPointPenPointToSegmentPen)UFOFormatVersion _UFOBaseIO) GlifLibError)userNameToFileName)BaseFormatVersionnormalizeFormatVersion numberTypes)anchorsValidatorcolorValidatorgenericTypeValidatorglyphLibValidatorguidelinesValidatoridentifierValidatorimageValidator)CallableIterableSet)Logger) ElementType FormatVersionFormatVersionsGLIFFormatVersionInputGlyphNameToFileNameFuncIntFloatPathOrFSUFOFormatVersionInput)FS)GlyphSetrreadGlyphFromStringwriteGlyphToStringglyphNameToFileName list[str]__all__r!loggerzcontents.plistzlayerinfo.plistc`eZdZdZdZdZe d d fd Ze d d fd ZxZ S)GLIFFormatVersiona{Class representing the versions of the .glif format supported by the UFO version in use. For a given :mod:`fontTools.ufoLib.UFOFormatVersion`, the :func:`supported_versions` method will return the supported versions of the GLIF file format. If the UFO version is unspecified, the :func:`supported_versions` method will return all available GLIF format versions. )r)rNufoFormatVersionOptional[UFOFormatVersion]returnc|"t||StSN)maxsupported_versionssuperdefault)clsr6 __class__s JC:\PYTHON\MyICR_Suite\python\Lib\site-packages\fontTools/ufoLib/glifLib.pyr>zGLIFFormatVersion.defaultYs<  's--.>??@@ @ww   frozenset[GLIFFormatVersion]c| tS|jh}|tjkr||jt|Sr:)r=r< FORMAT_1_0r FORMAT_3_0add FORMAT_2_0 frozenset)r?r6versionsr@s rAr<z$GLIFFormatVersion.supported_versionsas\  #77--// /N# /: : : LL ( ( ("""rBr:)r6r7r8r3)r6r7r8rC) __name__ __module__ __qualname____doc__rErH classmethodr>r< __classcell__r@s@rAr3r3NsJJ<@!!!!!![!<@ # # # # # #[ # # # # #rBr3c,eZdZdZddZdddZddZdS)Glyphz Minimal glyph object. It has no glyph attributes until either the draw() or the drawPoints() method has been called. glyphNamestrglyphSetr+r8Nonec"||_||_dSr:)rTrV)selfrTrVs rA__init__zGlyph.__init__zs'"* rBFpenroutputImpliedClosingLineboolcRt||}||dS)z9 Draw this glyph onto a *FontTools* Pen. )r\N)r drawPoints)rYr[r\pointPens rAdrawz Glyph.draw~s8% *B    !!!!!rBr`rcH|j|j||dS)z2 Draw this glyph onto a PointPen. N)rV readGlyphrT)rYr`s rAr_zGlyph.drawPointss& h?????rBN)rTrUrVr+r8rWF)r[rr\r]r8rW)r`rr8rW)rKrLrMrNrZrar_rBrArSrStse ++++"""""@@@@@@rBrSceZdZdZeZ dAdBdZdCdDdZdEdZdFdZ dGdHdZ dGdIdZ dJdZ dKd Z dLdMd&Z dNdOd+ZdPd,ZdQd.ZdRd/ZeZdSd1ZdTd2Z dGdUd6Z dGdVd8Z dGdWd:ZdFd;ZdXd<ZdYd@ZdS)Zr+aL GlyphSet manages a set of .glif files inside one directory. GlyphSet's constructor takes a path to an existing directory as it's first argument. Reading glyph data can either be done through the readGlyph() method, or by using GlyphSet's dictionary interface, where the keys are glyph names and the values are (very) simple glyph objects. To write a glyph to the glyph set, you use the writeGlyph() method. The simple glyph objects returned through the dict interface do not support writing, they are just a convenient way to get at the glyph data. NTFpathr(glyphNameToFileNameFuncr&r6r) validateReadr] validateWriteexpectContentsFiler8rWc t|t}n'#t$r}ddlm}|d||d}~wwxYwt |dr|}t|trS tj |} n*#tj j $rtd|zwxYwd|_nt|tjjrJ|} | n*#tj j$rtd| zwxYwd |_n$t)d t+|jz | d }n)#tj j$rt| }YnwxYwtj||_| |_ | t:|_|r|jstt:d |j|_ ||_!|tD}||_"||_#||_$d|_%d|_&|'dS) a 'path' should be a path (string) to an existing local directory, or an instance of fs.base.FS class. The optional 'glyphNameToFileNameFunc' argument must be a callback function that takes two arguments: a glyph name and a list of all existing filenames (if any exist). It should return a file name (including the .glif extension). The glyphNameToFileName function is called whenever a file name is created for a given glyph name. ``validateRead`` will validate read operations. Its default is ``True``. ``validateWrite`` will validate write operations. Its default is ``True``. ``expectContentsFile`` will raise a GlifLibError if a contents.plist file is not found on the glyph set file system. This should be set to ``True`` if you are reading an existing UFO and ``False`` if you create a fresh glyph set. r)UnsupportedUFOFormatzUnsupported UFO format: N __fspath__zNo glyphs directory '%s'Tzthe filesystem '%s' is closedFz-Expected a path string or fs object, found %s/z is missing.)(rr ValueErrorfontTools.ufoLib.errorsrmhasattrrn isinstancerUfsosfsOSFSerrors CreateFailedr _shouldClosebaser*checkFilesystemClosed TypeErrortyperK getsyspath NoSysPathrgbasenamedirNameexistsCONTENTS_FILENAME_havePreviousFilemajorr6ufoFormatVersionTupler. _validateRead_validateWrite_existingFileNames_reverseContentsrebuildContents) rYrgrhr6rirjrkerm filesystems rArZzGlyphSet.__init__s2 5 "2        D D D D D D&&?+;??   4 & & %??$$D dC   F!#d!3!3 9) F F F"#=#DEEE F&*D   bgj ) ) J Q  """"9- Q Q Q"#BZ#OPPP Q %D  ?$t**BUU  #((--DDy" # # #z??DDD # G,,T22  '1'8'89J'K'K  Cd&< C"3AAABB B%5%;7G" " *&9 # #  $0$137:> s: <7<9B'C-D'D)E//#FFc||j}|ti}|rd}t|tsd}n||D]g\}}t|t sd}t|t sd}4|j|sttd|h|rtdtz||_ d|_ d|_ dS)z Rebuild the contents dict by loading contents.plist. ``validateRead`` will validate the data, by default it is set to the class's ``validateRead`` value, can be overridden. NFTz( references a file that does not exist: z%s is not properly formatted) r _getPlistrrsdictitemsrUrtrrcontentsrr)rYrir invalidFormatnamefileNames rArzGlyphSet.rebuildContentss  -L>>"3R88  W!Mh--  $ &.nn&6&6  ND(%dC00-(, %h44(, !W^^H55*000((<  W"#ADU#UVVV(0 "& $rBdict[str, str]c|j?i}|jD]\}}|||<||_|jS)a Return a reversed dict of self.contents, mapping file names to glyph names. This is primarily an aid for custom glyph name to file name schemes that want to make sure they don't generate duplicate file names. The file names are converted to lowercase so we can reliably check for duplicates that only differ in case, which is important for case-insensitive file systems. )rrrlower)rYdkvs rAgetReverseContentszGlyphSet.getReverseContentssW  (A ++-- ! !1 !'')) $%D !$$rBcF|t|jdS)zv Write the contents.plist file out to disk. Call this method when you're done writing glyphs. N) _writePlistrrrYs rA writeContentszGlyphSet.writeContents(s# *DM:::::rBinforOptional[bool]cP||j}|ti}|r3t|tst dt |}|D]7\}} t|||#t$rt d|zwxYwdS)z ``validateRead`` will validate the data, by default it is set to the class's ``validateRead`` value, can be overridden. Nz*layerinfo.plist is not properly formatted.zSThe supplied layer info object does not support setting a necessary attribute (%s).) rrLAYERINFO_FILENAMErsrrvalidateLayerInfoVersion3DatarsetattrAttributeError)rYrriinfoDictattrvalues rA readLayerInfozGlyphSet.readLayerInfo1s  -L>>"4b99  ?h-- Q"#OPPP4X>>H#>>++  KD% dE****!   "i   s 4BB#cB||j}|jjdkrtd|jjzi}tD]T}t ||rB t||}n #t$rtd|zwxYw||dkr|sO|||<U|r.|rt|}| t|dS|j r@|j tr#|j tdSdSdS)z ``validateWrite`` will validate the data, by default it is set to the class's ``validateWrite`` value, can be overridden. Nz)layerinfo.plist is not allowed in UFO %d.zMThe supplied info object does not support getting a necessary attribute (%s).lib)rrrrlayerInfoVersion3ValueDatakeysrrgetattrrrrrrrtrremove)rYrrjinfoDatarrs rAwriteLayerInfozGlyphSet.writeLayerInfoGss   /M  % +a / /;,23  .3355 ' 'DtT"" '#D$//EE%&g =TU]]5]!&  / C8BB   / : : : : :  # /7I(J(J / GNN- . . . . . / / / /s $A55BrTrUbytesc |j|} |j|S#tjj$rt d|d|d|jwxYw)a Get the raw GLIF text for a given glyph name. This only works for GLIF files that are already on disk. This method is useful in situations when the raw XML needs to be read from a glyph set for a particular glyph before fully parsing it into an object structure via the readGlyph method. Raises KeyError if 'glyphName' is not in contents.plist, or GlifLibError if the file associated with can't be found. z The file 'z' associated with glyph 'z&' in contents.plist does not exist on )rrt readbytesrwResourceNotFoundrrYrTrs rAgetGLIFzGlyphSet.getGLIFksx=+ 7$$X.. .y)   ,*2((IIItwwH  s )2AOptional[float]cF|j|}||S)ao Returns the modification time for the GLIF file with 'glyphName', as a floating point number giving the number of seconds since the epoch. Return None if the associated file does not exist or the underlying filesystem does not support getting modified times. Raises KeyError if the glyphName is not in contents.plist. )rgetFileModificationTimers rAgetGLIFModificationTimez GlyphSet.getGLIFModificationTimes$=+++H555rB glyphObject Optional[Any]r`Optional[AbstractPointPen]validatec||j}||} t|}t|j}t |||||dS#t$r}|j|} d|j | d} n5#tj j $rd| dt|j d} YnwxYw|d|d| dd}~wwxYw)a` Read a .glif file for 'glyphName' from the glyph set. The 'glyphObject' argument can be any kind of object (even None); the readGlyph() method will attempt to set the following attributes on it: width the advance width of the glyph height the advance height of the glyph unicodes a list of unicode values for this glyph note a string lib a dictionary containing custom data image a dictionary containing image data guidelines a list of guideline data dictionaries anchors a list of anchor data dictionaries All attributes are optional, in two ways: 1) An attribute *won't* be set if the .glif file doesn't contain data for it. 'glyphObject' will have to deal with default values itself. 2) If setting the attribute fails with an AttributeError (for example if the 'glyphObject' attribute is read- only), readGlyph() will not propagate that exception, but ignore that attribute. To retrieve outline information, you need to pass an object conforming to the PointPen protocol as the 'pointPen' argument. This argument may be None if you don't need the outline data. readGlyph() will raise KeyError if the glyph is not present in the glyph set. ``validate`` will validate the data, by default it is set to the class's ``validateRead`` value, can be overridden. NformatVersionsr'z' from 'zThe issue is in glyph 'z', located in .)rr_glifTreeFromStringr3r<r_readGlyphFromTreerrrtrrwrrU _add_note) rYrTrr`rtexttreer glifLibErrorr glifLocations rArczGlyphSet.readGlyphsZd  )H||I&& &t,,D.AA*N -!          }Y/H EB47#5#5h#?#?BBB 9& E E E E8DDS\\DDD  E  " "R)RR<RRR     s<AA$$ C2. C-<BC-/C  C- C  C--C2drawPointsFunc,Optional[Callable[[AbstractPointPen], None]] formatVersionr%c| t|j}n> t|t}n'#t$r}ddlm}|d||d}~wwxYw|t|jvrddlm}|d|d|jd||j}|j |}||j (d|j D|_ | ||j }||j |<|j ||j||j|<t#||||| } |jr:|j|r | |j|krdS|j|| dS) aV Write a .glif file for 'glyphName' to the glyph set. The 'glyphObject' argument can be any kind of object (even None); the writeGlyph() method will attempt to get the following attributes from it: width the advance width of the glyph height the advance height of the glyph unicodes a list of unicode values for this glyph note a string lib a dictionary containing custom data image a dictionary containing image data guidelines a list of guideline data dictionaries anchors a list of anchor data dictionaries All attributes are optional: if 'glyphObject' doesn't have the attribute, it will simply be skipped. To write outline data to the .glif file, writeGlyph() needs a function (any callable object actually) that will take one argument: an object that conforms to the PointPen protocol. The function will be called by writeGlyph(); it has to call the proper PointPen methods to transfer the outline to the .glif file. The GLIF format version will be chosen based on the ufoFormatVersion passed during the creation of this object. If a particular format version is desired, it can be passed with the formatVersion argument. The formatVersion argument accepts either a tuple of integers for (major, minor), or a single integer for the major digit only (with minor digit implied as 0). An UnsupportedGLIFFormat exception is raised if the requested GLIF formatVersion is not supported. ``validate`` will validate the data, by default it is set to the class's ``validateWrite`` value, can be overridden. NrUnsupportedGLIFFormatz!Unsupported GLIF format version: z!Unsupported GLIF format version (z) for UFO format version rc6h|]}|Sre)r).0rs rA z&GlyphSet.writeGlyph..,s/+++)1HNN$$+++rB)rr)r3r>rrrprqrr<rrgetrvaluesr.rGrr_writeGlyphToBytesrrtrr writebytes) rYrTrrrrrrrdatas rA writeGlyphzGlyphSet.writeGlyphs\j  -55d6PQQMM  6}FW X X    IIIIII++I II   1 D D  &! !    F E E E E E''JMJJ*.*DJJJ   *H=$$Y//  &.++59]5I5I5K5K+++'// 4;RSSH'/DM) $  # ' '(8(8 9 9 9$0:C%hnn&6&67!   '      " x(( ))(3333 F 8T*****s: AAAc |j|}|j||j,|j||j|j|=|j|=dS)zPermanently delete the glyph from the glyph set on disk. Will raise KeyError if the glyph is not present in the glyph set. N)rrtrrrrrs rA deleteGlyphzGlyphSet.deleteGlyphCs|=+ x    " .  # * *8>>+;+; < < <  ,%hnn&6&67 M) $ $ $rBr/cNt|jSr:)listrrrs rArz GlyphSet.keysQsDM&&(()))rBc||jvSr:)rrYrTs rAhas_keyzGlyphSet.has_keyTsDM))rBintc*t|jSr:)lenrrs rA__len__zGlyphSet.__len__Ys4=!!!rBc^||jvrt||||Sr:)rKeyError glyphClassrs rA __getitem__zGlyphSet.__getitem__\s1 DM ) )9%% %y$///rB glyphNamesOptional[Iterable[str]]dict[str, list[int]]ci}||j}|D])}||}t|||<*|S)aC Return a dictionary that maps glyph names to lists containing the unicode value[s] for that glyph, if any. This parses the .glif files partially, so it is a lot faster than parsing all files completely. By default this checks all glyphs, but a subset can be passed with glyphNames. )rrr_fetchUnicodes)rYrunicodesrTrs rA getUnicodeszGlyphSet.getUnicodescs\  ++--J# 7 7I<< **D"0"6"6HY  rBdict[str, list[str]]ci}||j}|D])}||}t|||<*|S)aF Return a dictionary that maps glyph names to lists containing the base glyph name of components in the glyph. This parses the .glif files partially, so it is a lot faster than parsing all files completely. By default this checks all glyphs, but a subset can be passed with glyphNames. )rrr_fetchComponentBases)rYr componentsrTrs rAgetComponentReferenceszGlyphSet.getComponentReferencests]  ++--J# ? ?I<< **D$8$>$>Jy ! !rBdict[str, Optional[str]]ci}||j}|D])}||}t|||<*|S)a9 Return a dictionary that maps glyph names to the file name of the image referenced by the glyph. This parses the .glif files partially, so it is a lot faster than parsing all files completely. By default this checks all glyphs, but a subset can be passed with glyphNames. )rrr_fetchImageFileName)rYrimagesrTrs rAgetImageReferenceszGlyphSet.getImageReferencess\  ++--J# : :I<< **D 3D 9 9F9   rBcJ|jr|jdSdSr:)ryrtclosers rArzGlyphSet.closes*    GMMOOOOO  rBc|Sr:rers rA __enter__zGlyphSet.__enter__s rBexc_type exc_valueexc_tbc.|dSr:)r)rYrrrs rA__exit__zGlyphSet.__exit__s rB)NNTTF)rgr(rhr&r6r)rir]rjr]rkr]r8rWrd)rir]r8rW)r8rr8rWr:)rrrirr8rW)rrrjrr8rW)rTrUr8r)rTrUr8r)NNN) rTrUrrr`rrrr8rWNNNN) rTrUrrrrrr%rrr8rW)rTrUr8rW)r8r/)rTrUr8r])r8r)rTrUr8r)rrr8r)rrr8r)rrr8r)r8r+)rrrrrrr8rW)rKrLrMrNrSrrZrrrrrrrrcrrrr __contains__rrrrrrrrrerBrAr+r+sK  J <@26!"#(SSSSSj%%%%%@%%%% ;;;;,"/"/"/"/"/H* 6 6 6 6 &*/3#' OOOOOh&*GK04#' c+c+c+c+c+J % % % %********L""""000059$59$59"rBr+rTrUexistingFileNamesOptional[set[str]]r8cF|t}t||dS)z Wrapper around the userNameToFileName function in filenames.py Note that existingFileNames should be a set for large glyphsets or performance will suffer. Nz.glif)existingsuffix)setr)rTr s rAr.r.s* EE i2CG T T TTrBTaStringUnion[str, bytes]rrr`rr$rr]rWct|}|t}ntt}}|D]R} t |t} || .#t $r||YOwxYw|st d|t|||||dS)a/ Read .glif data from a string into a glyph object. The 'glyphObject' argument can be any kind of object (even None); the readGlyphFromString() method will attempt to set the following attributes on it: width the advance width of the glyph height the advance height of the glyph unicodes a list of unicode values for this glyph note a string lib a dictionary containing custom data image a dictionary containing image data guidelines a list of guideline data dictionaries anchors a list of anchor data dictionaries All attributes are optional, in two ways: 1) An attribute *won't* be set if the .glif file doesn't contain data for it. 'glyphObject' will have to deal with default values itself. 2) If setting the attribute fails with an AttributeError (for example if the 'glyphObject' attribute is read- only), readGlyphFromString() will not propagate that exception, but ignore that attribute. To retrieve outline information, you need to pass an object conforming to the PointPen protocol as the 'pointPen' argument. This argument may be None if you don't need the outline data. The formatVersions optional argument define the GLIF format versions that are allowed to be read. The type is Optional[Iterable[tuple[int, int], int]]. It can contain either integers (for the major versions to be allowed, with minor digits defaulting to 0), or tuples of integers to specify both (major, minor) versions. By default when formatVersions is None all the GLIF format versions currently defined are allowed to be read. ``validate`` will validate the read data. It is set to ``True`` by default. Nz9None of the requested GLIF formatVersions are supported: r)rr3r<rrrGrpr) rrr`rrrvalidFormatVersionsinvalidFormatVersionsrrs rAr,r,sp w ' 'D  0 0 2 2 69UUCEE2 7 7A 7 6q:K L L $'' 6666 - - -%))!,,,,, -# &!&&   * s A88BBrOptional[Callable[[Any], None]]writerrOptional[FormatVersion]rc t|t}n#t$rddlm}|dwxYw|r$t |t std|r"t|dkrtdtd|fdt|j fg}|j dkrt|j |d<tjd |}t} t!|||t#|d d rt%|||t#|d d rt'||||j d kr"t#|dd rt)||||j d kr#t#|dd rt+||| |t#|dd } |j d kr| rt-||| ||ftj|d} t1| | |} || |j dkr| rt3| | |t| sd| _t#|dd rt7|||tj|ddd} | S)z>Return .glif data for a glyph as a UTF-8 encoded bytes string.rrz2Unsupported GLIF format version: {formatVersion!r}z)The glyph name is not properly formatted.zThe glyph name is empty.rformat formatMinorglyphrNnoter5image guidelinesanchorsoutline) identifiersrr4 rzUTF-8T)encodingxml_declaration pretty_print)rr3rprqrrsrUrrrreprrminorr Elementr _writeAdvancer_writeUnicodes _writeNote _writeImage_writeGuidelines _writeAnchors SubElement GLIFPointPen_writeAnchorsFormat1r _writeLibtostring)rTrrrrrr glyphAttrsrootr"r r!r[rs rArr s .}>OPP    AAAAAA## @    H 9c22HFGGG7C NNa''5666 ) xm.A)B)BCDJa$()<$=$= =! =* - -DEEK+tX...{J--4{D(333{FD))0;h///aGK$$G$GKx000aGKt$L$LdKBBBk9d33GaGk4h???!"4337 hOOOs  ! # # # gx 8 8 87|| "!GL{E4((/+tX... > w4   D Ks4cTt|||||}|dS)a Return .glif data for a glyph as a string. The XML declaration's encoding is always set to "UTF-8". The 'glyphObject' argument can be any kind of object (even None); the writeGlyphToString() method will attempt to get the following attributes from it: width the advance width of the glyph height the advance height of the glyph unicodes a list of unicode values for this glyph note a string lib a dictionary containing custom data image a dictionary containing image data guidelines a list of guideline data dictionaries anchors a list of anchor data dictionaries All attributes are optional: if 'glyphObject' doesn't have the attribute, it will simply be skipped. To write outline data to the .glif file, writeGlyphToString() needs a function (any callable object actually) that will take one argument: an object that conforms to the PointPen protocol. The function will be called by writeGlyphToString(); it has to call the proper PointPen methods to transfer the outline to the .glif file. The GLIF format version can be specified with the formatVersion argument. This accepts either a tuple of integers for (major, minor), or a single integer for the major digit only (with minor digit implied as 0). By default when formatVesion is None the latest GLIF format version will be used; currently it's 2.0, which is equivalent to formatVersion=(2, 0). An UnsupportedGLIFFormat exception is raised if the requested UFO formatVersion is not supported. ``validate`` will validate the written data. It is set to ``True`` by default. )rrrrutf-8)rdecode)rTrrrrrs rAr-r-Ps<f %#    D ;;w  rBrelementr"c pt|dd}|.|r$t|tstd|dkrd}t|dd}|.|r$t|tstd|dkrd}|G|Et j|dt dt|fdt|fgdS|3t j|dtt|dS|3t j|dtt|dSdS) Nwidthz$width attribute must be int or floatrheightz%height attribute must be int or floatadvance)r<)r=) rrsrrr r0rr'r)rr:rr<r=s rAr*r*sd K$ / /E   GJuk:: GEFF F A::E [(D 1 1F   HJv{;; HFGG G Q;;F V/    (DLL1GT%[[3IJ K K       )TU -D-D-DEEEEE   )Tf-F-F-FGGGGG  rBcTt|dg}|rt|tr|g}t}|D]k}|r$t|tst d||vr-||d|z}t j|dt|ldS)Nrzunicode values must be intz%04Xunicode)hex) rrsrrrrGr r0r)rr:rrseencodehexCodes rAr+r+s{J33HJx--: 55D@@  =JtS11 =;<< < 4<<  4- )Tg->->->????@@rBct|dd}|r$t|tstdt|tr8|}d|zdz}|t j|d_dSdS)Nrznote attribute must be str )rrsrUrstripr r0r)rr:rrs rAr,r,s ; - -D9 4--97888$6zz||d{T!15&))...66rBczt|dd}|dS|rt|stdtd|dfg}tD]3\}}|||}||krt |||<4|d}|||d<tj|d|dS)NrzMimage attribute must be a dict or dict-like object with the proper structure.rcolor) rrrr_transformationInforr'r r0) rr:rrattrsrr>rrIs rAr-r-s K$ / /E } u--  [    *eJ&789 : :E,&& g $(( G  u++E$K IIg  E g Wgu-----rBr"set[str]ct|dg}|rt|std|D]#}t}|d}|t ||d<|d}|t ||d<|d} | t | |d<|d} | | |d<|d} | | |d<|d} | 2|r| |vrtd | z| |d<|| tj|d |%dS) Nrz8guidelines attribute does not have the proper structure.xyanglerrI identifier"identifier used more than once: %s guideline) rrrrrr'rGr r0) rr:r"rrrSrKrNrOrPrrIrQs rAr.r.slB77JW+J77WUVVV66   MM#   =aE#J MM#   =aE#J g&&  !%[[E'N}}V$$   E&M g&&  "E'N]]<00  ! VJ+55"#G*#TUUU",E,  OOJ ' ' ' +u5555/66rBr[r cx|rt|std|D]}i}|d}t||d<|d}t||d<|d}|||d<||||fd||dS)N5anchors attribute does not have the proper structure.rNrOrmove) segmentTyper)rrr'r beginPathaddPointendPath)r[r ranchorrKrNrOrs rAr2r2sT(11TRSSS   3K!WWc 3K!WWc zz&!!   E&M  aVd ;;;   rBc$t|dg}|rt|std|D]}t}|d}t ||d<|d}t ||d<|d} | | |d<|d} | | |d<|d} | 2|r| |vrtd| z| |d<|| tj|d |dS) Nr rUrNrOrrIrQrRr[) rrrrr'rrGr r0) rr:r"rr r[rKrNrOrrIrQs rAr/r/sB k9b11GT(11TRSSS33  3K!WWc 3K!WWc zz&!!   E&M 7##  "E'NZZ --  ! VJ+55"#G*#TUUU",E,  OOJ ' ' ' (E2222%33rBc>t|dd}|sdS|r#t|\}}|st|t|tst |}t j|d}tj|d |dS)Nrr5) indent_level) rrrrsrr totreer r0append)rr:rrvalidmessagers rAr3r3"s +ud + +C (*3//w (w'' ' c4 3ii!,,,A We$$++A.....rB)r~valueValidator)rIrrrc:|tvrdSt|}|d}|d}|d}t|sJ| |||}n#|tkr |||}n ||}|S)a This performs very basic validation of the value for attribute following the UFO 3 fontinfo.plist specification. The results of this should not be interpretted as *correct* for the font that they are part of. This merely indicates that the value is of the proper type and, where the specification defines a set range of possible values for an attribute, that the value is in the accepted range. Fr~rc valueOptions)rrcallabler)rrdataValidationDict valueType validatorre isValidValues rA*validateLayerInfoVersion3ValueForAttributerk<s ---u3D9"&&v..I"&&'788I%)).99L I    y 55  , , ,$9UI66LL$9U++L rBrdict[str, Any]c|D]H\}}|tvrtd|zt||}|std|d|dI|S)a This performs very basic validation of the value for infoData following the UFO 3 layerinfo.plist specification. The results of this should not be interpretted as *correct* for the font that they are part of. This merely indicates that the values are of the proper type and, where the specification defines a set range of possible values for an attribute, that the value is in the accepted range. zUnknown attribute %s.zInvalid value for attribute z (z).)rrrrk)rrrrjs rArrYs ~~''SS e 1 1 16=>> >A$NN  SQdQQeQQQRR R S OrBaFileUnion[str, bytes, int]c\tjr*tj|tjd}ntj|}|}|jdkrt d|jr,|jdkrt d|S)NTremove_commentsparserr#The GLIF is not properly formatted.Invalid GLIF structure.) r _have_lxmlparse XMLParsergetroottagrrrG)rnrr6s rA_glifTreeFromFiler}qs "{5)N)N)NOOO{5!! <<>>D x7@AAA y6TY__&&",,4555 KrBct|d} tjr*tj|tjd}ntj|}n"#t $r}t d|d}~wwxYw|jdkrt d|jr,|j d krt d |S) Nr8)r$TrqrszGLIF contains invalid XML.rrurvrw) r r rx fromstringrz Exceptionrr|rrG)rrr6etree_exceptions rArr~s 7W - - -DN   *#DQU1V1V1VWWWDD#D))D NNN788oMN x7@AAA y6TY__&&",,4555 KsA A A=(A88A=rrSet[GLIFFormatVersion]cb|d}||rtdd}|dd} tt|t|f}nh#t$r[}d|d|} |rddlm} | | |t}t d| |Yd}~nd}~wwxYw|r||vrtd | t|} n#t$rt|wxYw| |||||j dS) Nrz#Unspecified format version in GLIF.rrzUnsupported GLIF format: rrz_%s. Assuming the latest supported version (%s). Some data may be skipped or parsed incorrectly.zForbidden GLIF format version: )rrr`rr)rrr3rrprqrr>r1warning_READ_GLYPH_FROM_TREE_FUNCSrNotImplementedErrorr() rrr`rrformatVersionMajorformatVersionMinorrrmsgrreadGlyphFromTrees rArrs(++!  FDEE E-33 ) # $ $c*<&=&= >              4 E E E E E E'',,! 3)1133  >            $PM77N]NNOOO17 F 111!-0001 !' s%+A.. C8ACC/ C==DFkwargsc t|||g}dx}x}x}} |D]} | jdkrq|rZ|rtd| jrtd| jr,| jdkrtdd}t ||| ||| jdkr&|r|rtd d}t|| | jd kro| d } | td  t| d } | |vr| | #t$rtdwxYw| jdkr'|r| rtdd} t|| _| jdkr(|r|rtdd}t|| |td| z|rt|d|dSdS)NFr!*The outline element occurs more than once.0The outline element contains unknown attributes.rvInvalid outline structure.Tr>*The advance element occurs more than once.r@rA8A unicode element is missing its required hex attribute.3Illegal value for hex attribute of unicode element.r'The note element occurs more than once.r&The lib element occurs more than once.Unknown element in GLIF: %sr) _readNamer|rattribrrGbuildOutlineFormat1 _readAdvancerrr`rp _readNote_readLib_relaxedSetattr) rrr`rrrhaveSeenAdvancehaveSeenOutline haveSeenLib haveSeenNoter:rs rA_readGlyphFromTreeFormat1rsk4***HEJJOJoJ l/H/H ;) # # E"U&'STTT>&J<EGL$6$6$8$8B$>$>&'CDDD"O  Xw I I I I    [I % % QO Q"#OPPP"O g . . . . [I % % E""Ay"N 2JJH$$OOA&&&   "I [F " " NL N"#LMMML k7 + + + + [E ! ! MK M"#KLLLK ['8 4 4 4 4rr@rArrrrSz&Unknown children in guideline element.)rNrOrPr[z#Unknown children in anchor element.rNrOrz(The image element occurs more than once.z"Unknown children in image element.rrrrrrz(The guidelines are improperly formatted.rz%The anchors are improperly formatted.r )rrr|rrrrGbuildOutlineFormat2rrrr`rprr_number _readImagerrrrr)rrr`rrrrr r haveSeenImagerrrr"r:rrrs rA_readGlyphFromTreeFormat2rsk4***HJG Omo l EEKJHJH ;) # # E"U&'STTT>&J<EGL$6$6$8$8B$>$>&'CDDD"O##7K   [I % % QO Q"#OPPP"O g . . . . [I % % E""Ay"N 2JJH$$OOA&&&   "I [K ' ' MCLL M"#KLLL'.))F+ 9 96>>#*6$<#8#8F4L   f % % % % [H $ $ JCLL J"#HIII'.))F" 9 97>))#*6$<#8#8F4L NN6 " " " " [G # # M S&'QRRRw<<M&'KLLL M {GX 6 6 6 6 [F " " NL N"#LMMML k7 + + + + [E ! ! MK M"#KLLLK ['8 4 4 4 4>>9  H,WkBB HFGG G Y8888899s )EEz+dict[GLIFFormatVersion, Callable[..., Any]]rr6c|d}|r|std|r|t|d|dSdSdS)NrzEmpty glyph name in GLIF.)rrr)rr6rrTs rArrvsf  I8 867778[, VY7777788,,rBr>ct|dd}t|d|t|dd}t|d|dS)Nr<rr=)rrr)rr>r<r=s rArr~sb GKK++ , ,EK%000 W[[1-- . .FK622222rBrc|jdS|jd}dd|D}t|d|dS)NrFc3fK|],}||V-dSr:)rG)rlines rA z_readNote..s7DDdtzz||DTZZ\\DDDDDDrBr)rsplitjoinr)rrliness rArrsZ y IOOD ! !E 99DDeDDD D DDK.....rBrct|dksJ|d}tj|}|r#t|\}}|st |t |d|dS)Nr4rr)rr fromtreerrr)rrrchildplistrarbs rArrsu s88q==== FE  e $ $E(*511w (w'' 'K.....rBrct|j}tD]-\}}|||}t |||<.|rt |st dt|d|dS)Nz,The image element is not properly formatted.r)rrrJrrrrr)rrr imageDatarr>rs rArrsU\""I,)) g dG,,!%.. $Ky11KIJJJK)44444rBrQcontourAttributesFormat2>rzxScaleyScalexOffsetxyScaleyOffsetyxScalecomponentAttributesFormat1componentAttributesFormat2>rNrOrr~smoothpointAttributesFormat1pointAttributesFormat2noyespointSmoothOptions>rrVcurveqcurveoffcurvepointTypeOptionsr!Iterable[ElementType]cg}|D]}|jdkrbt|dkr;|d}|jdkr(t||}|||[|t |||o|jdkr|t |||t d|z|5|r5|rt|st dt|d|dSdSdS) Ncontourr4rpoint component&Unknown element in outline element: %sz*GLIF 1 anchors are not properly formatted.r ) r|r_buildAnchorFormat1r`_buildOutlineContourFormat1_buildOutlineComponentFormat1rrr)rr[r!rr r:rr[s rArrs# GSS ;) # #7||q   9''0AAF)v... +C(CCC [K ' '-c7HEEEG'QRR R7  M,W55 MKLL L Y88888rBrOptional[dict[str, Any]]c~|ddkrdS|d}|dS|d}|d}|r|td|J|r|td|Jt|}t|}t|||}|S) Nr~rVrrNrOz1Required x attribute is missing in point element.z1Required y attribute is missing in point element.)rNrOr)rrrr)rrrrNrOr[s rArrs yyF""t 99V  D |t #A #APAINOOO ===PAINOOO === A A A & & &F MrBrrc|r|jrtd|t|r(t |t d|}t |||dS)Nz&Unknown attributes in contour element.T)openContourOffCurveLeniencyr)rrrXr"_validateAndMassagePointStructuresr_buildOutlinePointsFormat1rZ)r[rrmassageds rArrsEGNECDDDMMOOO 7||25  "(,     #3111KKMMMMMrBlist[dict[str, Any]]c|D]E}|d}|d}|d}|d}|d}|||f|||FdS)NrNrOrWrrrWrr)rY)r[rrrNrOrWrrs rArrspPP #J #JM* xV} aVV$ OOOO PPrBrc |rUtrtdjD]}|tvrtd|zd}|r|td|Jt fdtD}tt ttttttf|}| ||dS)N,Unknown child elements of component element.*Unknown attribute in component element: %srz3The base attribute is not defined in the component.c3fK|]+\}}t|p|V,dSr:rrrrr>rs rArz0_buildOutlineComponentFormat1..Q4AD' d##.w//rB) rrrrrrtuplerJr float addComponent)r[rrr baseGlyphNametransformations ` rArrs'X y>> OMNN N$))++ X XD555"#ORV#VWWW6MM&))MRM)PQQQ  $ $ $EXN eUE5%67N]N33333rBc|D]T}|jdkrt|||| |jdkrt||||>td|jzdS)Nrrr)r|_buildOutlineContourFormat2_buildOutlineComponentFormat2r)rr[r!r"rr:s rArr sWW ;) # # 'Wk8 L L L L [K ' ' )#w X N N N NG'+UVV V WWrBc||r7|jD]}|tvrtd|z|d}|N|r7||vrtd|zt |std|z|| ||n9#t$r,|tdtYnwxYwt|r)t|t|}t|||||dS)Nz(Unknown attribute in contour element: %srQ)The identifier %s is used more than once.z'The contour identifier %s is not valid.rQzbThe beginPath method needs an identifier kwarg. The contour's identifier value has been discarded.)r)rrrrrrrGrXr}r DeprecationWarningrrr_buildOutlinePointsFormat2rZ)r[rr"rrrQrs rArr0sVN'')) V VD333"#MPT#TUUU4\**J  [(("?*L'z22 "= J  ###   ,,,,      p        7||I5 +h    #3+xHHHKKMMMMMs B773C-,C-c|D]}|d}|d}|d}|d}|d} |d} | N|r7| |vrtd| zt| std| z||  |||f||| | #t $r3|||f||| t d tYwxYwdS) NrNrOrWrrrQrThe identifier %s is not valid.)rWrrrQrz_The addPoint method needs an identifier kwarg. The point's identifier value has been discarded.)rrrrGrYr}r r) r[rr"rrrNrOrWrrrQs rArrSs^  #J #JM* xV}YY|,,  ! W,,&CjP+:66W&'H:'UVVV OOJ ' ' '  LLA'%         LL!Q[dL S S S q"      1sB00:C-,C-c D|rUtrtdjD]}|tvrtd|zd}|r|td|Jt fdtD}tt ttttttf|}d}|P|r9||vrtd|z|r!t|std|z| | | ||| dS#t$r/| ||td tYdSwxYw) Nrrrzrc3fK|]+\}}t|p|V,dSr:rrs rArz0_buildOutlineComponentFormat2..rrBrQrrrzgThe addComponent method needs an identifier kwarg. The component's identifier value has been discarded.)rrrrrrrrJr rrrGrr}r r)r[rr"rrrrrQs ` rArrysX y>> OMNN N$))++ X XD555"#ORV#VWWW6MM&))MRM)PQQQ  $ $ $EXN eUE5%67N|,,J  S[(("?*L S 3J ? ? S"#Dz#QRRR ###  :NNNNN     777 u        s E&&5FFc2t|sdSd}d}g}t|D]\}}|jdkrtd|jzt |j} || |rK| D]} | |vrtd| zt|rtddD]A} t| | | | <#t$r} td| d| d} ~ wwxYw| d d } |r| tvrtd | z| d krd} | | d <| d }n|}|r| dkr|dkrtd| dd} |r| | tvrtd| z| dk} | | d<|r| r| tdd|jvrd| d<|rA|dd dkr/d}t|D]} | d |dz }|r |d| }|r|r~||t|dz |z }|D]d} | d }||dz }|rN|dkrtd|dkrtd|dkr|dkrtdn|dkrn d}e|S)NFrz.Unknown child element (%s) of contour element.z&Unknown attribute in point element: %sz(Unknown child elements in point element.rz Required z' attribute is missing in point element.r~rzUnknown point type: %srWTrVrz9A move point occurs after the first point in the contour.rrzUnknown point smooth value: %srz*smooth attribute set in an offcurve point.rr4zmove can not have an offcurve.rzline can not have an offcurve.rr5z%Too many offcurves defined for curve.r)r enumerater|rrrr`rrrpoprrrreversed)rpointAttributesrrlastOnCurvePointhaveOffCurvePointrindexr:rrr pointTypercountoffCurvesCountrWs rArrs w<<H#G,,4!4!w ;' ! !@7;N W^$$  O  X X..&'ORV'VWWW/7|| O"#MNNN  D %eDk22d    "MMMM  IIfj11  E )9997)CDD D  " "I(m   $  $    V++ K 8T**  N*///"#Cf#LMMM5 h  M M9#4KLL L  ' ' E&M" - A;} % / /E!(++  '/QJEE -#GeVG,#%#*:*FX*-== # #E .K"!#!"f,,*+KLLL$..*+KLLL$//)A--"./V"W"WW.$00!" Os C## D-DDobjectcL t|||dS#t$rYdSwxYwr:)rr)rrrs rArrsA e$$$$$      s  ##sUnion[str, int, float]r'c t|}|S#t$rYnwxYw t|}|S#t$rtd|zwxYw)a Given a numeric string, return an integer or a float, whichever the string indicates. _number("1") will return the integer 1, _number("1.0") will return the float 1.0. >>> _number("1") 1 >>> _number("1.0") 1.0 >>> _number("a") # doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): ... GlifLibError: Could not convert a to an int or float. z(Could not convert %s to an int or float.)rrprr)rns rArrs !ff      K !HH KKKEIJJJKs  5AceZdZdS) _DoneParsingN)rKrLrMrerBrAr r 9sDrBr c.eZdZddZddZdd Zdd Zd S) _BaseParserr8rWcg|_dSr:) _elementStackrs rArZz_BaseParser.__init__>s(*rBrrcddlm}|}|j|_|j|_||ddS)Nr) ParserCreateT)xml.parsers.expatrstartElementHandlerStartElementHandlerendElementHandlerEndElementHandlerParse)rYrrrts rAryz_BaseParser.parseAsO222222%)%="#'#9  T4     rBrrUrKrc:|j|dSr:)rr`)rYrrKs rArz_BaseParser.startElementHandlerIs !!$'''''rBcJ|jd}||ksJdS)N)rr)rYrothers rArz_BaseParser.endElementHandlerLs)"&&r**}}}}}}rBNr)rr)rrUrKrr8rWrrUr8rW)rKrLrMrZryrrrerBrAr r =sd++++!!!!((((rBr glif list[int]cVt}|||jS)z0 Get a list of unicodes listed in glif. )_FetchUnicodesParserryrrrts rArrTs)" # #F LL ?rBc,eZdZd fd Zd fd ZxZS) rr8rWcVg|_tdSr:)rr=rZrYr@s rArZz_FetchUnicodesParser.__init__^s&#%  rBrrUrKrc@|dkrt|jrm|jddkr\|d}|E t|d}||jvr|j|n#t $rYnwxYwt ||dS)Nr@rrrAr)rrrrr`rpr=r)rYrrKrintValuer@s rArz(_FetchUnicodesParser.startElementHandlerbs I  " "2&'11IIe$$E "5"~~Ht}44 ,,X666!D ##D%00000s3A,, A98A9rrrUrKrr8rWrKrLrMrZrrPrQs@rArr]s[1111111111rBr Optional[str]czt} ||n#t$rYnwxYw|jS)z1 The image file name (if any) from glif. )_FetchImageFileNameParserryr rr s rArrvsQ' ( (F  T      ? & 33c,eZdZd fd Zd fd ZxZS) r*r8rWcVd|_tdSr:)rr=rZr#s rArZz"_FetchImageFileNameParser.__init__s&'+  rBrrUrKrc|dkr9|jr2|jddkr!|d|_tt ||dS)Nrrrr)rrrr r=r)rYrrKr@s rArz-_FetchImageFileNameParser.startElementHandlers_ 7??t1?d6H6LPW6W6W!IIj11DM  ##D%00000rBrr&r'rQs@rAr*r*s[1111111111rBr*ct} ||n#t$rYnwxYwt|jS)z= Get a list of component base glyphs listed in glif. )_FetchComponentBasesParserryr rbasesr s rArrsY( ) )F  T        r+c8eZdZd fd Zd fd Zd fd ZxZS) r0r8rWcVg|_tdSr:)r1r=rZr#s rArZz#_FetchComponentBasesParser.__init__s& "  rBrrUrKrc|dkrI|jrB|jddkr1|d}||j|t ||dS)Nrrr!rz)rrr1r`r=r)rYrrKrzr@s rArz._FetchComponentBasesParser.startElementHandlersy K  " "2&)3399V$$D !!$''' ##D%00000rBcd|dkrtt|dS)Nr!)r r=r)rYrr@s rArz,_FetchComponentBasesParser.endElementHandlers2 9    !!$'''''rBrr&r)rKrLrMrZrrrPrQs@rAr0r0sy 1 1 1 1 1 1((((((((((rBr0))rr4)rr)rr)rr4)rr)rrzlist[tuple[str, int]]rJcBeZdZdZ dddZddZdZ ddZddZdS)r1zb Helper class using the PointPen protocol to write the part of .glif files. NTr:r"rrr"r rr]r8rWc|t}t|t|_||_||_d|_d|_g|_||_ dS)Nr) rrr3rr"r!rprevOffCurveCountprevPointTypesr)rYr:rr"rs rArZzGLIFPointPen.__init__sW  %%K3MCTUU&  !")+  rBc Xt}|r|jjdkrb|jr<||jvrt d|zt |st d|z||d<|j|tj |j d||_ d|_ dS)Nr5rR%identifier not formatted properly: %srQrr) rrrrr"rrrGr r0r!rr8)rYrQrrKs rArXzGLIFPointPen.beginPaths   !d&8&>!&C&C} !111&} OOOE%e[99O*+MNNNObeE#JbeE#J * $ $K = Sf$$)<$"V///'0'+z99"#E #STTTg%%$*@1*D*D"#QRRR  "'E&MM$K * $ $  " "a ' " " "%&D " "";///  $} M !:!:"#KLLL#E(O   E&M  !d&8&>!&C&C} !111&rs rArzGLIFPointPen.addComponent2s?fi0122&)*=~&N&N * * "OT7U} QZ{%C%C Q"#OPPP"5kkd  !d&8&>!&C&C} !111&r"r8rW)rrrr"r8rW)rrrr"rr]r8rW)rrrr"rr]r8rW) rrr[rr!rrr]r8rW)rr"rr]r8r)r[rrr"rr]r8rW)r[rrrr8rW)r[rrr"rr]r8rW) rrr[rr!rr"rLrr]r8rW) r[rrr"r"rLrr]r8rW) r[rrrr"rLrr]r8rW) r[rrr"r"rLrr]r8rW)FT)rrrrUrrr8rW)rrr8r')rrr8r)rrr8r()rrr8r/)rN __future__rlogging collectionsrtypingrrrrr warningsr fontTools.misc.filesystemmiscrrtfontTools.miscr r fontTools.misc.textToolsr fontTools.pens.pointPenrrfontTools.ufoLibrrrqrfontTools.ufoLib.filenamesrfontTools.ufoLib.utilsrrrfontTools.ufoLib.validatorsrrrrrrrcollections.abcrrr r!fontTools.annotationsr"r#r$r%r&r'r(r)fontTools.misc.filesystem._baser*r0__annotations__ getLoggerrKr1rrr3rSr+r.r,rr-r*r+r,r-r.r2r/r3rrUrrkrr}rr<rrrrErHrrrrrrrrrrrrrrrrrrrrrrrrrrr r rrrr*rr0rJr1doctesttestmodrerBrArYsz    #"""""######<<<<<<<<<<<<<<&&&&&&&&&********,,,,,,GGGGGGGG99999999000000999999 37777777777                    322222#"8,,,,,,%&#####)###L@@@@@@@@>KKKKKzKKKf U U U U&"&"%) SSSSSp"&6: -1 @@@@@J"&6:-1 : : : : : zHHHH2 @ @ @ @6666....(6666@"3333< / / / /*Ts> : : : 4T*> ? ? ? :0    &"&+/->-Q-Q-S-S 22222n"&+/ >;>;>;>;>;F"&+/ h9h9h9h9h9X "; ";L 88883333////////5555'3^3333((((B\N'RRRRR#G#G#GGGGG#9\N#JJJJJ $e},,,,LLLLLLL 9999:(" P P P P44442 W W W W    F####L$ $ $ $ VKOeeeeZ    KKKKD     9   .11111;1112     1 1 1 1 1 1 1 1    ((((((((4...C;C;C;C;C;#C;C;C;L zNNNGOrB