
    jke_                     
   d Z ddlmZ ddlmZ ddlmZ ddlmZ	 ddl
mZ ddlmZmZ ddlmZ d	d
lmZmZ d$dZd Zd Zd Zd Zd Zd$dZd Zd Z G d de      Zej=                  e	j>                  d      d        Z ej=                  e	jB                  e	jD                  fd      d        Z d%dZ#d Z$d Z%d Z&d Z'd Z(d Z)d  Z*d! Z+e,d"k(  r4dd#l-Z-dd#l.Z. e.j^                   e-j`                         jb                         y#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)buildLookupbuildSingleSubstSubtable)OrderedDict   )VarLibErrorVarLibValidationErrorc           	      H   t        |t              r|gn
t        |      }d|vxs t        |      dkD  }t	        t        | j                               |       t        |      }t        |      \  }}d| vrt               | d<   n7t        | d   j                        j                  |      }|rt        d|       t        | d   j                  ||      }g }	|D ])  \  }
}|	j                  |
|D cg c]  }||   	 c}f       + t!        | | d   j                  |	|       yc c}w )ac  Add 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substitutionsGSUBz4FeatureVariations already exist for feature tag(s): N)
isinstancestrsortedlen_checkSubstitutionGlyphsExistsetgetGlyphOrderoverlayFeatureVariationsmakeSubstitutionsHashable	buildGSUB_existingVariableFeaturestableintersectionr   buildSubstitutionLookupsappendaddFeatureVariationsRaw)fontconditionalSubstitutions
featureTagfeatureTagsprocessLastr   allSubstitutionsexistingTags	lookupMapconditionsAndLookupsconditionSetss               >/usr/lib/python3/dist-packages/fontTools/varLib/featureVars.pyaddFeatureVariationsr0      sH   N #-Z"=:,6*CUK+Cs;/?!/CK!t))+,.
 --EFM 2K2.. T {V0f1C1CDQQ
 F|nU 
 )V,kI '? 
#m##-@QIaL@A	


 D$v,"4"46JKX As   -Dc                 2   t               }t        | d      r| j                  t| j                  j                  }| j                  j
                  D ]E  }|j                  j                  D ]*  }|j                  ||j                     j                         , G |S )NFeatureVariations)r   hasattrr2   FeatureListFeatureRecordFeatureVariationRecordFeatureTableSubstitutionSubstitutionRecordaddFeatureIndex
FeatureTag)r   existingFeatureVarsTagsfeaturesfvrftsrs        r/   r   r   b   s    !eu)*u/F/F/R$$22**AA 	TC44GG T'++HT5F5F,G,R,RST	T #"    c                     t               }|D ]4  \  }}||j                         z  }|t        |j                               z  }6 || z
  }|rt        ddj	                  |             y )NzAMissing glyphs are referenced in conditional substitution rules: z, )r   keysvaluesr   join)r   r   referencedGlyphNames_substitutionmissings         r/   r   r   l   s    5( ;< 1 1 33L$7$7$9 ::; #Z/G#		'"#%
 	
 r@   c                 X   t               }| D ].  \  }}t        |      }||v r||   j                  |       *|||<   0 |j                         D cg c]  \  }}|t	        |      f } }}~t               }t        |       D ]J  \  }}t        t        d |D        d             }||v r||   j                  |       =t	        |      ||<   L t        t        |j                                     } ~t               dff}t        |      }t        |       D ]  \  }\  }	}
t        |      }d|z  }|j                         D ]i  \  }}|	D ]_  }t        ||      \  }}|&t        |      }|j                  |d      |z  |z  ||<   |=t        |      }|j                  |d      |z  ||<   a k |} g }t        |j                         d       D ]V  \  }}|dk(  rg }d}|r)|dz  r|j                  | |   d          |dz  }|dz  }|r)|j                  t	        |      |f       X |S c c}}w )a  Compute 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'}])]

    c              3   D   K   | ]  }t        t        |              y wN)r   
