B
    d,                 @   s   d 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	 ddl
mZmZmZmZmZ d	d
gZdZdZeeZeZdd ZG dd deZdd Zdd Zdd Zdd Zd!ddZd"dd	Zdd Zd d
 Z dS )#a  Converts cubic bezier curves to quadratic splines.

Conversion is performed such that the quadratic splines keep the same end-curve
tangents as the original cubics. The approach is iterative, increasing the
number of segments for a spline until the error gets below a bound.

Respective curves from multiple fonts will be converted at once to ensure that
the resulting splines are interpolation-compatible.
    N)AbstractPen)PointToSegmentPen)ReverseContourPen   )curves_to_quadratic)UnequalZipLengthsErrorIncompatibleSegmentNumberErrorIncompatibleSegmentTypesErrorIncompatibleGlyphsErrorIncompatibleFontsErrorfonts_to_quadraticfont_to_quadraticgMbP?z&com.github.googlei18n.cu2qu.curve_typec              G   s.   t tdd | D dkr"t|  tt|  S )zyEnsure each argument to zip has the same length. Also make sure a list is
    returned for python 2/3 compatibility.
    c             s   s   | ]}t |V  qd S )N)len).0a r   `/work/yifan.wang/ringdown/master-ringdown-env/lib/python3.7/site-packages/fontTools/cu2qu/ufo.py	<genexpr>7   s    zzip.<locals>.<genexpr>r   )r   setr   list_zip)argsr   r   r   zip2   s    r   c               @   sX   e Zd Z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 )GetSegmentsPenzPen to collect segments into lists of points for conversion.

    Curves always include their initial on-curve point, so some points are
    duplicated between segments.
    c             C   s   d | _ g | _d S )N)_last_ptsegments)selfr   r   r   __init__C   s    zGetSegmentsPen.__init__c             G   s&   |dkr|d | _ | j||f d S )N)movelineqcurvecurve)r   r   append)r   tagr   r   r   r   _add_segmentG   s    
zGetSegmentsPen._add_segmentc             C   s   |  d| d S )Nr   )r%   )r   ptr   r   r   moveToL   s    zGetSegmentsPen.moveToc             C   s   |  d| d S )Nr   )r%   )r   r&   r   r   r   lineToO   s    zGetSegmentsPen.lineToc             G   s   | j d| jf|  d S )Nr    )r%   r   )r   pointsr   r   r   qCurveToR   s    zGetSegmentsPen.qCurveToc             G   s   | j d| jf|  d S )Nr!   )r%   r   )r   r)   r   r   r   curveToU   s    zGetSegmentsPen.curveToc             C   s   |  d d S )Nclose)r%   )r   r   r   r   	closePathX   s    zGetSegmentsPen.closePathc             C   s   |  d d S )Nend)r%   )r   r   r   r   endPath[   s    zGetSegmentsPen.endPathc             C   s   d S )Nr   )r   Z	glyphNameZtransformationr   r   r   addComponent^   s    zGetSegmentsPen.addComponentN)__name__
__module____qualname____doc__r   r%   r'   r(   r*   r+   r-   r/   r0   r   r   r   r   r   <   s   r   c             C   s"   t  }t|dd}| | |jS )z6Get a glyph's segments as extracted by GetSegmentsPen.T)ZoutputImpliedClosingLine)r   r   Z
drawPointsr   )glyphpenZpointPenr   r   r   _get_segmentsb   s    
r7   c             C   s   |    |  }|rt|}x|D ]\}}|dkr>|j|  q"|dkrR|j|  q"|dkrn|j|dd   q"|dkr|j|dd   q"|dkr|  q"|dkr|  q"t	d	| q"W dS )
z=Draw segments as extracted by GetSegmentsPen back to a glyph.r   r   r!   r   Nr    r,   r.   zUnhandled segment type "%s")
ZclearContoursZgetPenr   r'   r(   r+   r*   r-   r/   AssertionError)r5   r   reverse_directionr6   r$   r   r   r   r   _set_segmentsu   s$    

r:   c                s   t dd | D stdtdd | D |}t|d  t  fdd|dd	 D s`td
t d }||dd ||< dd |D S )z2Return quadratic approximations of cubic segments.c             s   s   | ]}|d  dkV  qdS )r   r!   Nr   )r   sr   r   r   r      s    z)_segments_to_quadratic.<locals>.<genexpr>zNon-cubic given to convertc             S   s   g | ]}|d  qS )r   r   )r   r;   r   r   r   
<listcomp>   s    z*_segments_to_quadratic.<locals>.<listcomp>r   c             3   s   | ]}t | kV  qd S )N)r   )r   r;   )nr   r   r      s    r   NzConverted incompatibly   c             S   s   g | ]}d |fqS )r    r   )r   pr   r   r   r<      s    )allr8   r   r   strget)r   max_errstatsZ
new_pointsZspline_lengthr   )r=   r   _segments_to_quadratic   s    &rE   c                s  yt dd | D  }W n tk
r2   t| Y nX t|s@dS |}g }i }xtt|D ]h\}}	|	d d  t fdd|	dd D sd	d |	D ||< n d
krt|	||}	d}||	 qVW |rt | }
x"t | |
D ]\}}t||| qW |rt	| |d|S )zDo the actual conversion of a set of compatible glyphs, after arguments
    have been set up.

    Return True if the glyphs were modified, else return False.
    c             S   s   g | ]}t |qS r   )r7   )r   gr   r   r   r<      s    z(_glyphs_to_quadratic.<locals>.<listcomp>Fr   c             3   s   | ]}|d   kV  qdS )r   Nr   )r   r;   )r$   r   r   r      s    z'_glyphs_to_quadratic.<locals>.<genexpr>r   Nc             S   s   g | ]}|d  qS )r   r   )r   r;   r   r   r   r<      s    r!   T)r   )
