o
    Ae1o                     @   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m	Z	 ddl
mZ ddlmZ edZg dZG d	d
 d
ejZG dd dZG dd dZdddZedkr_ddlZee  dS dS )u  MS VOLT ``.vtp`` to AFDKO ``.fea`` OpenType Layout converter.

Usage
-----

To convert a VTP project file:


    $ 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:

    $ 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)ast)TTFont
TTLibError)ParserzfontTools.voltLib.voltToFea)GDEFGSUBGPOSc                   @   s   e Zd ZdddZdS )MarkClassDefinition c                 C   s.   d}t | dds|d7 }|tj| |7 }|S )Nr   usedF#)getattrr   r
   asFea)selfindentres r   \/home/www/facesmatcher.com/pyenv/lib/python3.10/site-packages/fontTools/voltLib/voltToFea.pyr   9   s
   zMarkClassDefinition.asFeaN)r   )__name__
__module____qualname__r   r   r   r   r   r
   8   s    r
   c                   @   s   e Zd Zdd Zdd ZdS )Groupc                 C   s$   |j  | _ dd |jjD | _d S )Nc                 S   s"   g | ]}t |tjr|j qS r   )
isinstanceVAst	GroupNamegrouplower).0xr   r   r   
<listcomp>E   s
    z"Group.__init__.<locals>.<listcomp>)namer   enumgroups)r   r   r   r   r   __init__C   s   zGroup.__init__c                 C   sH   | j |jv rdS |j | jv rdS | jr|jsdS | js |jr"dS d S d S )NTF)r!   r#   )r   otherr   r   r   __lt__I   s   zGroup.__lt__N)r   r   r   r$   r&   r   r   r   r   r   B   s    r   c                   @   s   e Zd ZedZedZd0d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d&d' Zd(d) Zd*d+ Zd,d- Zd.d/ ZdS )1	VoltToFeaz[^A-Za-z_0-9.]z[^A-Za-z_0-9.\-]Nc                 C   s`   || _ || _i | _d | _i | _i | _i | _i | _t | _	i | _
i | _i | _i | _i | _i | _d S N)_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$   X   s   
zVoltToFea.__init__c                 C   P   || j vr#| jd|}|| j  v r|d7 }|| j  v s|| j |< | j | S N_)r7   _NOT_LOOKUP_NAME_REsubvaluesr   r!   r   r   r   r   _lookupNameo      


zVoltToFea._lookupNamec                 C   r;   r<   )r8   _NOT_CLASS_NAME_REr?   r@   rA   r   r   r   
_classNamew   rC   zVoltToFea._classNamec                 C   s  dd |j D }t|dd dD ]}| | q|j D ]G}t|tjr)| | qt|tjr9d|v r8| | qt|tj	rE| 
| qt|tjrLqt|tjrX| | qt|tjsbt|q|j D ]}t|tjr|jrvd|vrvqf|jr~d|vr~qf| | qfd S )Nc                 S   s   g | ]
}t |tjr|qS r   )r   r   GroupDefinition)r   sr   r   r   r           z0VoltToFea._collectStatements.<locals>.<listcomp>c                 S   s   t | S r(   )r   )r   r   r   r   <lambda>   s    z.VoltToFea._collectStatements.<locals>.<lambda>keyr	   r   )
statementssorted_groupDefinitionr   r   ZGlyphDefinition_glyphDefinitionZAnchorDefinition_anchorDefinitionZSettingDefinition_settingDefinitionrF   ZScriptDefinition_scriptDefinitionZLookupDefinitionNotImplementedErrorposr?   _lookupDefinition)r   doctablesr#   	statementr   r   r   _collectStatements   s8   



zVoltToFea._collectStatementsc              	      s  t  }|j} jr|t d | j   jr4|t d |dd t	 j
 D   jrU|t d  j D ]}|t|dg  || qD j }|D ]7}|| }|D ]#}|| }	|	D ]}
 fdd|	|
 D |	|
< qld	d
 |	
 D ||< qddd
 |
 D ||< q\dd
 |
 D }|r|t d |
 D ]a\}}t |}t	|dd d}|D ]H}|jt | t	|| dd d}|D ]0}