cleanupBox).0ks     r/   	<genexpr>z+overlayFeatureVariations.<locals>.<genexpr>   s     6Q*Q-(6s    c                 F    t        t        | j                                     S rK   )tupler   items)ds    r/   <lambda>z*overlayFeatureVariations.<locals>.<lambda>   s    eF1779$56 r@   )keyr   r   c                      t        | d          S )Nr   r   )
BoxAndRanks    r/   rT   z*overlayFeatureVariations.<locals>.<lambda>   s    :a=1I0I r@   )r   r   extendrR   dictreversedrQ   r   updatelist	enumerate
overlayBoxgetr"   )r%   mergedvaluerU   rN   vinitMapInitboxMapi
currRegionrF   newMapcurrRankboxrankcurrBoxr    	remainderrR   
substsLists                       r/   r   r   y   s   ^ ]F.  
ssm&=3Ku%F3K  :@HADGHH ]F78 
&
U6#66
 &=3Ku%u+F3K
&  $HV\\^$<=
 J?$K%F'(@A ?J[)6 	HIC% 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  Is   H&c                    i }|j                  |        |j                  |       t        |       t        |      z  D ]<  }| |   \  }}||   \  }}t        ||      }t        ||      }	||	k  sd|fc S ||	f||<   > t	        |      }
d}d}| D ]  }||v rd}d} n |D ]c  }|| vr||   \  }}||   \  }}||k  r||k  r#|r||fc S d}d}||k  rt        ||      }|}	n||k  r|}t        ||      }	n||fc S ||	f|
|<   e |r|dfS ||
fS )aI  Overlays ``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[   r   maxminrY   )topbotr    axisTagmin1max1min2max2minimummaximumrl   	extrudingfullyInsides                r/   r^   r^      s    Ls8c#h& 1\
d\
ddD/dD/ 9 ' 0W1( S	IIK c>	   .#!'*
d\
d4<DDL $$	 4<$oGGT\G$oG  $$$g-	'A .D T!!""r@   c                 b    | j                         D ci c]  \  }}|dk7  s|| c}}S c c}}w )zReturn a sparse copy of `box`, without redundant (default) values.

    >>> cleanupBox({})
    {}
    >>> cleanupBox({'wdth': (0.0, 1.0)})
    {'wdth': (0.0, 1.0)}
    >>> cleanupBox({'wdth': (-1.0, 1.0)})
    {}

    )g      g      ?)rR   )ri   taglimits      r/   rL   rL   K  s-     *-M:38LCJMMMs   ++c                    t        |t              r|gn
t        |      }d|vxs t        |      dkD  }|j                  dk  rd|_        t               }|j                  j                  D ch c]  }|j                  |v r|j                   c}t        |      z
  }|rg }	t        |      D ]D  }t        |g       }
|j                  j                  j                  |
       |	j                  |
       F t        |j                  j                        |j                  _        t        |       |	D ]  }
|j                  j                  j                  |
      }|j                  j                  D ]  }|j                   j"                  t%        d|j&                   d      |j                   j(                  D cg c]  }|j*                   }}|j                   j"                  g|z   D ]7  }|j,                  j                  |       t        |j,                        |_        9  |j/                  |        r7|j1                  fdt3        |j                  j                        D               t3        | d   j4                        D ci c]  \  }}|j6                  | }}}g }|D ]  \  }}g }t        |j9                               D ]9  \  }\  }}||kD  rt;        d	      t=        ||   ||      }|j                  |       ; g }t        |      D ]V  }|j                  j                  |   j>                  j@                  }|r||z   n||z   }|j                  tC        ||             X |j                  tE        ||              tG        |d
      r|jH                  |jH                  j                  dk7  r$t%        d|jH                  j                  dd      |jH                  jJ                  jM                  |       t        |jH                  jJ                        |jH                  _'        ytQ        |      |_$        yc c}w c c}w c c}}w )z{Low level implementation of addFeatureVariations that directly
    models the possibilities of the FeatureVariations table.r   r     Nz,Feature variations require that the script 'z$' defines a default language system.c              3   D   K   | ]  \  }}|j                   v r|  y wrK   )r;   )rM   indexfeaturer*   s      r/   rO   z*addFeatureVariationsRaw.<locals>.<genexpr>  s+      !
