a
    ZXhŎ                     @   s   d Z ddlZddl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 edZg d	Zd
d Zdd ZG dd dejZG dd dZdddZedkrddlZee  dS )u6  MS VOLT ``.vtp`` to AFDKO ``.fea`` OpenType Layout converter.

Usage
-----

To convert a VTP project file:


.. code-block:: sh

    $ fonttools voltLib.voltToFea input.vtp output.fea

It is also possible convert font files with `TSIV` table (as saved from Volt),
in this case the glyph names used in the Volt project will be mapped to the
actual glyph names in the font files when written to the feature file:

.. code-block:: sh

    $ fonttools voltLib.voltToFea input.ttf output.fea

The ``--quiet`` option can be used to suppress warnings.

The ``--traceback`` can be used to get Python traceback in case of exceptions,
instead of suppressing the traceback.


Limitations
-----------

* Not all VOLT features are supported, the script will error if it it
  encounters something it does not understand. Please report an issue if this
  happens.
* AFDKO feature file syntax for mark positioning is awkward and does not allow
  setting the mark coverage. It also defines mark anchors globally, as a result
  some mark positioning lookups might cover many marks than what was in the VOLT
  file. This should not be an issue in practice, but if it is then the only way
  is to modify the VOLT file or the generated feature file manually to use unique
  mark anchors for each lookup.
* VOLT allows subtable breaks in any lookup type, but AFDKO feature file
  implementations vary in their support; currently AFDKO’s makeOTF supports
  subtable breaks in pair positioning lookups only, while FontTools’ feaLib
  support it for most substitution lookups and only some positioning lookups.
    N)StringIO)TopologicalSorter)ast)TTFont