|
dkrdnd}|jt j|
|d || |
 D ]} j|  }t |}|j| qqq|| q jr[d|v r[g }dD ],}| jv rAd|  }t | j| }|| |t | q|d  qt d}|jt j|  || |S )Nz# Glyph classesz
# Mark classesc                 s   s    | ]}|d  V  qdS )   Nr   )r   cr   r   r   	<genexpr>   s    z.VoltToFea._buildFeatureFile.<locals>.<genexpr>z

# Lookupstargetsc                    s   g | ]}|   jv r|qS r   )r   r0   r   lr   r   r   r       s    z/VoltToFea._buildFeatureFile.<locals>.<listcomp>c                 S      i | ]	\}}|r||qS r   r   )r   tr_   r   r   r   
<dictcomp>       z/VoltToFea._buildFeatureFile.<locals>.<dictcomp>c                 S   ra   r   r   )r   rb   rG   r   r   r   rc      rd   c                 S   ra   r   r   )r   rb   fr   r   r   rc      rd   z
# Featuresc                 S      | dkrdS dS )NZDFLTr   rZ   r   kr   r   r   rI          z-VoltToFea._buildFeatureFile.<locals>.<lambda>rJ   c                 S   rf   )Ndfltr   rZ   r   rg   r   r   r   rI      ri   rj   TF)include_defaultr   ZBASEMARKLIGATUREZ	COMPONENTZGDEF_)r   ZFeatureFilerL   r.   appendCommentextendr@   r4   rM   itemsr0   r   r/   copyZFeatureBlockZScriptStatementZLanguageStatementr   ZLookupReferenceStatementr-   GlyphClassDefinitionGlyphClassNameZ
TableBlockZGlyphClassDefStatement)r   rW   rV   rL   lookupfeaturesftagscriptsstaglangsltagfeatureZstagsZltagsrk   r!   Z	lookuprefclasses	classname
glyphclassZgdefr   r`   r   _buildFeatureFile   sp   


	


zVoltToFea._buildFeatureFilec                 C   sN   t | j }|d u rt}| jd ur| j | _| || | |}|	 S r(   )

VoltParserr)   parseTABLESr*   ZgetGlyphOrderr,   rY   r   r   )r   rW   rV   fear   r   r   convert   s   

zVoltToFea.convertc                 C   s6   z|j }W n ty   |}Y nw t| j||S r(   )glyphAttributeErrorr   	GlyphNamer+   get)r   r   r!   r   r   r   
_glyphName      
zVoltToFea._glyphNamec                 C   s6   z|j }W n ty   |}Y nw t| j|  S r(   )r   r   r   ru   r.   r   )r   r   r!   r   r   r   
_groupName   r   zVoltToFea._groupNamec                 C   s   g }|D ]B}t |tjr|| | qt |tjr$|| | qt |tjr3|| | qt |tj	rC||j
|jf qt||S r(   )r   r   r   ro   r   r   r   Enum_enumRangestartendrS   )r   coveragerr   itemr   r   r   	_coverage   s   zVoltToFea._coveragec                 C   s   t | |jS r(   )r   
GlyphClassr   r"   )r   r"   r   r   r   r     s   zVoltToFea._enumc                 C   s:   g }|D ]}|  |}t|ttfs|g}|| q|S r(   )r   r   tuplelistrq   )r   contextoutr   r   r   r   r   _context  s   
zVoltToFea._contextc                 C   s8   |  |j}| |j}t||}|| j|j < d S r(   )rE   r!   r   r"   r   rt   r.   r   )r   r   r!   glyphsr   r   r   r   rN     s   zVoltToFea._groupDefinitionc                 C   s   z| j |j | j|j< W n	 ty   Y nw |jdv r7|j| jvr)t | j|j< | j|j j	
| |j |jdkrE| j|j d S |jdkrS|j| j|j< d S d S )Nrl   rm   rn   )r,   idr+   r!   	TypeErrortyper-   r   r   r   ro   r   r2   add
componentsr3   )r   r   r   r   r   rO     s   


zVoltToFea._glyphDefinitionc                 C   s   |j }|jD ]D}|j }|jD ];}dd |jD }|j }|| jvr%i | j|< || j| vr3i | j| |< || j| | vs>J | | j| | |< qqd S )Nc                 S   s   i | ]
}| d d dqS )\r   T)splitr^   r   r   r   rc   3  rH   z/VoltToFea._scriptDefinition.<locals>.<dictcomp>)tagr{   rw   lookupsr/   keys)r   scriptrz   langr|   r}   r   rx   r   r   r   rR   .  s   



zVoltToFea._scriptDefinitionc                 C   s4   |j dr|j| j|j < d S td|j   d S )NZ	COMPILER_zUnsupported setting ignored: )r!   
startswithvaluer6   logwarning)r   Zsettingr   r   r   rQ   <  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)rr   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   _adjustmentB  s   zVoltToFea._adjustmentc           
      C   sZ   |\}}}}}}|rJ |r|  pd }|r|  pd }	tj|p!d|p$d|p'd |	p*d dS )Nr   )ZxDeviceTableZyDeviceTable)rr   r   ZAnchor)
r   r   r   r   r   r   r   r   r   r   r   r   r   _anchorR  s   zVoltToFea._anchorc           	      C   s   |j }|j}| |j}|dr9d|ddd  }t| 	|}| 
|}t|||}|| j||f< d S || jvrCi | j|< || j| vrQi | j| |< || j| | |j< d S )NMARK_r=   rZ   )r!   Z
glyph_namer   rT   r   joinr   r   	MarkClassrE   r   r
   r4   r5   	component)	r   Z	anchordefZ
anchornameZ	glyphnameanchorr!   	markclassr   Zmarkdefr   r   r   rP   `  s   