r   r   r   any	enumerater@   rE   r#   r:   r	   )glyphsrC   r9   rD   Zsegments_by_locationZglyphs_modifiedZnew_segments_by_locationZincompatibleir   Znew_segments_by_glyphr5   new_segmentsr   )r$   r   _glyphs_to_quadratic   s0    rL   Fc             C   s\   |dkri }|st d }t|ttfr,|}n|gt|  }t|t| ksNtt| |||S )a  Convert the curves of a set of compatible of glyphs to quadratic.

    All curves will be converted to quadratic at once, ensuring interpolation
    compatibility. If this is not required, calling glyphs_to_quadratic with one
    glyph at a time may yield slightly more optimized results.

    Return True if glyphs were modified, else return False.

    Raises IncompatibleGlyphsError if glyphs have non-interpolatable outlines.
    Ni  )DEFAULT_MAX_ERR
isinstancer   tupler   r8   rL   )rI   rC   r9   rD   
max_errorsr   r   r   glyphs_to_quadratic   s    rQ   Tc                sb  |rjdd | D }t |dkrTtt|}|dkr@td dS |dkrJqjt|nt |dkrjtd d	krvi  r|rtd
 s|st t	|t
tfrt |t | kst|}	n|r|gt |  }	t	 t
tfrt | t  kstdd t|  D }	n r fdd| D }	d}
i }xt jdd | D  D ]}g }g }x:t| |	D ],\}}||krV|||  || qVW y|
t|||O }
W n6 tk
r } zt| |||< W d	d	}~X Y nX q>W |rt||
r"|r"t }tddfdd|D   |r^x4| D ],}|jtd}|dkr.d|jt< d}
q.W |
S )a  Convert the curves of a collection of fonts to quadratic.

    All curves will be converted to quadratic at once, ensuring interpolation
    compatibility. If this is not required, calling fonts_to_quadratic with one
    font at a time may yield slightly more optimized results.

    Return True if fonts were modified, else return False.

    By default, cu2qu stores the curve type in the fonts' lib, under a private
    key "com.github.googlei18n.cu2qu.curve_type", and will not try to convert
    them again if the curve type is already set to "quadratic".
    Setting 'remember_curve_type' to False disables this optimization.

    Raises IncompatibleFontsError if same-named glyphs from different fonts
    have non-interpolatable outlines.
    c             S   s   h | ]}|j td qS )cubic)librB   CURVE_TYPE_LIB_KEY)r   fr   r   r   	<setcomp>   s    z%fonts_to_quadratic.<locals>.<setcomp>r   Z	quadraticz%Curves already converted to quadraticFrR   z'fonts may contain different curve typesNz4Only one of max_err and max_err_em can be specified.c             S   s   g | ]\}}|j j| qS r   )info
unitsPerEm)r   rU   er   r   r   r<     s   z&fonts_to_quadratic.<locals>.<listcomp>c                s   g | ]}|j j  qS r   )rW   rX   )r   rU   )
max_err_emr   r   r<     s    c             s   s   | ]}|  V  qd S )N)keys)r   rU   r   r   r   r     s    z%fonts_to_quadratic.<locals>.<genexpr>zNew spline lengths: %sz, c             3   s   | ]}d | | f V  qdS )z%s: %dNr   )r   l)rD   r   r   r   ,  s    T)r   nextiterloggerrW   NotImplementedErrorwarning	TypeErrorrM   rN   r   rO   r8   r   r   unionr#   rL   r
   errorr   sortedr[   joinrS   rB   rT   )ZfontsrZ   rC   r9   rD   Z
dump_statsZremember_curve_typeZcurve_typesZ
curve_typerP   modifiedZglyph_errorsnamerI   Zcur_max_errorsfontrd   excZspline_lengthsr   )rZ   rD   r   r      sr    




 




c             K   s   t | gf|S )zConvenience wrapper around glyphs_to_quadratic, for just one glyph.
    Return True if the glyph was modified, else return False.
    )rQ   )r5   kwargsr   r   r   glyph_to_quadratic7  s    rl   c             K   s   t | gf|S )zConvenience wrapper around fonts_to_quadratic, for just one font.
    Return True if the font was modified, else return False.
    )r   )ri   rk   r   r   r   r   ?  s    )NFN)NNFNFT)!r4   loggingZfontTools.pens.basePenr   ZfontTools.pens.pointPenr   Z fontTools.pens.reverseContourPenr    r   errorsr   r   r	   r
   r   __all__rM   rT   	getLoggerr1   r_   r   r   r   r7   r:   rE   rL   rQ   r   rl   r   r   r   r   r   <module>   s,   

&'
 
W