TTLibError)ParserzfontTools.voltLib.voltToFea)GDEFGSUBGPOSc                 C   sV   g }t | ttfr,| D ]}|t| qn&t| drH|t| j n
||  |S )Nenum)
isinstancetuplelistextend_flatten_grouphasattrr   append)groupretitem r   `/var/www/viveiro_mudafortebrasil/venv/lib/python3.9/site-packages/fontTools/voltLib/voltToFea.pyr   =   s    

r   c                    s:   dd | D  dd | D }t |} fdd| D S )Nc                 S   s   i | ]}|j  |qS r   )namelower.0r   r   r   r   
<dictcomp>M       zsort_groups.<locals>.<dictcomp>c                 S   s&   i | ]}|j  d d t|D qS )c                 S   s"   g | ]}t |tjr|j qS r   )r   VAst	GroupNamer   r   r   xr   r   r   
<listcomp>O   s   z*sort_groups.<locals>.<dictcomp>.<listcomp>)r   r   r   r   r   r   r   r   N   s   c                    s   g | ]} | qS r   r   )r   r   	group_mapr   r   r"   W   r   zsort_groups.<locals>.<listcomp>)r   Zstatic_order)groupsgraphZsorterr   r#   r   sort_groupsL   s    r'   c                       s   e Zd Zd fdd	Z  ZS )LookupFNc                    s   t  ||| g | _d S N)super__init__chained)selfr   use_extensionlocation	__class__r   r   r+   [   s    zLookup.__init__)FN)__name__
__module____qualname__r+   __classcell__r   r   r0   r   r(   Z   s   r(   c                   @   s   e Zd ZedZedZd3ddZdd Zdd	 Z	d4ddZ
dd Zd5ddZdd Zdd Zdd Zd6ddZdd Zdd Zdd Zdd  Zd7d!d"Zd#d$ Zd%d& Zd'd( Zd)d* Zd+d, Zd-d. Zd/d0 Zd1d2 ZdS )8	VoltToFeaz[^A-Za-z_0-9.]z[^A-Za-z_0-9.\-]Nc                 C   s   t |tjr|d  | _| _nd | | _| _|| _i | _d | _i | _i | _	i | _
i | _t | _i | _i | _i | _i | _i | _i | _d S r)   )r   r   ZVoltFile_doc_file_or_path_font
_glyph_map_glyph_order_gdef_glyphclasses	_features_lookupsset_marks
_ligatures_markclasses_anchors	_settings_lookup_names_class_names)r-   file_or_pathfontr   r   r   r+   d   s"    zVoltToFea.__init__c                 C   sD   || j vr:| jd|}|| j  v r0|d7 }q|| j |< | j | S N_)rF   _NOT_LOOKUP_NAME_REsubvaluesr-   r   resr   r   r   _lookupName~   s    


zVoltToFea._lookupNamec                 C   sD   || j vr:| jd|}|| j  v r0|d7 }q|| j |< | j | S rJ   )rG   _NOT_CLASS_NAME_RErM   rN   rO   r   r   r   
_className   s    


zVoltToFea._classNameFc                 C   s  |j D ]}t|tjr| | qdd |j D }t|D ]}| | q:|j D ]~}t|tjrtd|v r| | qPt|tj	r| 
|| qPt|tjtjfrqPt|tjr| | qPt|tjsPt|qP|j D ]>}t|tjr|jrd|vrq|jr
d|vr
q| | qd S )Nc                 S   s   g | ]}t |tjr|qS r   )r   r   GroupDefinition)r   sr   r   r   r"      r   z0VoltToFea._collectStatements.<locals>.<listcomp>r
   r	   )
statementsr   r   ZGlyphDefinition_glyphDefinitionr'   _groupDefinitionZAnchorDefinition_anchorDefinitionZSettingDefinition_settingDefinitionrT   ZScriptDefinition_scriptDefinitionZLookupDefinitionNotImplementedErrorposrM   _lookupDefinition)r-   doctablesignore_unsupported_settings	statementr%   r   r   r   r   _collectStatements   s2    



zVoltToFea._collectStatementsc              	      s4  t  }|j} jr4|t d | j   jrh|t d |dd t	 j
 D   jr|t d  j D ]}||j || q j }|D ]n}|| }|D ]F}|| }	|	D ]}
 fdd|	|
 D |	|
< qdd	 |	
 D ||< qd
d	 |
 D ||< qdd	 |
 D }|r|t d |
 D ]B\}}t |}t	|dd d}|dkrt|dkrtd |d d }|D ]}|dkr|jt | t	|| dd d}|dkr
t|dkr
td |d d }|D ]v}
|dkrJ|
dkr*dnd}|jt j|
d|d || |
 D ]*} j|  }t |}|j| qVqq|| qR jr0d|v r0g }dD ]V}| jv rd|  }t | j| }|| |t | n
|d  qt d}|jt j|  || |S )Nz# Glyph classesz
# Mark classesc                 s   s   | ]}|d  V  qdS    Nr   )r   cr   r   r   	<genexpr>   r   z.VoltToFea._buildFeatureFile.<locals>.<genexpr>z

# Lookupsc                    s   g | ]}|   jv r|qS r   )r   r?   r   lr-   r   r   r"      s   z/VoltToFea._buildFeatureFile.<locals>.<listcomp>c                 S   s   i | ]\}}|r||qS r   r   )r   tri   r   r   r   r      r   z/VoltToFea._buildFeatureFile.<locals>.<dictcomp>c                 S   s   i | ]\}}|r||qS r   r   )r   rk   rU   r   r   r   r      r   c                 S   s   i | ]\}}|r||qS r   r   )r   rk   fr   r   r   r      r   z
# Featuresc                 S   s   | dkrdS dS )NZDFLTr   re   r   kr   r   r   <lambda>   r   z-VoltToFea._buildFeatureFile.<locals>.<lambda>)keyZaaltre   zvFEA syntax does not allow script statements in 'aalt' feature, so only lookups from the first script will be included.c                 S   s   | dkrdS dS )Ndfltr   re   r   rm   r   r   r   ro      r   zzFEA syntax does not allow language statements in 'aalt' feature, so only lookups from the first language will be included.rq   TF   )include_defaultr   ZBASEMARKLIGATUREZ	COMPONENTZGDEF_)r   ZFeatureFilerV   r=   r   Commentr   rN   rC   sorteditemsr?   r,   r>   copyZFeatureBlocklenlogwarningZScriptStatementZLanguageStatementljustr   ZLookupReferenceStatementr<   GlyphClassDefinitionGlyphClassNameZ
TableBlockZGlyphClassDefStatement)r-   r`   r_   rV   lookupfeaturesZfeature_tagscriptsZ
script_taglangsZlanguage_tagfeatureZscript_tagsZlanguage_tagsrs   r   Z	lookuprefclasses	classname
glyphclassZgdefr   rj   r   _buildFeatureFile   s    