w!!\1 !
s    fvarz<A condition set has a minimum value above the maximum value.r2      z/Unsupported FeatureVariations table version: 0x08xz (expected 0x00010000).))r   r   r   r   Versionr   r4   r5   r;   buildFeatureRecordr"   FeatureCountsortFeatureListr   
ScriptListScriptRecordScriptDefaultLangSysr   	ScriptTagLangSysRecordLangSysr:   r9   r[   r]   axesrs   rR   r   buildConditionTableFeatureLookupListIndex#buildFeatureTableSubstitutionRecordbuildFeatureVariationRecordr3   r2   r6   rX   FeatureVariationCountbuildFeatureVariations)r$   r   r%   r&   r'   r(   varFeatureIndicesr   newTagsvarFeatures
varFeaturevarFeatureIndexscriptRecordlsrlangSystemslangSys	axisIndexaxisaxisIndicesfeatureVariationRecordsr-   lookupIndicesconditionTablers   minValuemaxValuectrecordsexistingLookupIndicescombinedLookupIndicesr*   s                                 @r/   r#   r#   ^  sV    #-Z"=:,6*CUK+Cs;/?!/CK }}z!" ((66, 	L +-G / 	+J+J;J++22:>z*	+ *-U->->-L-L)M&% 	3J#//==CCJOO % 0 0 = = 	E&&55=%(2233WY  7C6I6I6W6WXss{{XX , 3 3 B BCkQ EG((//@+.w/C/C+DG(E	E !!/2	3  	   !
"+E,=,=,K,K"L!
 	
 8AfARAR7S$3ItiK  !'? 
#m-3L4F4F4H-I 	&)G)h("+R  %[%98XNB!!"%	& %&78 	O$)$5$5$C$C%goo "
  &5"%:: " NN3#%:	 	 &&'@	
3
: u)*u/F/F/R""**j8,,44S99PR  	66==>UV8;##::9
5 #99P"Qm4 Ys   ,!Q9Q	Qc                  x   t        d      } t        j                         x}| _        d|_        t        j
                         |_        g |j
                  _        t        j                         |_        g |j                  _        t        j                         |_	        g |j                  _
        t        j                         }d|_        t        j                         |_        d|j                  _        g |j                  _        d|j                  _        t        j                         }t        j                          |_        d|j                   _        g |j                   _        |j                   |j                  _        |j
                  j                  j'                  |       d|j
                  _        d|_        | S )z Build a GSUB table from scratch.r   r   DFLTNr     r   )r   otr   r   r   r   r   r4   r5   
LookupListLookupr   r   r   r   LangSysCountr   ReqFeatureIndexr:   r"   ScriptCountr2   )	fontTablegsubsreclangrecs       r/   r   r     s-    IWWY&D9?DLmmoDO#%DOO ~~'D%'D"mmoDODOO??DDN))+DK!%DKK "DKK DKK GjjlGO&,GOO##%GOO !(DKKOO  ''-"#DOO!Dr@   c                    t               }g }| D ]e  \  }}g }|D ]F  }t        t        |j                                     }|j	                  |       |j                  |       H |j	                  ||f       g |t        |      fS )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.)r   rQ   r   rR   r"   r9   )r%   r)   	condSubstr-   substitutionMapsr   substitutionMapsubsts           r/   r   r     s     uI*B 8&&/ 	(O&!6!6!89:E  '  '	( 	,678 f-...r@   c                       e Zd Zd Zy)ShifterVisitorc                     || _         y rK   )shift)selfr   s     r/   __init__zShifterVisitor.__init__  s	    
r@   N)__name__
__module____qualname__r    r@   r/   r   r     s    r@   r   r   c                 d    | j                   }|D cg c]  }||z   	 }}t        |||       y c c}w rK   )r   setattr)visitorobjattrra   r   ls         r/   visitr     s3    MME %&1QY&E&Cu 's   -c                 8    t        ||| j                  |z          y rK   )r   r   )r   r   r   ra   s       r/   r   r     s     Cw}}u,-r@   c                    |rt        | j                  j                        nd}i }t        |      D ]  \  }}||z   ||<    |s`t        |      }t	        |      }|j                  | j                  j                         |j                  | j                  j                         t        |      D ]  \  }}	t        |	      }
t        t        |
      g      }|r&| j                  j                  j                  |       n&| j                  j                  j                  ||       | j                  j                  ||	      |u rJ  t        | j                  j                        | j                  _        |S )zlBuild the lookups for the glyph substitutions, return a dict mapping
    the substitution to lookup indices.r   )r   r   r   r]   r   r   r4   r5   rY   r	   r
   r"   insertLookupCount)r   r)   r(   
