o
    _hŎ                     @   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rfddlZee  dS 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   sZ   g }t | ttfr| D ]	}|t| q|S t| dr&|t| j |S ||  |S )Nenum)
isinstancetuplelistextend_flatten_grouphasattrr   append)groupretitem r   O/var/www/html/myenv/lib/python3.10/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   s    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       zsort_groups.<locals>.<listcomp>)r   static_order)groupsgraph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   r2   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d4ddZdd Zdd Zdd Zdd  Zd4d!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 )6	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   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   P   || j vr#| jd|}|| j  v r|d7 }|| j  v s|| j |< | j | S N_)rI   _NOT_LOOKUP_NAME_REsubvaluesr/   r   resr   r   r   _lookupName~      


zVoltToFea._lookupNamec                 C   rM   rN   )rJ   _NOT_CLASS_NAME_RErQ   rR   rS   r   r   r   
_className   rV   zVoltToFea._classNameFc                 C   s  |j D ]}t|tjr| | qdd |j D }t|D ]}| | q|j D ]?}t|tjr:d|v r9| | q(t|tj	rG| 
|| q(t|tjtjfrQq(t|tjr]| | q(t|tjsgt|q(|j D ]}t|tjr|jr{d|vr{qk|jrd|vrqk| | qkd S )Nc                 S   s   g | ]
}t |tjr|qS r   )r   r   GroupDefinition)r   sr   r   r   r!          z0VoltToFea._collectStatements.<locals>.<listcomp>r
   r	   )
statementsr   r   GlyphDefinition_glyphDefinitionr)   _groupDefinitionAnchorDefinition_anchorDefinitionSettingDefinition_settingDefinitionrY   ScriptDefinition_scriptDefinitionLookupDefinitionNotImplementedErrorposrQ   _lookupDefinition)r/   doctablesignore_unsupported_settings	statementr&   r   r   r   r   _collectStatements   s<   





zVoltToFea._collectStatementsc              	      s&  t  }|j} jr|t d | j   jr4|t d |dd t	 j
 D   jrR|t d  j D ]}||j || qD j }|D ]7}|| }|D ]#}|| }	|	D ]}
 fdd|	|
 D |	|
< qidd	 |	
 D ||< qad
d	 |
 D ||< qYdd	 |
 D }|rD|t d |
 D ]\}}t |}t	|dd d}|dkrt|dkrtd |d d }|D ]l}|dkr|jt | t	|| dd d}|dkrt|dkrtd |d d }|D ];}
|dkr|
dkrdnd}|jt j|
d|d || |
 D ]} j|  }t |}|j| q%qq|| q jrd|v rg }dD ],}| jv rwd|  }t | j| }|| |t | qQ|d  qQt 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

# Lookupsc                    s   g | ]}|   jv r|qS r   )r   rB   r   lr/   r   r   r!      s    z/VoltToFea._buildFeatureFile.<locals>.<listcomp>c                 S      i | ]	\}}|r||qS r   r   )r   trt   r   r   r   r          z/VoltToFea._buildFeatureFile.<locals>.<dictcomp>c                 S   rv   r   r   )r   rw   rZ   r   r   r   r      rx   c                 S   rv   r   r   )r   rw   fr   r   r   r      rx   z
# Featuresc                 S      | dkrdS dS )NDFLTr   rp   r   kr   r   r   <lambda>       z-VoltToFea._buildFeatureFile.<locals>.<lambda>)keyaaltrp   zvFEA syntax does not allow script statements in 'aalt' feature, so only lookups from the first script will be included.c                 S   rz   )Ndfltr   rp   r   r|   r   r   r   r~      r   zzFEA syntax does not allow language statements in 'aalt' feature, so only lookups from the first language will be included.r   TF   )include_defaultr   BASEMARKLIGATURE	COMPONENTGDEF_)r   FeatureFiler\   r@   r   Commentr   rR   rF   sorteditemsrB   r.   rA   copyFeatureBlocklenlogwarningScriptStatementLanguageStatementljustr   LookupReferenceStatementr?   GlyphClassDefinitionGlyphClassName
TableBlockGlyphClassDefStatement)r/   rk   rj   r\   lookupfeaturesfeature_tagscripts
script_taglangslanguage_tagfeaturescript_tagslanguage_tagsr   r   	lookuprefclasses	classname
glyphclassgdefr   ru   r   _buildFeatureFile   s   