zVoltToFea._anchorDefinitionc           &   
   C   s2  |j }|j}t|tjrp|j D ]\\\}}\}}|j|d  }	|j|d  }
d}|	|
 D ]
}t|tj	s7d}q-| 
|	}| 
|
}| |}| |}t|dksTJ t|dks\J |tj|d ||d ||d qd S t|tjr|jD ]&\}}| 
|}| |}t|dksJ |t|d |fgg g d qyd S t|tjri }|jD ]F\}}|D ]}| D ]}|d| f}d| j| _qqt| |}|jD ]}| D ]}||vrg ||< ||| vr|| | qqq|D ]}d}|| jv r| j| }g }|| D ]B}t| |}td|d D ]/}t||k r+|g  d }|| j| | v r@| j| | | }||d  ||f qq| |}|| jv rct ||d }n|| jv rpt!||}nt"||d }|| qd S t|tj#rg } |j$D ]}!|!D ]}| D ]}| | qqqg }"|j%D ]}!|!D ]}| D ]}|"| qqq| D ]3}| |}#| j| d d }$d }%||"v r| j| d d }%|"&|"'| |t(|#|$|% q|"D ]}| |}#| j| d d }%|t(|#d |% qd S t)|)	NrZ   FTr   )
enumeratedr   entryexit)*rL   rT   r   r   PositionAdjustPairDefinitionadjust_pairrr   coverages_1coverages_2r   r   r   lenro   r   ZPairPosStatementPositionAdjustSingleDefinitionadjust_singleZSinglePosStatementPositionAttachDefinitioncoverage_toZglyphSetr4   r   r   rE   r   r3   ranger5   r   r2   ZMarkMarkPosStatementZMarkLigPosStatementZMarkBasePosStatementZPositionAttachCursiveDefinitionZcoverages_enterZcoverages_exitpopindexZCursivePosStatementrS   )&r   rv   	fealookuprL   rT   idx1idx2pos1pos2Z
coverage_1Z
coverage_2r   r   glyphs1glyphs2Zrecord1Zrecord2abr   recordanchorsZmarksr   markr!   rK   r   baser   r   r   Zenter_coverager   Zexit_coverager   r   r   r   r   r   _gposLookupr  s   














zVoltToFea._gposLookupc                 C   s  |j }|jrJ |j}t|tjrj|j D ]Q\\}	}
\}}| |j	|	d  }| |j
|
d  }t|dks:J t|dksBJ |d |d f}|rVt|||fg}n||f}t||||}|| qd S t|tjrt g}|jD ]\}}| |}|d | qx|rt|||fg}n	t||||g}|| d S t|tjrt g}|jD ]\}}|d | | q|rt|||fg}n	t||||g}|| d S t|)NrZ   r   )rL   ZreversalrT   r   r   r   r   rr   r   r   r   r   r   ZIgnorePosStatementZChainContextPosStatementro   r   r   r   rq   r   r   rS   )r   rv   prefixsuffixignorer   targetlookuprL   rT   r   r   r   r   r   r   r   rX   r   r   r   r   r   r=   r   r   r   _gposContextLookup  sP   