firstIndexr+   re   r   r   r   r   substMaplookups               r/   r!   r!     sB    1<T__++,JI'(89 4?%/!^	/"4 $% 'd&&445doo,,-./ B5;6x@ABOO""))&1OO""))!V4%%i&676AAAB #&doo&<&<"=DOOr@   c                 j    t        j                         }d|_        | |_        t	        |       |_        |S )z%Build the FeatureVariations subtable.r   )r   r2   r   r6   r   r   )r   fvs     r/   r   r   5  s2    				BBJ 7B"#:;BIr@   c                     t        j                         }| |_        t        j                         |_        ||j                  _        |j                  j                          |S )zBuild a FeatureRecord.)r   r5   r;   r   r   populateDefaults)r&   lookupListIndicesfrs      r/   r   r   >  sE    				BBMBJ!2BJJJJ!Ir@   c                 `   t        j                         }t        j                         |_        | |j                  _        t	        |       |j                  _        t        j                         |_        d|j                  _        ||j                  _        t	        |      |j                  _	        |S )zBuild a FeatureVariationRecord.r   )
r   r6   ConditionSetConditionTabler   ConditionCountr7   r   r8   SubstitutionCount)r   substitutionRecordsr>   s      r/   r   r   H  s    

#
#
%C(C&4C#&).&9C##%#>#>#@C +5C  (6IC  3589L5MC  2Jr@   c                     t        j                         }| |_        t        j                         |_        ||j                  _        t        |      |j                  _        |S )z'Build a FeatureTableSubstitutionRecord.)r   FeatureTableSubstitutionRecordr:   r   r   r   r   )featureIndexr   r?   s      r/   r   r   U  sH    ,,.D$D::<DL#4DLL "#45DLLKr@   c                 f    t        j                         }d|_        | |_        ||_        ||_        |S )zBuild a ConditionTable.r   )r   r   Format	AxisIndexFilterRangeMinValueFilterRangeMaxValue)r   filterRangeMinValuefilterRangeMaxValuer   s       r/   r   r   _  s3    				BBIBL0B0BIr@   c                    t        | j                  j                        D cg c]  \  }}|j                  ||f }}}|j	                          |D cg c]  \  }}}|
 c}}}| j                  _        t        t        |D cg c]  \  }}}|
 c}}}t        t        |                        }t        | |       yc c}}w c c}}}w c c}}}w )zSort the feature list by feature tag, and remap the feature indices
    elsewhere. This is needed after the feature list has been modified.
    N)
r]   r4   r5   r;   sortrY   zipranger   remapFeatures)r   r   featagIndexFear}   featureRemaps         r/   r   r   i  s     $E$5$5$C$CDE3 
$K  BM&N&NsE3s&NE#+66sE3U6c+>N8OPL
 %&
 'O6s   C CCc                    t        | j                  j                        D ]h  \  }}|j                  j                  }|t        ||       t        |j                  j                        D ]  \  }}|j                  }t        ||        j t        | d      rX| j                  K| j                  j                  D ]1  }|j                  j                  D ]  }	||	j                     |	_         3 yyy)z7Go through the scripts list, and remap feature indices.Nr2   )r]   r   r   r   r   _remapLangSysr   r   r3   r2   r6   r7   r8   r:   )
r   r   scriptIndexscriptdefaultLangSyslangSysRecordIndex
langSysRecr   r>   r?   s
             r/   r   r   |  s    ()9)9)F)FG 1V55%.,7.78S8S.T 	1*
 ((G'<0	1	1 u)*u/F/F/R**AA 	DC44GG D$01B1B$C!D	D 0S*r@   c                     | j                   dk7  r|| j                      | _         | j                  D cg c]  }||   	 c}| _        y c c}w )Nr   )r   r:   )r   r   r   s      r/   r   r     sD    &(".w/F/F"G=D=Q=QREL/RGRs   A__main__N)r   )F)2__doc__fontTools.misc.dictToolsr   fontTools.misc.intToolsr   fontTools.ttLibr   fontTools.ttLib.tablesr   r   fontTools.ttLib.ttVisitorr   fontTools.otlLib.builderr	   r
   collectionsr   errorsr   r   r0   r   r   r   r^   rL   r#   r   r   r   register_attrr   r   SubstLookupRecordPosLookupRecordr!   r   r   r   r   r   r   r   r   r   doctestsysexittestmodfailedr   r@   r/   <module>r     s#  
 . - $ 1 / J # 6NYb#

pzR#jN&lRhB/ Y 
 bjj*;< = 2--.0A..>
'&D S zCHH_W__%%& r@   