L idZddlmZddlZddlZddlZddlZddlZddlZddl m Z m Z ddl m Z ddlmZmZmZmZmZmZmZmZddlmZddlmZdd lmZdd lmZmZgd Z d Z!e!d zZ"dZ#dZ$Gdde%Z&Gdde'Z(Gdde(Z)Gdde)Z*Gdde)Z+dZ,dZ-dZ.ee/ee0ee0e0fffZ1ee/e0fZ2Gdde)Z3Gdd e)Z4d!Z5Gd"d#e)Z6Gd$d%e6Z7Gd&d'e6Z8Gd(d)e)Z9Gd*d+e)Z:Gd,d-e)Z;Gd.d/e)Z<Gd0d1e)Z=Gd2d3e'Z>Gd4d5eZ?Gd6d7ee(Z@d9d8ZAy):zA designSpaceDocument - Read and write designspace files ) annotationsN)BytesIOStringIO)indent)AnyDictListMutableMappingOptionalTupleUnioncast)etree)plistlib)LogMixin)tobytestostr)AxisDescriptorAxisLabelDescriptorAxisMappingDescriptor BaseDocReader BaseDocWriterDesignSpaceDocumentDesignSpaceDocumentErrorDiscreteAxisDescriptorInstanceDescriptorLocationLabelDescriptorRangeAxisSubsetDescriptorRuleDescriptorSourceDescriptorValueAxisSubsetDescriptorVariableFontDescriptorz&{http://www.w3.org/XML/1998/namespace}langctj|jtjj }|j drd|z}|S|j drd|z}|S)z O  (? Oc0fd}fd}t||S)zBGenerate a propery that holds a path always using forward slashes.ct|SN)getattr)self private_names r.getterz"posixpath_property..getter@st\**r0c:| t|}t||yr3)r/setattr)r5valuer6s r.setterz"posixpath_property..setterDs  %LElE*r0)property)r6r7r;s` r.posixpath_propertyr==s++ FF ##r0ceZdZddZdZy)rNc ||_||_yr3)msgobj)r5r@rAs r.__init__z!DesignSpaceDocumentError.__init__Nsr0clt|j|jd|jzzSdzS)Nz: %r)strr@rAr5s r.__str__z DesignSpaceDocumentError.__str__Rs/488}TXX5I 1RRrRRr0r3)__name__ __module__ __qualname__rBrGr0r.rrMs Sr0rceZdZdZy) AsDictMixinc6i}|jjD]t\}}|jdrt|dr|j }n;t |t r+|Dcgc] }t|dr|j n|"}}|||<v|Scc}w)N_asdict)__dict__itemsr,hasattrrP isinstancelist)r5dattrr:vs r.rPzAsDictMixin.asdictWs ==..0 KD%s#uh' E4(LQRqwq(';BRRAdG Ss&%BN)rHrIrJrPrKr0r.rMrMVs r0rMceZdZdZdZdZy)SimpleDescriptorz$Containers for a bunch of attributesc |jD]} t||t||k(sJ y#t$r&td|t||dt||YPwxYw)Nzfailed attributez!=)_attrsr4AssertionErrorprint)r5otherrWs r.comparezSimpleDescriptor.compareislKK D tT*geT.BBBB " &D$'E4(  s/,AAc |jDcgc]}|dtt||d}}tdj |d}|j j d|dScc}w)N=,  z( z ))r\reprr4rr' __class__rH)r5aattrss r.__repr__zSimpleDescriptor.__repr__wsl;?;;GaA3aWT1-./q1GGtyy'0..))*#eWC88Hs"A*N)rHrIrJ__doc__r`rjrKr0r.rZrZds. 9r0rZceZdZdZdZgdZedZedZddddddddddddddddddd Z e d Z e jdd Z dd Z dd ZddZy)r uSimple container for data related to the source .. code:: python doc = DesignSpaceDocument() s1 = SourceDescriptor() s1.path = masterPath1 s1.name = "master.ufo1" s1.font = defcon.Font("master.ufo1") s1.location = dict(weight=0) s1.familyName = "MasterFamilyName" s1.styleName = "MasterStyleNameOne" s1.localisedFamilyName = dict(fr="Caractère") s1.mutedGlyphNames.append("A") s1.mutedGlyphNames.append("Z") doc.addSource(s1) source)filenamer*name layerNamelocationcopyLib copyGroups copyFeatures muteKerningmuteInfomutedGlyphNames familyName styleNamelocalisedFamilyName _filename_pathNF)rnr*fontrorqdesignLocationrprxryrzrrcopyInforsrtrurvrwc"||_ ||_ ||_ ||_ ||n|xsi|_ ||_ ||_ | |_ | xsi|_ | |_ | |_ | |_ ||_ ||_ ||_ |xsg|_yr3)rnr*r}ror~rprxryrzrrrrsrtrurvrw)r5rnr*r}rorqr~rprxryrzrrrrsrtrurvrws r.rBzSourceDescriptor.__init__s*!   :    -8Nhn"  # % # $7#<"    !  % ) ' !  /4" r0c|jS)zdict. Axis values for this source, in design space coordinates. MutatorMath + varLib. .. deprecated:: 5.0 Use the more explicit alias for this property :attr:`designLocation`. r~rFs r.rqzSourceDescriptor.location0"""r0c|xsi|_yr3rr5rqs r.rqzSourceDescriptor.location;&n"r0c4t||j|<y)zNSetter for :attr:`localisedFamilyName` .. versionadded:: 5.0 Nrrzr5rx languageCodes r. setFamilyNamezSourceDescriptor.setFamilyName?s 27z1B  .r0c8|jj|S)zNGetter for :attr:`localisedFamilyName` .. versionadded:: 5.0 rzgetr5rs r. getFamilyNamezSourceDescriptor.getFamilyNameFs ''++L99r0ci}|jD]i}|j|jvr'|j|j||j<B|j|j||j<k|S)zGet the complete design location of this source, from its :attr:`designLocation` and the document's axis defaults. .. versionadded:: 5.0 )axesror~ map_forwarddefault)r5docresultaxiss r.getFullDesignLocationz&SourceDescriptor.getFullDesignLocationMsq &(HH CDyyD///$($7$7 $Btyy!$($4$4T\\$Btyy!  C  r0)rqzOptional[SimpleLocationDict]enr'DesignSpaceDocument'returnSimpleLocationDict)rHrIrJrkflavorr\r=rnr*rBr<rqr;rrrrKr0r.r r }s&FF""+.H g &D     'H T##__--C: r0r c(eZdZdZgdZdddddZy)raRepresents the rule descriptor element: a set of glyph substitutions to trigger conditionally in some parts of the designspace. .. code:: python r1 = RuleDescriptor() r1.name = "unique.rule.name" r1.conditionSets.append([dict(name="weight", minimum=-10, maximum=10), dict(...)]) r1.conditionSets.append([dict(...), dict(...)]) r1.subs.append(("a", "a.alt")) .. code:: xml ro conditionSetssubsNcB||_ |xsg|_ |xsg|_yr3r)r5rorrs r.rBzRuleDescriptor.__init__zs0 Y*0b JB  r0rHrIrJrkr\rBrKr0r.rr\s6/F#4d r0rc@tfd|jDS)zJReturn True if any of the rule's conditionsets matches the given location.c36K|]}t|ywr3)evaluateConditions).0crqs r. zevaluateRule..sK1!!X.Ks)anyr)rulerqs `r. evaluateRulers K8J8JK KKr0c|D]X}||d}|jd ||dkDs%y|jd |d|kDsAy|d|cxkr |dkrUyyy)zReturn True if all the conditions matches the given location. - If a condition has no minimum, check for < maximum. - If a condition has no maximum, check for > minimum. rominimummaximumFT)r) conditionsrqcdr:s r.rrs  F$ 66)  $r)}$ VVI  &)}u$I%82i=89  r0cg}|D]^}t||s|D]F}d}|jD]\}}||k(s d}n|r|j6|j|H|}g}`|S)zApply these rules at this location to these glyphnames. Return a new list of glyphNames with substitutions applied. - rule order matters FT)rrappend) rulesrq glyphNamesnewNamesrroswaprhbs r. processRulesrsH  h '" * IIDAqqy#OOA&OOD) *"JH  r0c*eZdZdZddgZddddddZy)raRepresents the axis mapping element: mapping an input location to an output location in the designspace. .. code:: python m1 = AxisMappingDescriptor() m1.inputLocation = {"weight": 900, "width": 150} m1.outputLocation = {"weight": 870} .. code:: xml inputLocationoutputLocationNrr descriptiongroupDescriptioncR|xsi|_ |xsi|_ ||_ ||_yr3r)r5rrrrs r.rBzAxisMappingDescriptor.__init__sI2?1D" 3A2FB ' !1 r0rrKr0r.rrs'0/ 0F  # r0rceZdZdZdZdZgdZedZedZ dddddddddddddddddddddd d Z e d Z e jdd Z dd ZddZddZddZddZddZddZddZdddZ ddZ ddZddZy) raSimple container for data related to the instance .. code:: python i2 = InstanceDescriptor() i2.path = instancePath2 i2.familyName = "InstanceFamilyName" i2.styleName = "InstanceStyleName" i2.name = "instance.ufo2" # anisotropic location i2.designLocation = dict(weight=500, width=(400,300)) i2.postScriptFontName = "InstancePostscriptName" i2.styleMapFamilyName = "InstanceStyleMapFamilyName" i2.styleMapStyleName = "InstanceStyleMapStyleName" i2.lib['com.coolDesignspaceApp.specimenText'] = 'Hamburgerwhatever' doc.addInstance(i2) instancer)rnr*ro locationLabelr~ userLocationrxrypostScriptFontNamestyleMapFamilyNamestyleMapStyleNamerzlocalisedStyleNamelocalisedStyleMapFamilyNamelocalisedStyleMapStyleNameglyphskerninginfolibr{r|NT)rnr*r}rorqrr~rrxryrrrrzrrrrrrrc||_ ||_ ||_ ||_ ||_ ||n|xsi|_ |xsi|_ | |_ | |_ | |_ | |_ | |_ |xsi|_ |xsi|_ |xsi|_ |xsi|_ |xsi|_ ||_ ||_ |xsi|_yr3)rnr*r}rorr~rrxryrrrrzrrrrrrr)r5rnr*r}rorqrr~rrxryrrrrzrrrrrrrs r.rBzInstanceDescriptor.__init__5sS2!        + -8Nx~2  1=0B % # #5 #5 "3 $7#<"  #5": ,G+L"( +E*J' l      9"8r0c|jS)zdict. Axis values for this instance. MutatorMath + varLib. .. deprecated:: 5.0 Use the more explicit alias for this property :attr:`designLocation`. rrFs r.rqzInstanceDescriptor.locationrr0c|xsi|_yr3rrs r.rqzInstanceDescriptor.locationrr0c4t||j|<y)z8These methods give easier access to the localised names.N)rr)r5ryrs r. setStyleNamezInstanceDescriptor.setStyleNames05i0@ -r0c8|jj|Sr3)rrrs r. getStyleNamezInstanceDescriptor.getStyleNames&&**<88r0c4t||j|<yr3rrs r.rz InstanceDescriptor.setFamilyNames16z1B  .r0c8|jj|Sr3rrs r.rz InstanceDescriptor.getFamilyNames''++L99r0c4t||j|<yr3)rr)r5rrs r.setStyleMapStyleNamez'InstanceDescriptor.setStyleMapStyleNames8=>O8P'' 5r0c8|jj|Sr3)rrrs r.getStyleMapStyleNamez'InstanceDescriptor.getStyleMapStyleNames..22<@@r0c4t||j|<yr3)rr)r5rrs r.setStyleMapFamilyNamez(InstanceDescriptor.setStyleMapFamilyNames9>?Q9R((6r0c8|jj|Sr3)rrrs r.getStyleMapFamilyNamez(InstanceDescriptor.getStyleMapFamilyNames//33LAAr0cd|_|i|_i|_y|ji|_||jvr |j|=|ji|_||jvr|j|=yy)aClear all location-related fields. Ensures that :attr:``designLocation`` and :attr:``userLocation`` are dictionaries (possibly empty if clearing everything). In order to update the location of this instance wholesale, a user should first clear all the fields, then change the field(s) for which they have data. .. code:: python instance.clearLocation() instance.designLocation = {'Weight': (34, 36.5), 'Width': 100} instance.userLocation = {'Opsz': 16} In order to update a single axis location, the user should only clear that axis, then edit the values: .. code:: python instance.clearLocation('Weight') instance.designLocation['Weight'] = (34, 36.5) Args: axisName: if provided, only clear the location for that axis. .. versionadded:: 5.0 N)rr~r)r5axisNames r. clearLocationz InstanceDescriptor.clearLocations8"  "$D  "D ""*&(#4...''1  ($&!4,,,%%h/-r0c|jy|j|j}|&td|jd|jd|S)zGet the :class:`LocationLabelDescriptor` instance that matches this instances's :attr:`locationLabel`. Raises if the named label can't be found. .. versionadded:: 5.0 NzIInstanceDescriptor.getLocationLabelDescriptor(): unknown location label `z` in instance `z`.)rgetLocationLabelrro)r5rlabels r.getLocationLabelDescriptorz-InstanceDescriptor.getLocationLabelDescriptorsf    %$$T%7%78 =*++/+=+=*>odii[XZ\  r0c|j|}||j|jSi}|jD]}|j|j vr'|j |j||j<B|j|jvr6|j|j|j||j<|j|j ||j<|S)a!Get the complete design location of this instance, by combining data from the various location fields, default axis values and mappings, and top-level location labels. The source of truth for this instance's location is determined for each axis independently by taking the first not-None field in this list: - ``locationLabel``: the location along this axis is the same as the matching STAT format 4 label. No anisotropy. - ``designLocation[axisName]``: the explicit design location along this axis, possibly anisotropic. - ``userLocation[axisName]``: the explicit user location along this axis. No anisotropy. - ``axis.default``: default axis value. No anisotropy. .. versionadded:: 5.0 )rrrrror~r)r5rrrrs r.rz(InstanceDescriptor.getFullDesignLocation3s(//4  ??5#5#56 6*,HH CDyyD///$($7$7 $Btyy!d///$($4$4T5F5Ftyy5Q$Rtyy!$($4$4T\\$Btyy!  C r0cB|j|j|S)zGet the complete user location for this instance. .. seealso:: :meth:`getFullDesignLocation` .. versionadded:: 5.0 ) map_backwardr)r5rs r.getFullUserLocationz&InstanceDescriptor.getFullUserLocationTs  : :3 ?@@r0)rqz!Optional[AnisotropicLocationDict]rr3)rz Optional[str])rrr!Optional[LocationLabelDescriptor])rrrAnisotropicLocationDictr)rHrIrJrkr_defaultLanguageCoder\r=rnr*rBr<rqr;rrrrrrrrrrrrrKr0r.rrs &FF,"+.H g &D     $(#'  /V9p##__--A9C:QASB(0T( *(( BAr0rc@dtdfdtdfdtdfdtd fd td fd }|j|vr||jSt|d kr|dd t|z zz}n|dd }|t|fS)NwghtWeightrwdthWidthopszz Optical SizeslntSlantitalItalic)weightwidthopticalslantitalic*)dictlowerlen)ronamestags r.tagForAxisNamer^s48,-$'*+DN34$'*+48,-  E zz|uTZZ\"" 4y1}SAD M**2Ah  r0c(eZdZdZdddddddddZy)AbstractAxisDescriptorrNFrro labelNameshiddenmap axisOrdering axisLabelsc||_ ||_ |xsi|_ ||_ |xsg|_ ||_ |xsg|_yr3r )r5rror r r r rs r.rBzAbstractAxisDescriptor.__init__ssr   %*   9" ) 6@5E2 r0)rHrIrJrrBrKr0r.rrps# F   8 r0rc TeZdZdZgdZddddddddddd fd ZdZdZd ZxZ S) ru/Simple container for the axis data. Add more localisations? .. code:: python a1 = AxisDescriptor() a1.minimum = 1 a1.maximum = 1000 a1.default = 400 a1.name = "weight" a1.tag = "wght" a1.labelNames['fa-IR'] = "قطر" a1.labelNames['en'] = "Wéíght" a1.map = [(1.0, 10.0), (400.0, 66.0), (1000.0, 990.0)] a1.axisOrdering = 1 a1.axisLabels = [ AxisLabelDescriptor(name="Regular", userValue=400, elidable=True) ] doc.addAxis(a1) )rrorrrr r rNF) rror rrrr r r rc `t ||||||| | ||_ ||_ ||_yNr )superrBrrr) r5rror rrrr r r rrgs r.rBzAxisDescriptor.__init__sV !%!        r0c t|j|j|j|j|j |j |j|j|j|j S)N) rror rrrr r r r) rrror rrrr r r rrFs r. serializezAxisDescriptor.serializesWLLLLLL;;**  r0c ddlm}|js|S|||jDcic]\}}|| c}}Scc}}w)z?Maps value from axis mapping's input (user) to output (design).rpiecewiseLinearMap)fontTools.varLib.modelsrr r5rXrks r.rzAxisDescriptor.map_forwards8>xxH!!txx%@tq!ad%@AA%@s < c ddlm}t|tr|d}|js|S|||jDcic]\}}|| c}}Scc}}w)z?Maps value from axis mapping's output (design) to input (user).rr)rrrTtupler rs r.rzAxisDescriptor.map_backwardsK> a !AxxH!!txx%@tq!ad%@AA%@s A ) rHrIrJrkr\rBrrr __classcell__rgs@r.rrsF, F   & P  BBr0rc LeZdZdZdZdZdddddddddd fd ZdZd ZxZ S) raContainer for discrete axis data. Use this for axes that do not interpolate. The main difference from a continuous axis is that a continuous axis has a ``minimum`` and ``maximum``, while a discrete axis has a list of ``values``. Example: an Italic axis with 2 stops, Roman and Italic, that are not compatible. The axis still allows to bind together the full font family, which is useful for the STAT table, however it can't become a variation axis in a VF. .. code:: python a2 = DiscreteAxisDescriptor() a2.values = [0, 1] a2.default = 0 a2.name = "Italic" a2.tag = "ITAL" a2.labelNames['fr'] = "Italique" a2.map = [(0, 0), (1, -11)] a2.axisOrdering = 2 a2.axisLabels = [ AxisLabelDescriptor(name="Roman", userValue=0, elidable=True) ] doc.addAxis(a2) .. versionadded:: 5.0 r)rrovaluesrr r rNF) rror r!rr r r rc Xt |||||||| ||_ |xsg|_yr)rrBrr!) r5rror r!rr r r rrgs r.rBzDiscreteAxisDescriptor.__init__;sL !%!  &  $*.i:41aqEzQ: )nextr r5r:s `r.rz"DiscreteAxisDescriptor.map_forwardas:488:EBBr0clttrdtfd|jDS)zMaps value from axis mapping's output to input. Returns value unchanged if no mapping entry is found. Note: for discrete axes, each value must have its mapping entry, if you intend that value to be mapped. rc34K|]\}}|k(s |ywr3rKr%s r.rz6DiscreteAxisDescriptor.map_backward..ur&r')rTrr(r r)s `r.rz#DiscreteAxisDescriptor.map_backwardks/ eU #!HE:488:EBBr0) rHrIrJrkrr\rBrrrrs@r.rrsC:F VF   $ LC Cr0rcHeZdZdZdZdZddddddddZd dZed d Z y) raContainer for axis label data. Analogue of OpenType's STAT data for a single axis (formats 1, 2 and 3). All values are user values. See: `OTSpec STAT Axis value table, format 1, 2, 3 `_ The STAT format of the Axis value depends on which field are filled-in, see :meth:`getFormat` .. versionadded:: 5.0 r userMinimum userValue userMaximumroelidable olderSiblinglinkedUserValuer NF)r.r0r1r2r3r c||_ ||_ ||_ ||_ ||_ ||_ ||_ |xsi|_yr3r-) r5ror/r.r0r1r2r3r s r.rBzAxisLabelDescriptor.__init__sh-86 )P,76 G&  #/ 1@44>4D" r0cP|jy|j |jyy)uDDetermine which format of STAT Axis value to use to encode this label. =========== ========= =========== =========== =============== STAT Format userValue userMinimum userMaximum linkedUserValue =========== ========= =========== =========== =============== 1 ✅ ❌ ❌ ❌ 2 ✅ ✅ ✅ ❌ 3 ✅ ❌ ❌ ✅ =========== ========= =========== =========== =============== )r3r.r0rFs r. getFormatzAxisLabelDescriptor.getFormats0    +    '4+;+;+Gr0cT|jjdxs |jSzDReturn the English name from :attr:`labelNames` or the :attr:`name`.rr rrorFs r. defaultNamezAxisLabelDescriptor.defaultName"""4(5DII5r0)rintrrE) rHrIrJrkrr\rBr9r<r=rKr0r.rrxsH F F # J"66r0rcBeZdZdZdZdZdddddZed dZd d Z y) ra@Container for location label data. Analogue of OpenType's STAT data for a free-floating location (format 4). All values are user values. See: `OTSpec STAT Axis value table, format 4 `_ .. versionadded:: 5.0 r)ror1r2rr FN)r1r2r cb||_ |xsi|_ ||_ ||_ |xsi|_yr3rorr1r2r )r5rorr1r2r s r.rBz LocationLabelDescriptor.__init__sP H0<0B '  #/ +5*: r0cT|jjdxs |jSr;r<rFs r.r=z#LocationLabelDescriptor.defaultNamer>r0c|jDcic]=}|j|jj|j|j?c}Scc}w)zGet the complete user location of this label, by combining data from the explicit user location and default axis values. .. versionadded:: 5.0 )rrorrr)r5rrs r.rz+LocationLabelDescriptor.getFullUserLocationsL  IIt((,,TYY E E   sAAr@r) rHrIrJrkrr\rBr<r=rrKr0r.rrs=F OF  D66  r0rc8eZdZdZdZdZedZdddddZy)r"aContainer for variable fonts, sub-spaces of the Designspace. Use-cases: - From a single DesignSpace with discrete axes, define 1 variable font per value on the discrete axes. Before version 5, you would have needed 1 DesignSpace per such variable font, and a lot of data duplication. - From a big variable font with many axes, define subsets of that variable font that only include some axes and freeze other axes at a given location. .. versionadded:: 5.0 variable-font)rn axisSubsetsrr{NcR||_ ||_ |xsg|_ |xsi|_yr3rornrHr)r5rornrHrs r.rBzVariableFontDescriptor.__init__!sC  &   B  .1YB=r0) rHrIrJrkrr\r=rnrBrKr0r.r"r"s) F /F!+.H)-4T>r0r"cReZdZdZdZdZej dejddZy)rzZSubset of a continuous axis to include in a variable font. .. versionadded:: 5.0 axis-subsetror. userDefaultr0N)r.rNr0cB||_ ||_ ||_ ||_yr3rM)r5ror.rNr0s r.rBz"RangeAxisSubsetDescriptor.__init__Ds9 <"- -8 #. r0) rHrIrJrkrr\mathinfrBrKr0r.rr;s+ F BF%)HH9$DHH r0rceZdZdZdZdZdZy)r!zhSingle value of a discrete or continuous axis to use in a variable font. .. versionadded:: 5.0 rLror/c"||_ ||_yr3rS)r5ror/s r.rBz"ValueAxisSubsetDescriptor.__init__cs  !*Jr0N)rHrIrJrkrr\rBrKr0r.r!r!Zs F "FKr0r!c4eZdZdZeZeZeZ e Z e Z eZeZeZeZeZeZedZedZedZedZedZddZ ddZ!d Z"dd Z#d Z$d Z%dZ&dZ' ddZ(dZ) ddZ*d d d ddZ+dZ,dZ- d dZ.d!dZ/dZ0y )"rrec"|jSr3)axisDescriptorClassclss r.getAxisDecriptorzBaseDocWriter.getAxisDecriptorz&&((r0c"|jSr3)axisMappingDescriptorClassrXs r.getAxisMappingDescriptorz&BaseDocWriter.getAxisMappingDescriptor~s--//r0c"|jSr3)sourceDescriptorClassrXs r.getSourceDescriptorz!BaseDocWriter.getSourceDescriptors((**r0c"|jSr3)instanceDescriptorClassrXs r.getInstanceDescriptorz#BaseDocWriter.getInstanceDescriptors**,,r0c"|jSr3)ruleDescriptorClassrXs r.getRuleDescriptorzBaseDocWriter.getRuleDescriptorr[r0c~||_||_|j|_t j d|_y)N designspace)r*documentObject_getEffectiveFormatTupleeffectiveFormatTupleETElementroot)r5 documentPathrjs r.rBzBaseDocWriter.__init__s2  ,$($A$A$C!JJ}- r0c djd|jD|jjd<|jj s,|jj s|jjitjd}|jj#|jj|jd<|jj||jj D]}|j||jj rd}t}|jj D]}t|dd|k7rb|-|jjddj|t|dd}tjd }|||jd <|j|||-|jjddj||jj r]tjd } |jj D]} |j#| | |jj| |jj$rMt|jd d rddi} ni} |jjtjd| |jj$D]} |j'| |jj(r.|jjtjd|jj(D]} |j+| |jj,r]tjd}|jj,D]}|j/|||jj||jj0r.|jjtjd|jj0D]}|j3||jj4r1|j7|j|jj4dtj8|j}|j;|j<|d||y)N.c32K|]}t|ywr3)rEris r.rz&BaseDocWriter.write..s-Xc!f-Xformatrelidedfallbacknamer.axesrmappingsrlabelsrulesProcessingLastF processinglastrsourceszvariable-fonts instancesr7xml)encodingmethodxml_declaration pretty_print)r'rlroattribrjr axisMappingselidedFallbackNamermrnr_addAxisobjectr4findall_addAxisMappinglocationLabels_addLocationLabelr_addRuler _addSource variableFonts_addVariableFontr _addInstancer_addLib ElementTreewriter*)r5prettyrr axesElement axisObjectmappingsElement lastGroup mappingObject labelsElement labelObject attributes ruleObject sourceObjectvariableFontsElement variableFontinstanceObjecttrees r.rzBaseDocWriter.writes%(XX-Xd>W>W-X%X "    $ $""//""55A**V,K""55A''::""#78 II  [ )--22 &J MM* % &    + +"OI!%!4!4!A!A E =*#? $ 3 3 A A J %%&:LI J II  1 2    ( ( II  RZZ 4 5"11;; .N   n - .    " " LLD$7$7$;$;Q ?~~dii( II+  r0c|jj}td|jjDsx|jjsbtd|jj Ds<|jj s&td|jjDr|dkrd}|jjr|dkrd}|S)zTry to use the version specified in the document, or a sufficiently recent version to be able to encode what the document contains. c3pK|].}t|dxs|jduxs |j0yw)r!N)rSr r)rrs r.rz9BaseDocWriter._getEffectiveFormatTuple..sEh'#$$D0#??#s46c34K|]}|jywr3)rz)rrms r.rz9BaseDocWriter._getEffectiveFormatTuple..sX&6--Xsc3PK|]}|jxs |j ywr3)rr)rrs r.rz9BaseDocWriter._getEffectiveFormatTuple..s,&&?(*?*??s$&r)rr8) rj formatTuplerrrrrrr)r5 minVersions r.rkz&BaseDocWriter._getEffectiveFormatTuples((44 !//44   ""11XDK0J(5J  f %N#u,.2oonQ>O.P !!(+.2oonQ>O.P !!(+.2oon.M !!(+   j ) *,,,r0cnt||k(rd|zSd|zjdjdS)Nz%dz%f0rr)r?rstrip)r5nums r.rzBaseDocWriter.intOrFloats7 s8s?#: s ""3'..s33r0ctjd}|j|j|jd<|jD] }tjd}|D]}|j d|j d&tjd}|j d|jd<|j d-|j |j d|jd<|j d-|j |j d|jd<|j|t|s|j|#|jD]L}tjd}|d|jd<|d |jd <|j|Nt|r.|jjd dj|yy) Nrro conditionsetrr conditionsubrr8with.rules) rmrnrorrrrrrrror) r5r ruleElementrconditionsetElementcondconditionElementr subElements r.rzBaseDocWriter._addRulesjj( ?? &)3K  v &$22 8J"$**^"< " =88I&.488I3F3N#%::k#: 26((62B ''/88I&29=+:$++I688I&29=+:$++I6$**+;< =&'""#67% 8&?? +CE*J(+AJ  f %(+AJ  f %   z *  + {  II  h ' * 1 1+ > r0ctjd}|j|jd<|j|jd<j ||j |jrv|jD]g\}}tjd}j||jd<j||jd<|j|i|j |jrwtjd}|j"t|j|jd<|jD]}j|||j|t|d rQj|j|jd <j|j |jd <n=t|d r1d j#fd |j$D|jd <j|j&|jd<|j(rd|jd<j*j-ddj|y)Nrrror inputoutputr{orderingrrr! c3@K|]}j|ywr3)r)rrXr5s r.rz)BaseDocWriter._addAxis..Js4'("4r1r ryr)rmrnrrro_addLabelNamesr r rrr rrE _addAxisLabelrSrrr'r!rr ror)r5r axisElement inputValue outputValue mapElementrrs` r.rzBaseDocWriter._addAxis4sjj( $.NN 5!%/__ 6" K)>)>? >>+5>> /' KZZ. -1__Z-H !!'*.2ook.J !!(+"":.  /  " " .*2G2GJJx0M&&236z7N7N3O $$Z0#.. 9""=%8 9   } - :y ),0OOJ>.4L   +   28L   /  ,59__%%6L   1 2 L%*:*:;<(r0ct|jD]E\}}tjd}||jt <||_|j|Gy)N labelname)sortedrRrmrnrXML_LANGtextr)r5 parentElementr r labelNamelanguageElements r.rzBaseDocWriter._addLabelNameszsX'-j.>.>.@'A 2 #L) jj5O/;O " "8 ,#,O   1  2r0c`tjd}|j|jd<|jrd|jd<|j rd|jd<|j ||j|j||j|j|y)Nrrorr1rr) rmrnrorr1r2rr _addLocationElementrr)r5rrrs r.rzBaseDocWriter._addLocationLabelszz'* &+jj F# >>.4L   +   28L   / L%*:*:;   E.IZZ 4 ,0II !!&)&tyy1eU+26//%(2KJ%%h/26//%(2KJ%%h/26//%2HJ%%h/!!*-)dii<.GZZ 4 ,0II !!&)$TYY/151G !!+.!!*-! ." z?Q    , r0c. tjd}|j|j|jd<|j|j|jd<|j |j |jd<|j |j |jd<|jrt|jj}|j|D]W}|dk(r tjd}||jt<|j||_ |j|Y|jrt|jj}|j|D]W}|dk(r tjd}||jt<|j!||_ |j|Y|j"rt|j"j}|j|D]W}|dk(r tjd}||jt<|j%||_ |j|Y|j&rt|j&j}|j|D]W}|dk(r tjd}||jt<|j)||_ |j|Y|j*d k\r5|ji|j-||j.|j0 n@|j24|j5|j2\} |_|j| |j6|j6|jd <|j8|j8|jd <|j:|j:|jd<|j<|j<|jd<|j*d kr|j>r|jAd gk(r&tjd} |j| |jAd d} tC|j>jED]*\} } |jG||| | } | j| ,|jHr&tjd}|j||jJr&tjd}|j||jM||jNd|jPjAddj|y)Nrrorq familyname stylenamerstylemapstylenamestylemapfamilynamerrrnpostscriptfontnamez.glyphsrrrrrz .instances))rmrnrorrrxryrrUkeyssortrrrrrzrrrrrrlrr~rrqrrnrrrrrrrR_writeGlyphElementrrrrro)r5rinstanceElement languageCodescodelocalisedStyleNameElementlocalisedFamilyNameElement!localisedStyleMapStyleNameElement"localisedStyleMapFamilyNameElementlocationElement glyphsElement glyphNamedata glyphElementkerningElement infoElements r.rzBaseDocWriter._addInstances$**Z0    *-;-@-@O " "6 *  ' ' 31?1M1MO " ": .  $ $ 03A3L3LO " "< 0  # # /2@2J2JO " "; /  , , !B!B!G!G!IJM    % B4<,.JJ{,C)=A)00:1?1L1LT1R).&&'@A  B  - - !C!C!H!H!JKM    % C4<-/ZZ -E*>B*11(;2@2N2Nt2T*/&&'AB  C  4 4 !J!J!O!O!QRM    % J4<46JJ?R4S1EI188B"77=26 &&'HI J  5 5 !K!K!P!P!RSM    % K4<57ZZ@T5U2FJ299(C"88>37 &&'IJ K  $ $ .++3((##1#@#@!/!B*11(;2>2L2LT2R*/$$%?@  A   E*J(+J  f %   ,  " "JJx0M+.M  (   /  $ $ jj4O-0O " "6 *   1  L$9$9**V,K$$-0 ""6*$$-0 ""6*   -  # #ZZ 2N,/N ! !& )   0  ' '$44 3!zz'2 .2 ##F+.1 ##F+$$\2  3  $ $ .  $ $l.C.C %  6:5N5N%%6 2O\2   1 *%a(// >r0cPtjd}|j|jd<|j|j|jd<|j rtjd}|j D]b}tjd}|j|jd<t |drtt|}|jtj k7r(|j|j|jd<|jtjk7r(|j|j|jd<|jm|j|j|jd <nDt |d r8tt|}|j|j |jd <|j#|e|j#||j%||j&d |j#|y) NrGrornz axis-subsetsrLr.rr userdefaultr/rr)rmrnrorrnrHrSrrr.rPrQrr0rNr!r/rrr)r5rvf vfElementsubsetsElementsubset subsetElements r.rzBaseDocWriter._addVariableFontVsJJ/ #%77  ;; "+-;;I  Z ( >>ZZ7N.. 5 " = 9 /5{{ $$V,6=1!";VDF))dhhY6>Boo"..? ,,];))TXX5>Boo"..? ,,];))5>Boo"..? ,,];V[1!";VDF8<((9M((5%%m43 54   ^ , Y*Y'r0c|sytjd}|jtj|||j|y)Nr) indent_level)rmrnrrtotree)r5rr r"rs r.rzBaseDocWriter._addLib}s= ZZ& (//$\JKZ(r0ctjd}|jdrd|jd<|jdDdj |jdDcgc] }t |c}|jd<|jd7|j |jd\}|d<|j||||jd<|jd "%>"0))00++--)). I V6-*4 ?@:</&)%).A) )*2 +' +0G +  +"37+/ -0 - ) -8hCT@?D%('%(-C%( %(N)"r0rceZdZeZeZeZe Z e Z e ZeZeZeZeZeZdZedZdZdZddZdZddZ d Z!d Z"dd Z#d Z$d Z%dZ&ddZ' ddZ(dZ)dZ*dZ+dZ,y)rcF||_||_tj|j}|j |_|j j jdd|j_g|_ g|_ g|_ g|_ i|_ d|_y)Nrwz3.0T)r*rjrmparsegetrootrorr formatVersion_axesrrr axisDefaults_strictAxisNames)r5rprjrs r.rBzBaseDocReader.__init__s  ,xx "LLN ,0II,<,<,@,@5,Q)    $r0cRtt|d}|||}d|_|S)Nutf-8)r)rrr*)rYstringrjfr5s r. fromstringzBaseDocReader.fromstrings+ GFW5 61n%  r0c|j|j|j|j|j |j |j yr3)readAxes readLabels readRulesreadVariableFonts readSources readInstancesreadLibrFs r.readzBaseDocReader.readsL        r0ctg}|jjd}|B|jjdd}|dvrt d|z|dk(|j _|jjdD]'}|j}|jjdx}|_ |j||}|r6|jj||jjd |jd D]2}|j||} | |jj| 4|jd D]=} | jd} | jd } |jj| | f?|j|*||j _y) Nrr}first>r~rTzO processing attribute value is not valid: %r, expected 'first' or 'last'r~z .rules/rulerozWFound stray rule conditions outside a conditionset. Wrapped them in a new conditionset.z .conditionsetz.subr)rorrrrrjr|rrfro_readConditionElementsrrlogrrr) r5r rulesElementprocessingValuerrruleNameexternalConditionsconditionSetElement conditionSetrrhrs r.rMzBaseDocReader.readRulessyy~~h/  #*1155lGLO&77.13BC7F6OD   399,,]; %K113J)4););)?)?)G GHz!%!-F.K-5-Aw)KGIK JJrN+ , r0c~ |jjd}|,d|jvr|jd|j_|jj d}|sy|D]}|jj dk\rYd|jvrK|j}|jdjdDcgc] }t|c}|_ nb|j}t|jjd|_ t|jjd|_t|jjd |_|jjd |_|jjd d rd |_|jjd|_|j dD]O}t|jd}t|jd}|j&j)||fQ|j dD]F} | j+D]1\} } | t,k(st/| j0|j2| <3H|jd} | kd| jvrt5| jd|_| j dD],} |j8j)|j;| .|jj<j)||j|j>|j <g|j_ |jj dD]5}|jjd}|j dD]}|jjd}|jd}|jd}i}i}|j dD].}|jd }t|jd}|||<0|j dD].}|jd }t|jd}|||<0|jC||||}|jj@j)|8ycc}w)Nryrxz .axes/axisrr!rrrrror FTrr rrrz.labelsrz.labelz.axes/mappingsrr .dimensionrr)"rorrrjrrrr6r(r^r!rWrrrrror rr rrRrrrr r?r r readAxisLabelrrCrr])r5r axisElementsrrsrrhrlabelNameElementkeyr#rrrrrr inputElement outputElementinputLoc outputLocrror:axisMappingObjects r.rKzBaseDocReader.readAxesstiinnW-  "';{?Q?Q'Q5@5G5G$6D   2yy((6  '# DK##//69 2 22!==? &1&8&8&B&H&H&M%!"E!H% !"557 %*;+=+=+A+A)+L%M "%*;+=+=+A+A)+L%M "!&{'9'9'='=i'H!IJ )0044VE%*HTN+#0"7"7 "E,J%,,V4D!*"3"3H"=>E&+IdO,%)$C$C"*#, +%5 %D%! ##00778IJ) K KA%sR:c  hd}t|j|z }|rtddj||j d}| td|j d}| tdt |}|j d}| t |nd}|j d } | t | nd} |j d } | t | nd} |j d d k(rd nd} |j dd k(rd nd}|j dDcic]4}|jD]\}}|tk(r||jxsd!6}}}}|j|||| | || |Scc}}}w)N>ror1rrrrrz+label element contains unknown attributes: , ro)label element must have a name attribute.rz.label element must have a uservalue attribute.rrrr1rTFrrrD)ror/r.r0r1r2r3r ) setrrr'rr^rrRrrr7)r5element xml_attrs unknown_attrsrovalueStrr: minimumStrr maximumStrrlinkedValueStr linkedValuer1r2 label_namerWr#r s r.rdzBaseDocReader.readAxisLabel^s GNN+i7 *=dii >V=WX {{6" <*+VW W;;{+  *@ h[[/ '1'=% #4[[/ '1'=% #4 %67/=/IeN+t ";;z2f<4%&{{>:fDt% &ook:  (..0 dx *//'R '   ,,%'!-   s(9E>c |jjdkryhd}|jjdD]:}t |j |z }|rt ddj||jd}| t d|j|\}}|rt d|d |jd d k(rd nd }|jdd k(rd nd }|jdD cic]4} | jD]\} } | tk(r| | jxsd!6} } } } |j||||| } |jjj| =ycc} } } w)Nr>ror1rz .labels/labelz+Label element contains unknown attributes: rororpz