zVoltToFea._buildFeatureFilec                 C   sb   | j d u rt| j | _ | j }|d u rt}| jd ur!| j | _| ||| | 	|}|
 S r+   )r:   
VoltParserr;   parseTABLESr<   getGlyphOrderr>   rn   r   asFea)r/   rk   rl   rj   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   r   r@   r   )r/   r   r   r   r   r   
_groupName  r   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   ru   r   r   r!   '  s    z'VoltToFea._glyphSet.<locals>.<listcomp>glyphSet)r/   r   r   ru   r   	_glyphSet&  s   
zVoltToFea._glyphSetc                 C   s   g }|D ]^}t |tjr|| | qt |tjr$|| | qt |tjrC| j|j	dd}|r:|
| q|t| qt |tjr_| |}|rV|
| q|t| qt||S NTflatten)r   r   r   r   r   r   r   Enum	_coverager   r   r   
GlyphClassRanger   rg   )r/   coverager   r   r   r   r   r   r   ,  s$   
zVoltToFea._coveragec                 C   sJ   g }|D ]}| j |dd}t|dkrt|}n|d }|| q|S )NTr   rp   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   )	rX   r   r   r   r   r   r   r@   r   )r/   r   r   glyphsr   classdefr   r   r   r_   N  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 )Nr   r   r   )r>   idr=   r   	TypeErrortyper?   r   r   r   r   r   rD   add
componentsrE   )r/   r   r   r   r   r^   U  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)splitrs   r   r   r   r   j  r[   z/VoltToFea._scriptDefinition.<locals>.<dictcomp>)tagr   r   lookupsrA   keys)r/   scriptstaglangltagr   r   ftagr   r   r   re   e  s   



zVoltToFea._scriptDefinitionc                 C   s<   |j dr|j| j|j < d S |std|j   d S d S )N	COMPILER_zUnsupported setting ignored: )r   
startswithvaluerH   r   r   )r/   settingignore_unsupportedr   r   r   rc   s  s
   zVoltToFea._settingDefinitionc                 C   sV   |\}}}}}}|r|  pd }|r|  pd }	|r|  pd }
tj||||	|
|dS )N)
xPlacement
yPlacementxAdvance
xPlaDevice
yPlaDevice
xAdvDevice)r   r   ValueRecord)r/   
adjustmentadvdxdyadv_adjust_bydx_adjust_bydy_adjust_by
adv_device	dx_device	dy_devicer   r   r   _adjustmenty  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   )xDeviceTableyDeviceTable)r   r   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r*|d d |dd    }n| }|| j| vr<i | j| |< || j| | |j< d S )NMARK_   )r   
glyph_namer   rh   rG   r   r   	component)r/   	anchordef
anchorname	glyphnameanchorr   r   r   ra     s   


zVoltToFea._anchorDefinitionc           +   
      s  |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 }t }|jD ]\}} | d|j }t|}| }t }|D ]	}||  q||s|| |sq|| |D ]!} |} j| d|  d }t |||} |  j!||f< q|j"D ]&}!|! D ]}"|"|vr"g ||"< ||f||" vr4||" ||f qqqt# fdd	|D }#t# fd
