
    <`,                         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j        e          ZeZd Z G d de          Zd Zd Zd Zd Z	 ddZ	 	 ddZd Z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                      t          t          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              3   4   K   | ]}t          |          V  d S Nlen).0as     3lib/python3.11/site-packages/fontTools/cu2qu/ufo.py	<genexpr>zzip.<locals>.<genexpr>7   s(      $$!s1vv$$$$$$    r   )r   setr   list_zip)argss    r   zipr   2   sK    
 3$$t$$$$$%%**$d++dr   c                   H    e Zd ZdZd Zd Zd Zd Zd Zd Z	d Z
d	 Z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                 "    d | _         g | _        d S r   )_last_ptsegmentsselfs    r   __init__zGetSegmentsPen.__init__C   s    r   c                 `    |dv r|d         | _         | j                            ||f           d S )N)movelineqcurvecurve)r!   r"   append)r$   tagr   s      r   _add_segmentzGetSegmentsPen._add_segmentG   s9    555 HDMc4[)))))r   c                 2    |                      d|           d S )Nr'   r.   r$   pts     r   moveTozGetSegmentsPen.moveToL       &"%%%%%r   c                 2    |                      d|           d S )Nr(   r0   r1   s     r   lineTozGetSegmentsPen.lineToO   r4   r   c                 .     | j         d| j        g|R   d S )Nr)   r.   r!   r$   pointss     r   qCurveTozGetSegmentsPen.qCurveToR   s'    (DM;F;;;;;;r   c                 .     | j         d| j        g|R   d S )Nr*   r8   r9   s     r   curveTozGetSegmentsPen.curveToU   s'    '4=:6::::::r   c                 0    |                      d           d S )Ncloser0   r#   s    r   	closePathzGetSegmentsPen.closePathX   s    '"""""r   c                 0    |                      d           d S )Nendr0   r#   s    r   endPathzGetSegmentsPen.endPath[   s    %     r   c                     d S r    )r$   	glyphNametransformations      r   addComponentzGetSegmentsPen.addComponent^   s    r   N)__name__
__module____qualname____doc__r%   r.   r3   r6   r;   r=   r@   rC   rH   rE   r   r   r   r   <   s           * * *
& & && & &< < <; ; ;# # #! ! !    r   r   c                 x    t                      }t          |d          }|                     |           |j        S )z6Get a glyph's segments as extracted by GetSegmentsPen.T)outputImpliedClosingLine)r   r   
drawPointsr"   )glyphpenpointPens      r   _get_segmentsrS   b   s?     

C !tDDDH	X<r   c                    |                                   |                                 }|rt          |          }|D ]\  }}|dk    r |j        |  |dk    r |j        |  '|dk    r |j        |dd           @|dk    r |j        |dd           Y|dk    r|                                 t|dk    r|                                 t          d	|z            dS )
z=Draw segments as extracted by GetSegmentsPen back to a glyph.r'   r(   r*   r   Nr)   r?   rB   zUnhandled segment type "%s")
clearContoursgetPenr   r3   r6   r=   r;   r@   rC   AssertionError)rP   r"   reverse_directionrQ   r-   r   s         r   _set_segmentsrY   u   s    

,,..C %$$ F F	T&==CJF]]CJG^^CKabb"""H__CL$qrr(###G^^MMOOOOE\\KKMMMM !>!DEEEF Fr   c                 v   t          d | D                       s
J d            t          d | D             |          }t          |d                   t          fd|dd         D                       s
J d            t          d	z
            }|                    |d          dz   ||<   d
 |D             S )z2Return quadratic approximations of cubic segments.c              3   .   K   | ]}|d          dk    V  dS )r   r*   NrE   r   ss     r   r   z)_segments_to_quadratic.<locals>.<genexpr>   s*      111qtw111111r   zNon-cubic given to convertc                     g | ]
}|d          S )r   rE   r\   s     r   
<listcomp>z*_segments_to_quadratic.<locals>.<listcomp>   s    %=%=%=qad%=%=%=r   r   c              3   >   K   | ]}t          |          k    V  d S r   r   )r   r]   ns     r   r   z)_segments_to_quadratic.<locals>.<genexpr>   s-      33qs1vv{333333r   r   NzConverted incompatibly   c                     g | ]}d |fS )r)   rE   )r   ps     r   r_   z*_segments_to_quadratic.<locals>.<listcomp>   s    ...aXqM...r   )allr   r   strget)r"   max_errstats
new_pointsspline_lengthra   s        @r   _segments_to_quadraticrl      s     1111111OO3OOOO$%=%=H%=%=%=wGGJJqMA3333JqrrN33333MM5MMMMAJJM 99]A66:E-..:....r   c                 ,   	 t          d | D              }n# t          $ r t          |           w xY wt          |          sdS |}g }i }t	          |          D ]t\  }}	|	d         d         t          fd|	dd         D                       sd |	D             ||<   ndk    rt          |	||          }	d	}|                    |	           u|r0t          | }
t          | |
          D ]\  }}t          |||           |rt          | |
          |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                 ,    g | ]}t          |          S rE   )rS   )r   gs     r   r_   z(_glyphs_to_quadratic.<locals>.<listcomp>   s     $F$F$F!]1%5%5$F$F$Fr   Fr   c              3   0   K   | ]}|d          k    V  dS )r   NrE   )r   r]   r-   s     r   r   z'_glyphs_to_quadratic.<locals>.<genexpr>   s+      5511Q43;555555r   r   Nc                     g | ]
}|d          S )r   rE   r\   s     r   r_   z(_glyphs_to_quadratic.<locals>.<listcomp>   s    666qt666r   r*   T)r"   )
r   r   r	   any	enumeratere   rl   r,   rY   r
   )glyphsrh   rX   ri   segments_by_locationglyphs_modifiednew_segments_by_locationincompatibleir"   new_segments_by_glyphrP   new_segmentsr-   s                @r   _glyphs_to_quadraticr|      s   5"$F$Fv$F$F$FG! 5 5 5,V4445#$$ u (O!L !566 2 28qk!n555555555 	#66X666LOOG^^-hGGH"O ''1111 B #%= >#&v/D#E#E 	B 	BE<%/@AAAA K+F\JJJJs    1Fc                     |i }|s