zVoltToFea._buildFeatureFilec                 C   sb   | j d u rt| j | _ | j }|d u r,t}| jd urB| j | _| ||| | 	|}|
 S r)   )r7   
VoltParserr8   parseTABLESr9   ZgetGlyphOrderr;   rc   r   ZasFea)r-   r`   ra   r_   fear   r   r   convert
  s    


zVoltToFea.convertc                 C   s6   z
|j }W n ty    |}Y n0 t| j||S r)   )glyphAttributeErrorr   	GlyphNamer:   get)r-   r   r   r   r   r   
_glyphName  s
    

zVoltToFea._glyphNamec                 C   s6   z
|j }W n ty    |}Y n0 t| j|  S r)   )r   r   r   r   r=   r   )r-   r   r   r   r   r   
_groupName  s
    

zVoltToFea._groupNamec                    s    fdd|  D S )Nc                    s*   g | ]"}t |ttjfr" |n|qS r   )r   strr   r   r   r    rj   r   r   r"   '  s   z'VoltToFea._glyphSet.<locals>.<listcomp>glyphSet)r-   r   r   rj   r   	_glyphSet&  s    
zVoltToFea._glyphSetc                 C   s   g }|D ]}t |tjr*|| | qt |tjrH|| | qt |tjr| j|j	dd}|rt|
| q|t| qt |tjr| |}|r|
| q|t| qt|q|S NTflatten)r   r   r   r   r   r   r   Enum	_coverager   r   r   
GlyphClassRanger   r\   )r-   coverager   ry   r   r   r   r   r   ,  s$    

zVoltToFea._coveragec                 C   sJ   g }|D ]<}| j |dd}t|dkr2t|}n|d }|| q|S )NTr   re   r   )r   r{   r   r   r   )r-   contextoutr   r   r   r   r   _contextC  s    zVoltToFea._contextc                 C   sH   |  |j}| j|jjdd}t|}t||}|| j|j < d S r   )	rS   r   r   r   r   r   r   r=   r   )r-   r   r   glyphsr   Zclassdefr   r   r   rX   N  s
    
zVoltToFea._groupDefinitionc                 C   s   z| j |j | j|j< W n ty*   Y n0 |jdv rn|j| jvrRt | j|j< | j|j j	
| |j |jdkr| j|j n|jdkr|j| j|j< d S )Nrt   ru   rv   )r;   idr:   r   	TypeErrortyper<   r   r   r   r   r   rA   add
componentsrB   )r-   r   r   r   r   rW   U  s    


zVoltToFea._glyphDefinitionc                 C   s   |j }|jD ]}|j }|jD ]v}dd |jD }|j }|| jvrJi | j|< || j| vrfi | j| |< || j| | vs|J | | j| | |< qqd S )Nc                 S   s   i | ]}| d d dqS )\r   T)splitrh   r   r   r   r   j  r   z/VoltToFea._scriptDefinition.<locals>.<dictcomp>)tagr   r   lookupsr>   keys)r-   scriptZstaglangltagr   r   Zftagr   r   r   r[   e  s    



zVoltToFea._scriptDefinitionc                 C   s6   |j dr|j| j|j < n|s2td|j   d S )NZ	COMPILER_zUnsupported setting ignored: )r   
startswithvaluerE   r|   r}   )r-   ZsettingZignore_unsupportedr   r   r   rZ   s  s    zVoltToFea._settingDefinitionc                 C   sV   |\}}}}}}|r|  pd }|r,|  p.d }	|r<|  p>d }
tj||||	|
|dS )N)Z
xPlacementZ
yPlacementZxAdvanceZ
xPlaDeviceZ
yPlaDeviceZ
xAdvDevice)ry   r   ZValueRecord)r-   
adjustmentadvdxdyadv_adjust_bydx_adjust_bydy_adjust_byZ
adv_device	dx_device	dy_devicer   r   r   _adjustmenty  s    zVoltToFea._adjustmentc           
      C   sZ   |\}}}}}}|rJ |r$|  p&d }|r4|  p6d }	tj|pBd|pHd|pNd |	pTd dS )Nr   )ZxDeviceTableZyDeviceTable)ry   r   ZAnchor)
r-   r   r   r   r   r   r   r   r   r   r   r   r   _anchor  s    zVoltToFea._anchorc                 C   s   |j }|j}| |j}|| jvr,i | j|< |drT|d d |dd    }n| }|| j| vrxi | j| |< || j| | |j< d S )NMARK_   )r   Z
glyph_namer   r]   rD   r   r   	component)r-   Z	anchordef
anchorname	glyphnameanchorr   r   r   rY     s    


zVoltToFea._anchorDefinitionc           +   
      s  |j }|j}t|tjr|j D ]\\}}\}}|j|d  }	|j|d  }
d}|	|
 D ]}t|tj	sZd}qZ 
|	} 
|
} |} |}t|dksJ t|dksJ |tj|d ||d ||d q"nt|tjrH|jD ]N\}} 
|} |}t|dks"J |t|d |fgg g d qnt|tjri }t }|jD ]\}} | d|j }t|}| }t }|D ]}||  q||s|| |sؐqf|| |D ]D} |} j| d|  d }t |||} |  j!||f< q|j"D ]L}!|! D ]<}"|"|vrTg ||"< ||f||" vr>||" ||f q>q2qft# fdd	|D }#t# fd
d	|D }$|D ]}"d}%|#r̈ j$|" }%dd t%|%D }||" D ]f\}}t|}t%d|%d D ]B}&|& j|" | v r j|" | |& }||&d  ||f qq |"}!|$rpt&|!|d }n$|#rt'|!|}nt(|!|d }|| qn0t|tj)rg }'|j*D ],}|D ] }!|! D ]}"|'|" qҐqƐqg }(|j+D ],}|D ] }!|! D ]}"|(|" q
qq|'D ]f}" |"} j|" d d })d }*|"|(v rx j|" d d }*|(,|(-|" |t.||)|* q(|(D ]6}" |"} j|" d d }*|t.|d |* qnt/|d S )Nre   FTr   )
enumerated.r   c                 3   s   | ]}| j v V  qd S r)   )rB   r   nrj   r   r   rg     r   z(VoltToFea._gposLookup.<locals>.<genexpr>c                 3   s   | ]}| j v V  qd S r)   )rA   r   rj   r   r   rg     r   c                 S   s   g | ]}g qS r   r   )r   rK   r   r   r   r"     r   z)VoltToFea._gposLookup.<locals>.<listcomp>entryexit)0rV   r]   r   r   PositionAdjustPairDefinitionadjust_pairry   coverages_1coverages_2r   r   r   r{   r   r   ZPairPosStatementPositionAdjustSingleDefinitionadjust_singleZSinglePosStatementPositionAttachDefinitionr@   coverage_torS   r   Z	MarkClassr   updater   
isdisjointdifference_updater   rD   ZMarkClassDefinitionrC   r   allrB   rangeZMarkMarkPosStatementZMarkLigPosStatementZMarkBasePosStatementZPositionAttachCursiveDefinitionZcoverages_enterZcoverages_exitpopindexZCursivePosStatementr\   )+r-   r   	fealookuprV   r]   idx1idx2pos1pos2Z
coverage_1Z
coverage_2r   r   glyphs1glyphs2Zrecord1Zrecord2abr   recordZanchorsZallmarksr   r   r   Z	markclassZmarksmarkr   r   r   Zmarkdefbaser   Zis_ligatureZis_markr   r   Zenter_coverageZexit_coverager   r   r   rj   r   _gposLookup  s    






















zVoltToFea._gposLookupc                 C   s  |j }|j}t|tjr|j D ]\\}	}
\}}| |j|	d  }| |j	|
d  }t
|dksjJ t
|dkszJ |d |d f}|rt|||fg}nt|||||g}|| q"nt|tjr<t g}|jD ] \}}|d | j|dd q|rt|||fg}nt||||g}|| nt|tjrt g}|jD ]"\}}|d | j|dd qZ|rt|||fg}nt||||g}|| nt|d S )Nre   r   Tr   )rV   r]   r   r   r   r   ry   r   r   r   r{   r   ZIgnorePosStatementZChainContextPosStatementr   r   r   r   r   r   r   r\   )r-   r   prefixsuffixignorer   r,   rV   r]   r   r   r   r   r   r   r   rb   r   rK   r   r   r   r   _gposContextLookup+  sH    



zVoltToFea._gposContextLookupc                    sR  |j }|j}t|tjri }|j D ]\}}|r8|sb|j\}}	}
t	| d|	 d|
 d q(
|}
|}t|dksJ t|d  |d  D ].\}}|t|g t| qq(| D ](\}}tg |g t|}|| qd S |j D ]8\}}|r(|sT|j\}}	}
t	| d|	 d|
 d q
|}
|}t|tjrt|dksJ t|dksJ |t||g g d qt|tjrȐqt|tjrt|dksJ |tg |d g | qt|tjrBt|dks&J tg |g |d d}tdd |D   dkr6t fdd|D stJ d	d
 |D } fdd
|D }|d  }t|dkr|d g  }t| ksJ |td|  tg ||R  D ]<}fdd
|D }|tg |d d g |d d qn
|| nt|qd S )N:: Ignoring empty substitutionre   r   Fc                 s   s   | ]}t | V  qd S r)   r{   r   r    r   r   r   rg     r   z(VoltToFea._gsubLookup.<locals>.<genexpr>c                 3   s"   | ]}t |  d fv V  qdS rd   r   r    r   r   r   rg     r   c                 S   s   g | ]}|  qS r   r   r    r   r   r   r"     r   z)VoltToFea._gsubLookup.<locals>.<listcomp>c                    s*   g | ]"}t |d kr"|d g  n|qS )re   r   )r{   r    r   r   r   r"     r   # c                    s   g | ]}  |qS r   )r   r    rj   r   r   r"     r   ) rV   rM   r   r   SubstitutionAlternateDefinitionmappingry   r/   r|   r}   r   r{   zipr   
setdefaultr   r   r   r   ZAlternateSubstStatementr   SubstitutionSingleDefinitionZSingleSubstStatement+SubstitutionReverseChainingSingleDefinitionSubstitutionMultipleDefinitionZMultipleSubstStatementSubstitutionLigatureDefinitionZLigatureSubstStatementmaxr   rw   r\   )r-   r   r   rV   rM   Z
alternatesrp   valpathlinecolumnr   replacementsZ	src_glyphZ
repl_glyphr   rb   replacementZzippedr   )r   r-   r   _gsubLookupY  s    





zVoltToFea._gsubLookupc              	   C   sn  |j }|j}t|tjr|j D ]d\}	}
|	r2|
s\|j\}}}t	| d| d| d q"| 
|	}| 
|
}|t|||| q"g |_d S t|tjtjtjtjfstt|g }|j D ]P\}	}
|	r|
s|j\}}}t	| d| d| d q|| j
|	dd qt|dkr2t|g}|rR|t|||fg n|t||||g d S )Nr   r   Tr   re   )rV   rM   r   r   r   r   ry   r/   r|   r}   r   r   r   Z ReverseChainSingleSubstStatementr,   r   r   r   r   r\   r   r   r{   r   ZIgnoreSubstStatementZChainContextSubstStatement)r-   r   r   r   r   r   r,   rV   rM   rp   r   r   r   r   r   r   r   r   r   _gsubContextLookup  sP    

	
zVoltToFea._gsubContextLookupc              	   C   s
  d }d }d}|j dkr|dO }|js,|dO }|js<|dO }n0t|jtrV| |j}n|jd url| |j}d }|s|d us|d urt|||}d}| j	
drd}d	|jv rX|jd	d }| | jvrt| ||d
}|d ur|j| |jtd|j  n6| j|  }|jt  |jtd|j  || j| < n:t| |j|d
}|d ur|j| || j|j < |jd ur|jtd|j  g }	|jD ]^}
| |
j}| |
j}|
jdk}|	|||g |rt|jdkr|	g g dg q|	rtj| |jd |d
}|j| |jd urf| || n|j d ur~| !|| |	D ]N\}}}|jd ur| "|||||| n |j d ur| #|||||| qn2|jd ur| || n|j d ur| !|| d S )Nr   ZRTLre         FZCOMPILER_USEEXTENSIONLOOKUPSTr   )r.   r   ZEXCEPT_CONTEXTz chained)$	directionZprocess_baseZprocess_marksr   r   r   Zmark_glyph_setr   ZLookupFlagStatementrE   r   r   r   r   r?   r(   rQ   rV   r   rw   ZSubtableStatementcommentsr   r   leftrightZex_or_inr{   LookupBlockr,   rM   r   r]   r   r  r   )r-   r   Zmark_attachementZmark_filteringflagsZlookupflagsr.   r   r   Zcontextsr   r   r   r   r,   r   r   r   r^     s    







zVoltToFea._lookupDefinition)N)F)NF)F)F)r2   r3   r4   recompilerL   rR   r+   rQ   rS   rc   r   r   r   r   r   r   r   rX   rW   r[   rZ   r   r   rY   r   r   r   r  r^   r   r   r   r   r6   `   s4   