d	|D }$|D ]v}"d}%|#r] j$|" }%dd t%|%D }||" D ]3\}}t|}t%d|%d D ]!}&|& j|" | v r j|" | |& }||&d  ||f qzqj |"}!|$rt&|!|d }n|#rt'|!|}nt(|!|d }|| qQd 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 r3 j|" d d }*|(,|(-|" |t.||)|* q|(D ]}" |"} j|" d d }*|t.|d |* qAd S t/|)Nrp   FTr   )
enumerated.r   c                 3       | ]}| j v V  qd S r+   )rE   r   nru   r   r   rr         z(VoltToFea._gposLookup.<locals>.<genexpr>c                 3   r   r+   )rD   r   ru   r   r   rr     r  c                 S   s   g | ]}g qS r   r   )r   rO   r   r   r   r!     r   z)VoltToFea._gposLookup.<locals>.<listcomp>entryexit)0r\   rh   r   r   PositionAdjustPairDefinitionadjust_pairr   coverages_1coverages_2r   r   r   r   r   r   PairPosStatementPositionAdjustSingleDefinitionadjust_singleSinglePosStatementPositionAttachDefinitionrC   coverage_torX   r   	MarkClassr   updater   
isdisjointdifference_updater   rG   MarkClassDefinitionrF   r   allrE   rangeMarkMarkPosStatementMarkLigPosStatementMarkBasePosStatementPositionAttachCursiveDefinitioncoverages_entercoverages_exitpopindexCursivePosStatementrg   )+r/   r   	fealookupr\   rh   idx1idx2pos1pos2
coverage_1
coverage_2r   r   glyphs1glyphs2record1record2abr   recordanchorsallmarksr   r   r   	markclassmarksmarkr   r   r   markdefbaser   is_ligatureis_markr   r   enter_coverageexit_coverager  r  r   ru   r   _gposLookup  s   





















zVoltToFea._gposLookupc                 C   s  |j }|j}t|tjrc|j D ]O\\}	}
\}}| |j|	d  }| |j	|
d  }t
|dks5J t
|dks=J |d |d f}|rQt|||fg}n
t|||||g}|| qd S t|tjrt g}|jD ]\}}|d | j|dd qq|rt|||fg}n	t||||g}|| d S t|tjrt g}|jD ]\}}|d | j|dd q|rt|||fg}n	t||||g}|| d S t|)Nrp   r   Tr   )r\   rh   r   r   r  r  r   r   r  r  r   r   IgnorePosStatementChainContextPosStatementr   r
  r   r  r   r  r  rg   )r/   r   prefixsuffixignorer  r.   r\   rh   r   r!  r"  r#  r&  r'  r   rm   r*  rO   r   r   r   r   _gposContextLookup+  sJ   



zVoltToFea._gposContextLookupc                    s4  |j }|j}t|tjri }|j D ]T\}}|r|s0|j\}}	}
t	| d|	 d|
 d q
|}
|}t|dksBJ t|d  |d  D ]\}}|t|g t| qOq| D ]\}}tg |g t|}|| qld S |j D ]\}}|r|s|j\}}	}
t	| d|	 d|
 d q
|}
|}t|tjrt|dksJ t|dksJ |t||g g d qt|tjrqt|tjrt|dksJ |tg |d g | qt|tjrt|dksJ tg |g |d d}tdd |D   dkrt fdd|D s-J d	d
 |D } fdd
|D }|d  }t|dkrQ|d g  }t| ksZJ |td|  tg ||R  D ]}fdd
|D }|tg |d d g |d d qnq|| qt|d S )N:: Ignoring empty substitutionrp   r   Fc                 s   s    | ]	}t | V  qd S r+   r   r   r   r   r   r   rr     s    z(VoltToFea._gsubLookup.<locals>.<genexpr>c                 3   s$    | ]}t |  d fv V  qdS ro   rA  r   r  r   r   rr     s   " 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 )rp   r   )r   r   rB  r   r   r!     s   * # c                    s   g | ]}  |qS r   )r   r   ru   r   r   r!     s    ) r\   rQ   r   r   SubstitutionAlternateDefinitionmappingr   r1   r   r   r   r   zipr   
setdefaultr   r   r   r   AlternateSubstStatementr   SubstitutionSingleDefinitionSingleSubstStatement+SubstitutionReverseChainingSingleDefinitionSubstitutionMultipleDefinitionMultipleSubstStatementSubstitutionLigatureDefinitionLigatureSubstStatementmaxr  r   rg   )r/   r   r  r\   rQ   
alternatesr   valpathlinecolumnr   replacements	src_glyph
repl_glyphr   rm   replacementzippedr   )r  r/   r   _gsubLookupY  s   




