a
    w=icN                     @   s  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mZ ddlmZ dd	lmZmZ d/ddZdd Zdd Zdd Zdd Zd0ddZdd Zdd Zdd Zdd Zdd  Zd!d" Zd#d$ Zd%d& Zd'd( Z d)d* Z!d+d, Z"e#d-krdd.l$Z$dd.l%Z%e%&e$' j( d.S )1zModule 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popCount)newTable)otTables)buildLookupbuildSingleSubstSubtable)OrderedDict   )VarLibErrorVarLibValidationErrorrvrnc                    s   t t|  |d t|}t|\}}d| vr:t | d< t| d j| g }|D ]$\}}|| fdd|D f qRt	| | d j|| dS )a  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)
    )
glyphNamessubstitutionsGSUBc                    s   g | ]} | qS  r   ).0s	lookupMapr   m/home/droni/.local/share/virtualenvs/DPS-5Je3_V2c/lib/python3.9/site-packages/fontTools/varLib/featureVars.py
<listcomp>C       z(addFeatureVariations.<locals>.<listcomp>N)
_checkSubstitutionGlyphsExistsetZgetGlyphOrderoverlayFeatureVariationsmakeSubstitutionsHashable	buildGSUBbuildSubstitutionLookupstableappendaddFeatureVariationsRaw)fontconditionalSubstitutions
featureTagr   allSubstitutionsZconditionsAndLookupsconditionSetr   r   r   addFeatureVariations   s     

r'   c                 C   sT   t  }|D ]$\}}|| O }|t | O }q
||  }|rPtdd| d S )NzAMissing glyphs are referenced in conditional substitution rules: z, )r   keysvaluesr   join)r   r   ZreferencedGlyphNames_Zsubstitutionmissingr   r   r   r   I   s    r   c                 C   s  t  }| D ]0\}}t|}||v r2|| | q
|||< q
dd | D } ~t  }t| D ]J\}}ttdd |D dd d}||v r|| | q^t|||< q^t	t| } ~t dff}t |}t
| D ]\}\}}t |}	d	|> }
| D ]r\}}|D ]d}t||\}}|d
urDt|}|	|d|B |
B |	|< |d
urt|}|	|d|B |	|< qq|	}qg }t| dd dD ]h\}}|dkrqg }d}|r|d	@ r|| | d	  |d	L }|d	7 }q|t||f q|S )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                 S   s   g | ]\}}|t |fqS r   )dict)r   kvr   r   r   r      r   z,overlayFeatureVariations.<locals>.<listcomp>c                 s   s   | ]}t t|V  qd S N)r   
cleanupBox)r   r.   r   r   r   	<genexpr>   r   z+overlayFeatureVariations.<locals>.<genexpr>c                 S   s   t t|  S r0   )tuplesorteditems)dr   r   r   <lambda>   r   z*overlayFeatureVariations.<locals>.<lambda>)keyr   r
   Nc                 S   s   t | d  S )Nr
   r   )Z
BoxAndRankr   r   r   r7      r   )r	   r   extendr5   reversedr3   r4   updater-   list	enumerate
overlayBoxgetr    )r#   mergedvaluer8   ZinitMapInitZboxMapiZ
currRegionr+   ZnewMapZcurrRankboxZrankZcurrBoxintersection	remainderr5   Z
substsListr   r   r   r   U   s`    /




r   c                 C   sD  i }| |  | | t| t|@ D ]P}| | \}}|| \}}t||}t||}	||	k sld|f  S ||	f||< q(t|}
d}d}|D ]}||vrd}q|| \}}|| \}}||kr||krq|r||f  S d}d}||krt||}|}	n&||kr|}t||}	n||f  S ||	f|
|< q|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minr-   )topZbotrD   axisTagZmin1Zmax1Zmin2Zmax2minimummaximumrE   Z
exactlyOneZfullyInsider   r   r   r>      sJ    





r>   c                 C   s   dd |   D S )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)})
        {}

    c                 S   s   i | ]\}}|d kr||qS ))g      g      ?r   )r   taglimitr   r   r   
<dictcomp>&  r   zcleanupBox.<locals>.<dictcomp>)r5   )rC   r   r   r   r1     s    r1   c                 C   s  |j dk rd|_ d|_g }t|jjD ]\}}|j|kr&|| q&|st|g }|jj| t|jj|j_	t
| |jj|}|jjD ]`}	|	jjdu rtd|	j ddd |	jjD }
|	jjg|
 D ]}|j| t|j|_	qq|g}dd t| d	 jD }g }|D ]\}}g }t| D ]:\}\}}||krLtd
t|| ||}|| q.g }|D ]*}|jj| jj}|t|||  qr|t|| qt||_dS )z{Low level implementation of addFeatureVariations that directly
    models the possibilities of the FeatureVariations table.  Nz,Feature variations require that the script 'z$' defines a default language system.c                 S   s   g | ]
}|j qS r   )LangSys)r   Zlsrr   r   r   r   Q  r   z+addFeatureVariationsRaw.<locals>.<listcomp>c                 S   s   i | ]\}}|j |qS r   )rI   )r   	axisIndexZaxisr   r   r   rN   X  r   z+addFeatureVariationsRaw.<locals>.<dictcomp>Zfvarz<A condition set has a minimum value above the maximum value.)VersionFeatureVariationsr=   FeatureListFeatureRecord
FeatureTagr    buildFeatureRecordlenZFeatureCountsortFeatureListindex
ScriptListScriptRecordScriptDefaultLangSysr   	ScriptTagLangSysRecordFeatureIndexZaxesr4   r5   r   buildConditionTableFeatureLookupListIndex#buildFeatureTableSubstitutionRecordbuildFeatureVariationRecordbuildFeatureVariations)r"   r   r#   r$   ZvarFeatureIndicesrZ   featureZ
varFeatureZvarFeatureIndexZscriptRecordZlangSystemslangSysZaxisIndicesfeatureVariationRecordsr&   ZlookupIndicesconditionTablerI   ZminValueZmaxValuectrecordsZexistingLookupIndicesr   r   r   r!   -  sT    