$X


 ._2r6   c                 C   s  ddl }ddlm} ddlm} |jdtjd}|jdd|d	d
 |jdd|dd
 |jdddt	ddd |jddddd |jdddd |
| }||jrdndd |j}d}z:t|}d|v rt|d jd}ntd  W d!S W n ty   Y n0 t||}z||j}	W n ty }
 zr|jr: t|
jd d"d}d#|
 d$}|r|\}}}t| d%| d%| d&|  n
t| W Y d}
~
d!S d}
~
0 0 t|jd'}||	 W d   n1 s0    Y  dS )(z'Convert MS VOLT to AFDKO feature files.r   N)Path)configLoggerzfonttools voltLib.voltToFea)descriptioninputZINPUTzinput font/VTP file to process)metavarr   helpfeaturefileZOUTPUTzoutput feature filez-tz--tabler   r`   z:List of tables to write, by default all tables are written)actionchoicesdestr  z-qz--quiet
store_truezSuppress non-error messages)r  r  z--tracebacku   Don’t catch exceptionsERRORINFO)levelZTSIVzutf-8z6"TSIV" table is missing, font was not saved from VOLT?re   r/   "z" is not supportedr   z: w)argparsepathlibr  Z	fontToolsr  ArgumentParsermain__doc__add_argumentr   
parse_argsquietr  r   r   datadecoder|   errorr   r6   r   r`   r\   	tracebackgetattrargsopenr  write)r)  r  r  r  parseroptionsrH   rI   	converterr   er/   messager   r   r   Zfeafiler   r   r   r  J  sj    




"
r  __main__)N)r   loggingr
  ior   Zgraphlibr   ZfontTools.feaLibr   ZfontTools.ttLibr   r   ZfontTools.voltLibr   ZfontTools.voltLib.parserr   r   	getLoggerr|   r   r   r'   r  r(   r6   r  r2   sysr   r   r   r   r   <module>   s.   -
     o
B