zVoltToFea._gsubLookupc              	   C   sj  |j }|j}t|tjrI|j D ]2\}	}
|	r|
s.|j\}}}t	| d| d| d q| 
|	}| 
|
}|t|||| qg |_d S t|tjtjtjtjfs\tt|g }|j D ]'\}	}
|	rk|
s|j\}}}t	| d| d| d qc|| j
|	dd qct|dkrt|g}|r|t|||fg d S |t||||g d S )Nr?  r@  Tr   rp   )r\   rQ   r   r   rL  rF  r   r1   r   r   r   r   r    ReverseChainSingleSubstStatementr.   rJ  rM  rO  rE  rg   r   r   r   r   IgnoreSubstStatementChainContextSubstStatement)r/   r   r;  r<  r=  r  r.   r\   rQ   r   rS  rT  rU  rV  r   rW  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 }nt|jtr+| |j}n|jd ur6| |j}d }|sB|d usB|d urIt|||}d}| j	
drSd}d	|jv r|jd	d }| | jvrt| ||d
}|d urz|j| |jtd|j  n| 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 |r
t|jdkr
|	g g dg q|	rgtj| |jd |d
}|j| |jd ur.| || n|j d ur:| !|| |	D ](\}}}|jd urS| "|||||| q<|j d urc| #|||||| q<d S |jd uru| || d S |j d ur| !|| d S d S )Nr   RTLrp         FCOMPILER_USEEXTENSIONLOOKUPSTr   )r0   rC  EXCEPT_CONTEXTz chained)$	directionprocess_baseprocess_marksr   r   r   mark_glyph_setr   LookupFlagStatementrH   r   r   r   r   rB   r*   rU   r\   r   r   SubtableStatementcommentsr   r   leftrightex_or_inr   LookupBlockr.   rQ   r\  rh   r8  r`  r>  )r/   r   mark_attachementmark_filteringflagslookupflagsr0   r   r  contextsr   r;  r<  r=  r.   r   r   r   ri     s   








zVoltToFea._lookupDefinitionr+   )F)NF)r4   r5   r6   recompilerP   rW   r-   rU   rX   rn   r   r   r   r   r   r   r   r_   r^   re   rc   r   r   ra   r8  r>  r\  r`  ri   r   r   r   r   r8   `   s6    



$
X

 ._2r8   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inputINPUTzinput font/VTP file to process)metavarr   helpfeaturefileOUTPUTzoutput feature filez-tz--tabler   rk   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)levelTSIVzutf-8z6"TSIV" table is missing, font was not saved from VOLT?rp   r1   "z" is not supportedr?  z: w)argparsepathlibrx  	fontToolsry  ArgumentParsermain__doc__add_argumentr   
parse_argsquietr{  r   r   datadecoder   errorr   r8   r   rk   rg   	tracebackgetattrargsopenr  write)r  r  rx  ry  parseroptionsrK   rL   	converterr   er1   messagerT  rU  rV  feafiler   r   r   r  J  st   



"
"r  __main__r+   )r  loggingrv  ior   graphlibr   fontTools.feaLibr   fontTools.ttLibr   r   fontTools.voltLibr   fontTools.voltLib.parserr   r   	getLoggerr   r   r   r)   rp  r*   r8   r  r4   sysr  r   r   r   r   <module>   s2    -
     
oB