t           dz  }t          |t          t          f          r|}n|gt	          |           z  }t	          |          t	          |           k    sJ 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   r|   )rt   rh   rX   ri   
max_errorss        r   glyphs_to_quadraticr      s     } )!D('D%=)) -

YV,
z??c&kk))))
4EuMMMr   Tc                    |rd | D             }t          |          dk    rTt          t          |                    }|dk    rt                              d           dS |dk    rn<t          |          t          |          dk    rt                              d           i r|rt          d	          s	|st          t          |t          t          f          r%t          |          t          |           k    sJ |}	n|r|gt          |           z  }	t          t          t          f          r=t          |           t                    k    sJ d
 t          |           D             }	nrfd| D             }	d}
i } t                      j        d | D              D ]}g }g }t          | |	          D ]9\  }}||v r0|                    ||                    |                    |           :	 |
t!          |||          z  }
g# t"          $ r)}t                              |           |||<   Y d}~d}~ww xY w|rt'          |          |
r_|r]t)                                                    }t                              dd                    fd|D                       z             |r<| D ]9}|j                            t2          d          }|dk    rd|j        t2          <   d}
:|
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                 N    h | ]"}|j                             t          d           #S )cubic)librg   CURVE_TYPE_LIB_KEYr   fs     r   	<setcomp>z%fonts_to_quadratic.<locals>.<setcomp>   s)    MMM!quyy!3W==MMMr   r   	quadraticz%Curves already converted to quadraticFr   z'fonts may contain different curve typesNz4Only one of max_err and max_err_em can be specified.c                 2    g | ]\  }}|j         j        |z  S rE   info
unitsPerEm)r   r   es      r   r_   z&fonts_to_quadratic.<locals>.<listcomp>  s6     : : :!Q f'!+ : : :r   c                 .    g | ]}|j         j        z  S rE   r   )r   r   
max_err_ems     r   r_   z&fonts_to_quadratic.<locals>.<listcomp>  s#    DDDaf'*4DDDr   c              3   >   K   | ]}|                                 V  d S r   )keysr   s     r   r   z%fonts_to_quadratic.<locals>.<genexpr>  s*      661affhh666666r   zNew spline lengths: %sz, c              3   2   K   | ]}d ||         fz  V  dS )z%s: %dNrE   )r   lri   s     r   r   z%fonts_to_quadratic.<locals>.<genexpr>+  sI       :F :F12H58},:F :F :F :F :F :Fr   T)r   nextiterloggerr   NotImplementedErrorwarning	TypeErrorr~   r   r   r   r   r   unionr,   r|   r   errorr   sortedr   joinr   rg   r   )fontsr   rh   rX   ri   
dump_statsremember_curve_typecurve_types
curve_typer   modifiedglyph_errorsnamert   cur_max_errorsfontr   excspline_lengthss    `  `              r   r   r      s   (  FMMuMMM{q  d;//00J[((CDDDuw&&)*555!!NNDEEE} Pg PNOOO %' %$
'D%=)) ,7||s5zz))))

	 ,YU+
*tUm,, E5zzS__,,,,: :"%eZ"8"8: : :

	 EDDDDeDDD
HL666667 % %uj11 	- 	-KD%t||d4j)))%%e,,,	%,(95B B BHH& 	% 	% 	%LL!$L	%  3$\222 HJ H

--,		 :F :F :F :F6D:F :F :F 1F 1F G 	H 	H 	H    	  	 D&8'BBJ[((/:+,Os   ;H
IH??Ic                     t          | gfi |S )zConvenience wrapper around glyphs_to_quadratic, for just one glyph.
    Return True if the glyph was modified, else return False.
    )r   )rP   kwargss     r   glyph_to_quadraticr   7  s    
 w11&111r   c                     t          | gfi |S )zConvenience wrapper around fonts_to_quadratic, for just one font.
    Return True if the font was modified, else return False.
    )r   )r   r   s     r   r   r   ?  s    
 tf/////r   )NFN)NNFNFT)!rL   loggingfontTools.pens.basePenr   fontTools.pens.pointPenr    fontTools.pens.reverseContourPenr    r   errorsr   r	   r
   r   r   __all__r~   r   	getLoggerrI   r   r   r   r   rS   rY   rl   r|   r   r   r   r   rE   r   r   <module>r      s      . . . . . . 5 5 5 5 5 5 > > > > > > ! ! ! ! ! !               !4
5
 = 		8	$	$   # # # # #[ # # #L  &F F F0/ / /# # #N >BN N N N: AF:>V V V Vr2 2 20 0 0 0 0r   