zVoltToFea._gposContextLookupc              	   C   s  |j }|j}|j D ]\}	}
|	r|
s(|j\}}}t| d| d| d qd }| |	}| |
}|rB|||f}t	|g}nwt
|tjrbt|dksPJ t|dksXJ t|||||}nWt
|tjrt|dkspJ t|dksxJ t||||}n8t
|tjrt|dksJ t||d |||}nt
|tjrt|dksJ t||||d |}nt||| qd S )N:z: Ignoring empty substitutionrZ   r   )rL   r?   mappingrr   locationr   r   r   r   ZIgnoreSubstStatementr   r   ZSubstitutionSingleDefinitionr   ZSingleSubstStatementZ+SubstitutionReverseChainingSingleDefinitionZ ReverseChainSingleSubstStatementZSubstitutionMultipleDefinitionZMultipleSubstStatementZSubstitutionLigatureDefinitionZLigatureSubstStatementrS   ro   )r   rv   r   r   r   chainr   rL   r?   rK   valpathlinecolumnrX   r   ZreplacementsZchain_contextr   r   r   _gsubLookup  sL   



zVoltToFea._gsubLookupc              	   C   s  d }d }d}|j dkr|dO }|js|dO }|js|dO }nt|jtr+| |j}n|jd ur6| |j}d }|sB|d usB|d urIt|||}d|j	v r|j	
dd }| | jvr|t| |}|d uro|j| |jtd|j	  n| j|  }|jt  |jtd|j	  || j| < nt| |j	}|d ur|j| || j|j	 < |jd ur|jtd|j  g }|jr|jD ]0}	| |	j}
| |	j}|	jdk}||
||d	g |rt|jdkr|g g d	d
g qn	|g g d	d	g d }|D ]m\}
}}}|jd ur)| ||
|||| |jd ur| jdr9d
|_|
sE|sE|sE|ry|sm|d u rm| |j	d }t|}t |dg |_!|j!| | "|| | #||
|||| q| "|| qd S )Nr   ZRTLrZ         r   z# ZEXCEPT_CONTEXTFTZCOMPILER_USEEXTENSIONLOOKUPSz targetr]   )$	directionZprocess_baseZprocess_marksr   strr   Zmark_glyph_setr   ZLookupFlagStatementr!   r   r   r0   ZLookupBlockrB   rL   ro   rp   ZSubtableStatementcommentsr   r   leftrightZex_or_inr   r?   r   rT   r6   r   Zuse_extensionr   r]   r   r   )r   rv   Zmark_attachementZmark_filteringflagsZlookupflagsr!   r   Zcontextsr   r   r   r   r   r   Z
targetnamer   r   r   rU   =  s   








zVoltToFea._lookupDefinitionr(   )r   r   r   recompiler>   rD   r$   rB   rE   rY   r   r   r   r   r   r   r   rN   rO   rR   rQ   r   r   rP   r   r   r   rU   r   r   r   r   r'   T   s2    


!
B	n4)r'   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rQdndd |j}d}zt|}d|v rnt|d jd}ntd  W d!S W n	 ty   Y nw t||}z||j}	W nC ty }
 z7|jr t|
jd d"d}d#|
 d$}|r|\}}}t| d%| d%| d&|  nt| W Y d}
~
d!S d}
~
ww t|jd'}||	 W d   dS 1 sw   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--tablero   rW   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?rZ   r   "z" is not supportedr   z: w)argparsepathlibr   Z	fontToolsr   ArgumentParsermain__doc__add_argumentr   
parse_argsquietr   r   r   datadecoder   errorr   r'   r   rW   rS   	tracebackr   argsopenr   write)r  r  r   r   parseroptionsr9   r:   	converterr   er   messager   r   r   Zfeafiler   r   r   r    st   



"
"r  __main__r(   )r  loggingr   ior   ZfontTools.feaLibr   ZfontTools.ttLibr   r   ZfontTools.voltLibr   ZfontTools.voltLib.parserr   r   	getLoggerr   r   r
   r   r'   r  r   sysr   r   r   r   r   <module>   s,    )

    
AB