r!   c                  C   s   t d} t  }| _d|_t |_g |j_t |_g |j_t	 |_	g |j	_
t }d|_t |_d|j_g |j_d|j_t }t |_d|j_g |j_|j|j_|jj| d|j_d|_| S )z Build a GSUB table from scratch.r   rO   ZDFLTNr     r
   )r   otr   r   rR   r[   r\   rT   rU   
LookupListLookupr_   r]   r^   r`   ZLangSysCountrP   ReqFeatureIndexra   r    ZScriptCountrS   )Z	fontTablegsubZsrecZlangrecr   r   r   r   q  s0    





r   c                 C   sd   t  }g }| D ]H\}}g }|D ](}tt| }|| || q|||f q|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   r3   r4   r5   r    add)r#   r%   Z	condSubstr&   ZsubstitutionMapsr   substitutionMapsubstr   r   r   r     s    
r   c           	      C   s   t | jj}i }t|D ]\}}|| ||< q|D ]@}t|}tt|g}| jj| | jj||  |u s2J q2t | jj| j_|S )zlBuild the lookups for the glyph substitutions, return a dict mapping
    the substitution to lookup indices.)	rX   rp   rq   r=   r-   r   r   r    LookupCount)	rs   r%   Z
firstIndexr   rB   ru   rv   ZsubstMaplookupr   r   r   r     s    r   c                 C   s"   t  }d|_| |_t| |_|S )z%Build the FeatureVariations subtable.   )ro   rS   rR   FeatureVariationRecordrX   ZFeatureVariationCount)rj   Zfvr   r   r   rg     s
    
rg   c                 C   s.   t  }| |_t  |_||j_|j  |S )zBuild a FeatureRecord.)ro   rU   rV   rc   rd   ZpopulateDefaults)r$   lookupListIndicesfrr   r   r   rW     s    

rW   c                 C   sP   t  }t  |_| |j_t| |j_t  |_d|j_||j_t||j_	|S )zBuild a FeatureVariationRecord.ry   )
ro   rz   ZConditionSetConditionTablerX   ZConditionCountFeatureTableSubstitutionrR   SubstitutionRecordZSubstitutionCount)rk   ZsubstitutionRecordsfvrr   r   r   rf     s    

rf   c                 C   s0   t  }| |_t  |_||j_t||j_|S )z'Build a FeatureTableSubstitutionRecord.)ro   ZFeatureTableSubstitutionRecordra   rc   rd   rX   rw   )ZfeatureIndexr{   ftsrr   r   r   re     s    
re   c                 C   s$   t  }d|_| |_||_||_|S )zBuild a ConditionTable.r
   )ro   r}   ZFormatZ	AxisIndexZFilterRangeMinValueZFilterRangeMaxValue)rQ   ZfilterRangeMinValueZfilterRangeMaxValuerl   r   r   r   rb     s    rb   c                 C   s^   dd t | jjD }|  dd |D | j_ttdd |D tt|}t| | dS )zSort the feature list by feature tag, and remap the feature indices
    elsewhere. This is needed after the feature list has been modified.
    c                 S   s   g | ]\}}|j ||fqS r   )rV   )r   rZ   fear   r   r   r     r   z#sortFeatureList.<locals>.<listcomp>c                 S   s   g | ]\}}}|qS r   r   r   rL   rZ   r   r   r   r   r     r   c                 S   s   g | ]\}}}|qS r   r   r   r   r   r   r     r   N)	r=   rT   rU   sortr-   ziprangerX   remapFeatures)r   ZtagIndexFeafeatureRemapr   r   r   rY     s
     rY   c           
      C   s   t | jjD ]H\}}|jj}|dur.t|| t |jjD ]\}}|j}t|| q:qt| dr| j	dur| j	j
D ]}|jjD ]}	||	j |	_q~qrdS )z7Go through the scripts list, and remap feature indices.NrS   )r=   r[   r\   r]   r^   _remapLangSysr`   rP   hasattrrS   rz   r~   r   ra   )
r   r   ZscriptIndexscriptZdefaultLangSysZlangSysRecordIndexZ
langSysRecri   r   r   r   r   r   r     s    
r   c                    s0   | j dkr | j  | _  fdd| jD | _d S )Nrn   c                    s   g | ]} | qS r   r   )r   rZ   r   r   r   r     r   z!_remapLangSys.<locals>.<listcomp>)rr   ra   )ri   r   r   r   r   r     s    
r   __main__N)r   )r   ))__doc__ZfontTools.misc.dictToolsr   ZfontTools.misc.intToolsr   ZfontTools.ttLibr   ZfontTools.ttLib.tablesr   ro   ZfontTools.otlLib.builderr   r   collectionsr	   errorsr   r   r'   r   r   r>   r1   r!   r   r   r   rg   rW   rf   re   rb   rY   r   r   __name__doctestsysexittestmodfailedr   r   r   r   <module>   s6   
9wO
D!	



