L iDfdZddlmZddlmZddlmZddlmZ ddl m Z ddl m Z mZddlmZd d lmZmZd%d Zd Zd ZdZdZdZd%dZdZdZGdde Zej=e j>ddZ ej=e jBe jDfddZ d&dZ#dZ$dZ%dZ&dZ'dZ(dZ)d Z*d!Z+d"Z,e-d#k(r4dd$l.Z.dd$l/Z/e/j`e.jbjdy$y$)'zModule to build FeatureVariation tables: https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#featurevariations-table NOTE: The API is experimental and subject to change. )hashdict bit_count)newTable)otTables) TTVisitor) buildLookupbuildSingleSubstSubtable) OrderedDict) VarLibErrorVarLibValidationErrorc t|tr|gn t|}d|vxst|dkD}t t |j |t|}t|\}}d|vrt|d<n7t|djj|}|rtd|t|dj||}g} |D])\} }| j| |D cgc]} ||  c} f+t!||dj| ||j#dx} t%d| j&| _yycc} w)acAdd conditional substitutions to a Variable Font. The `conditionalSubstitutions` argument is a list of (Region, Substitutions) tuples. A Region is a list of Boxes. A Box is a dict mapping axisTags to (minValue, maxValue) tuples. Irrelevant axes may be omitted and they are interpretted as extending to end of axis in each direction. A Box represents an orthogonal 'rectangular' subset of an N-dimensional design space. A Region represents a more complex subset of an N-dimensional design space, ie. the union of all the Boxes in the Region. For efficiency, Boxes within a Region should ideally not overlap, but functionality is not compromised if they do. The minimum and maximum values are expressed in normalized coordinates. A Substitution is a dict mapping source glyph names to substitute glyph names. Example: # >>> f = TTFont(srcPath) # >>> condSubst = [ # ... # A list of (Region, Substitution) tuples. # ... ([{"wdth": (0.5, 1.0)}], {"cent": "cent.rvrn"}), # ... ([{"wght": (0.5, 1.0)}], {"dollar": "dollar.rvrn"}), # ... ] # >>> addFeatureVariations(f, condSubst) # >>> f.save(dstPath) The `featureTag` parameter takes either a str or a iterable of str (the single str is kept for backwards compatibility), and defines which feature(s) will be associated with the feature variations. Note, if this is "rvrn", then the substitution lookup will be inserted at the beginning of the lookup list so that it is processed before others, otherwise for any other feature tags it will be appended last. rvrnr ) glyphNames substitutionsGSUBz4FeatureVariations already exist for feature tag(s): zOS/2N) isinstancestrsortedlen_checkSubstitutionGlyphsExistset getGlyphOrderoverlayFeatureVariationsmakeSubstitutionsHashable buildGSUB_existingVariableFeaturestable intersectionr buildSubstitutionLookupsappendaddFeatureVariationsRawgetmax usMaxContext) fontconditionalSubstitutions featureTag featureTags processLastrallSubstitutions existingTags lookupMapconditionsAndLookups conditionSetsos2s b/mnt/ssd/data/python-lab/Trading/venv/lib/python3.12/site-packages/fontTools/varLib/featureVars.pyaddFeatureVariationsr4sxN#-Z"=:,6*CUK +Cs;/?!/CK!t))+,. --EFM2K2..T {V 0f1C1CDQQ   F|nU  ) V ,kI'? # m## -@QIaL@ A  D$v,"4"46JKXxx,q#"2"23-As- E c2t}t|dr|jt|jj}|jj D]E}|j jD]*}|j||jj,G|S)NFeatureVariations) rhasattrr6 FeatureList FeatureRecordFeatureVariationRecordFeatureTableSubstitutionSubstitutionRecordadd FeatureIndex FeatureTag)rexistingFeatureVarsTagsfeaturesfvrftsrs r3rrks!eu)*u/F/F/R$$22**AA TC44GG T'++HT5F5F,G,R,RS T T #"ct}|D]4\}}||jz}|t|jz}6||z }|rtddj |y)NzAMissing glyphs are referenced in conditional substitution rules: z, )rkeysvaluesrjoin)rrreferencedGlyphNames_ substitutionmissings r3rrus5(;< 1 1 33L$7$7$9 ::;#Z/G#  '"# %  rDcXt}|D].\}}t|}||vr||j|*|||<0|jDcgc]\}}|t |f}}}~t}t |D]J\}}t td|Dd}||vr||j|=t |||<Ltt |j}~tdff}t|}t|D]\}\} } t|} d|z} |jD]i\} }| D]_}t|| \}}|&t|}| j|d|z| z| |<|=t|}| j|d|z| |<ak| }g}t|jdD]V\} }|dk(r g}d}|r)|dzr|j||d|dz}|dz }|r)|jt | |fX|Scc}}w)aCompute overlaps between all conditional substitutions. The `conditionalSubstitutions` argument is a list of (Region, Substitutions) tuples. A Region is a list of Boxes. A Box is a dict mapping axisTags to (minValue, maxValue) tuples. Irrelevant axes may be omitted and they are interpretted as extending to end of axis in each direction. A Box represents an orthogonal 'rectangular' subset of an N-dimensional design space. A Region represents a more complex subset of an N-dimensional design space, ie. the union of all the Boxes in the Region. For efficiency, Boxes within a Region should ideally not overlap, but functionality is not compromised if they do. The minimum and maximum values are expressed in normalized coordinates. A Substitution is a dict mapping source glyph names to substitute glyph names. Returns data is in similar but different format. Overlaps of distinct substitution Boxes (*not* Regions) are explicitly listed as distinct rules, and rules with the same Box merged. The more specific rules appear earlier in the resulting list. Moreover, instead of just a dictionary of substitutions, a list of dictionaries is returned for substitutions corresponding to each unique space, with each dictionary being identical to one of the input substitution dictionaries. These dictionaries are not merged to allow data sharing when they are converted into font tables. Example:: >>> condSubst = [ ... # A list of (Region, Substitution) tuples. ... ([{"wght": (0.5, 1.0)}], {"dollar": "dollar.rvrn"}), ... ([{"wght": (0.5, 1.0)}], {"dollar": "dollar.rvrn"}), ... ([{"wdth": (0.5, 1.0)}], {"cent": "cent.rvrn"}), ... ([{"wght": (0.5, 1.0), "wdth": (-1, 1.0)}], {"dollar": "dollar.rvrn"}), ... ] >>> from pprint import pprint >>> pprint(overlayFeatureVariations(condSubst)) [({'wdth': (0.5, 1.0), 'wght': (0.5, 1.0)}, [{'dollar': 'dollar.rvrn'}, {'cent': 'cent.rvrn'}]), ({'wdth': (0.5, 1.0)}, [{'cent': 'cent.rvrn'}]), ({'wght': (0.5, 1.0)}, [{'dollar': 'dollar.rvrn'}])] c3DK|]}tt|ywN)r cleanupBox).0ks r3 z+overlayFeatureVariations..s6Q*Q-(6s cFtt|jSrO)tupleritems)ds r3z*overlayFeatureVariations..seF1779$56rD)keyrr c t|d S)Nr r) BoxAndRanks r3rXz*overlayFeatureVariations..s:a=1I0IrD)r rextendrVdictreversedrUrupdatelist enumerate overlayBoxr$r")r(mergedvaluerYrRv initMapInitboxMapi currRegionrJnewMapcurrRankboxrankcurrBoxr remainderrV substsLists r3rrs^]F. ssm &= 3K  u %F3K  :@HADG HH]F78 & U 6#66   &= 3K  u %u+F3K & $HV\\^$<= J?$K  %F'(@A ?J[)6 HIC% H*4Wc*B' i+#+L#9L+1::lA+F+MPX+XF<(( ( 3I(. 9a(@4(GF9% H H  E I . T 19  ax!!":1"=a"@A QJD FA   d3i,- . Lu IsH&ci}|j||j|t|t|zD]<}||\}}||\}}t||}t||} || ksd|fcS|| f||<>t |} d} d} |D] }||vrd} d} n|D]c}||vr||\}}||\}}||kr||kr#| r||fcSd} d} ||krt||}|} n||kr|}t||} n||fcS|| f| |<e| r|dfS|| fS)aIOverlays ``top`` box on top of ``bot`` box. Returns two items: * Box for intersection of ``top`` and ``bot``, or None if they don't intersect. * Box for remainder of ``bot``. Remainder box might not be exact (since the remainder might not be a simple box), but is inclusive of the exact remainder. NFT)r_rr%minr]) topbotr axisTagmin1max1min2max2minimummaximumro extruding fullyInsides r3rbrbsLs8c#h&1\ d\ ddD/dD/ 9  ' 0 W1(S IIK c>      . #  !'* d\ d 4>> cleanupBox({}) {} >>> cleanupBox({'wdth': (0.0, 1.0)}) {'wdth': (0.0, 1.0)} >>> cleanupBox({'wdth': (-1.0, 1.0)}) {} )gg?)rV)rltaglimits r3rPrPTs-*- M:38LCJ MM Ms ++c t|tr|gn t|}d|vxst|dkD}|jdkrd|_t }|j jDchc]}|j|vr |jc} t | z }|rg} t|D]D}t|g} |j jj| | j| Ft|j j|j _ t|| D],} |j jj| } |jjD]} | j j"At%j&} d| _d| _g| _d| _ | | j _| j j.Dcgc]}|j&}}| j j"g|zD]7} | j,j| t| j,| _ 9|j1| / r7|j3 fdt5|j jDt5|dj6Dcic]\}}|j8|}}}t;|d xr|j<du}g}|D]M\}}g}t|j?D]9\}\}}||kDr tAd tC||||}|j|;g}t|D]V} |j j| jDjF}|r||zn||z}|jtI| |X|rmtK|j<|x}rU|jLjNjQ|t|jLjN|jL_)3|jtU||P|r|j<jd k7r$tWd |j<jd d|j<jXjQ|t|j<jX|j<_-yt]||_ycc}wcc}wcc}}w)z{Low level implementation of addFeatureVariations that directly models the possibilities of the FeatureVariations table.rr Nrc3DK|]\}}|jvr|ywrO)r?)rQindexfeaturer-s r3rSz*addFeatureVariationsRaw..s+! w!!\1 ! s fvarr6z LangSysRecordr=r_raaxesrur7r6rVrbuildConditionTableFeatureLookupListIndex#buildFeatureTableSubstitutionRecordfindFeatureVariationRecordr;r<r\SubstitutionCountbuildFeatureVariationRecordr r:FeatureVariationCountbuildFeatureVariations)!r'rr(r)r*r+varFeatureIndicesrnewTags varFeatures varFeaturevarFeatureIndex scriptRecordlangSyslsr langSystems axisIndexaxis axisIndiceshasFeatureVariationsfeatureVariationRecordsr0 lookupIndicesconditionTableruminValuemaxValuectrecordsexistingLookupIndicescombinedLookupIndicesrBr-s! @r3r#r#gs#-Z"=:,6*CUK +Cs;/?!/CK }}z!" ((66     , L +-G  / +J+J;J    + + 2 2: >   z * +*-U->->-L-L)M&% 3J#//==CCJOO % 0 0 = = E &&55= jjlG*.G'.4G++-G(+,G(9@L''66B6I6I6W6WXss{{X X , 3 3 B BCkQEG((//@+.w/C/C+DG(E E  ! !/ 2! 3$   ! "+E,=,=,K,K"L!  8AfARAR7S$3It iK *+S0G0Gt0S!'?## m-3L4F4F4H-I & )G)h("+R%[%98XNB  ! !" %  &%&78 O$)$5$5$C$C%goo " & 5"%:: " NN3#%:   -e.E.E~V VC V  ( ( ; ; B B7 K=@,,??>C ( ( : $ * *+NGD C#J  " " * *j 8,,44S99PR  66==>UV8;  # # : :9 5#99P"QK:Ys,!S#!S(4S-cxtd}tjx}|_d|_tj |_g|j _tj|_g|j_tj|_ g|j_ tj }d|_ tj|_ d|j_ g|j_d|j_tj}tj |_d|j _g|j _|j |j_ |j j j'|d|j _d|_|S)z Build a GSUB table from scratch.rrDFLTNrrr )rrrrrrrr8r9 LookupListLookup ScriptTagrrr LangSysCountrrr>r" ScriptCountr6) fontTablegsubsreclangrecs r3rrs- IWWY&D9?DLmmoDO#%DOO ~~'D%'D"mmoDODOO ?? DDN))+DK!%DKK "DKK DKK GjjlGO&,GOO##%GOO !(DKKOO  ''-"#DOO!D rDct}g}|D]e\}}g}|D]F}tt|j}|j ||j |H|j ||fg|t|fS)zTurn all the substitution dictionaries in sorted tuples of tuples so they are hashable, to detect duplicates so we don't write out redundant data.)rrUrrVr"r=)r(r, condSubstr0substitutionMapsrsubstitutionMapsubsts r3rr suI*B8& & / (O&!6!6!89:E   '   ' ( , 67 8 f-. ..rDceZdZdZy)ShifterVisitorc||_yrO)shift)selfrs r3__init__zShifterVisitor.__init__s  rDN)__name__ __module__ __qualname__rrDr3rrsrDrrcd|j}|Dcgc]}||z }}t|||ycc}wrO)rsetattr)visitorobjattrrdrls r3visitr s3 MME % &1QY &E & Cu 's -c8t|||j|zyrO)rr)rrrrds r3rr's Cw}}u,-rDc|rt|jjnd}i}t|D] \}}||z||<|s`t|}t |}|j |j j|j |jjt|D]\}} t| } tt| g} |r&|jjj| n&|jjj|| |jj|| | urJt|jj|j_ |S)zlBuild the lookups for the glyph substitutions, return a dict mapping the substitution to lookup indices.r)rrrrarrr8r9r]r r r"insert LookupCount) rr,r+ firstIndexr.rhrrrrsubstMaplookups r3r!r!.sB1<T__++,JI'(894?%/!^ /"4 $% ' d&&445 doo,,-./B5;6x@AB  OO " " ) )& 1 OO " " ) )!V 4%%i&676AAAB#&doo&<&<"=DOO rDcjtj}d|_||_t ||_|S)z%Build the FeatureVariations subtable.r)rr6rr:rr)rfvs r3rrMs2   BBJ 7B"#:;B IrDctj}||_tj|_||j_|jj |S)zBuild a FeatureRecord.)rr9r?rrpopulateDefaults)r)lookupListIndicesfrs r3rrVsE   BBMBJ!2BJJJJ! IrDctj}t|dk7rEtj|_||j_t||j_nd|_tj |_d|j _||j _t||j _ |S)zBuild a FeatureVariationRecord.rNr) rr:r ConditionSetConditionTableConditionCountr;rr<r)rsubstitutionRecordsrBs r3rr`s # # %C >a??,*8'*-n*='#%#>#>#@C +5C  (6IC  3589L5MC  2 JrDctj}||_tj|_||j_t ||j_|S)z'Build a FeatureTableSubstitutionRecord.)rFeatureTableSubstitutionRecordr>rrrr) featureIndexrrCs r3rrpsH , , .D$D::N8OPL %& 'O 6sC C C ct|jjD]h\}}|jj}| t ||t|jj D]\}}|j}t ||jt|drX|jK|jjD]1}|jjD]} || j| _ 3yyy)z7Go through the scripts list, and remap feature indices.Nr6)rarrrr _remapLangSysrrr7r6r:r;r<r>) rr scriptIndexscriptdefaultLangSyslangSysRecordIndex langSysRecrrBrCs r3rrs()9)9)F)FG1 V55  % ., 7.7 8S8S.T 1 *   ((G '< 0 1 1u)*u/F/F/R**AA DC44GG D$01B1B$C! D D0S*rDc|jdk7r||j|_|jDcgc]}|| c}|_ycc}w)Nr)rr>)rrrs r3rrsD&(".w/F/F"G=D=Q=QREL/RGRs A__main__N)r)F)3__doc__fontTools.misc.dictToolsrfontTools.misc.intToolsrfontTools.ttLibrfontTools.ttLib.tablesrrfontTools.ttLib.ttVisitorrfontTools.otlLib.builderr r collectionsr errorsr rr4rrrrbrPr#rrr register_attrrrSubstLookupRecordPosLookupRecordr!rrrrrrrrrrdoctestsysexittestmodfailedrrDr3rs' .-$1/J#6V4r#  pzR#j N&{RFB / Y bjj*;<= 2--.0A..>   '& D S  z CHH_W__  % %&rD