1 /***************************************************************************/
5 /* FreeType convenience functions to handle glyphs (body). */
7 /* Copyright 1996-2000 by */
8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */
10 /* This file is part of the FreeType project, and may only be used, */
11 /* modified, and distributed under the terms of the FreeType project */
12 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */
13 /* this file you indicate that you have read the license and */
14 /* understand and accept it fully. */
16 /***************************************************************************/
18 /*************************************************************************/
20 /* This file contains the definition of several convenience functions */
21 /* that can be used by client applications to easily retrieve glyph */
22 /* bitmaps and outlines from a given face. */
24 /* These functions should be optional if you are writing a font server */
25 /* or text layout engine on top of FreeType. However, they are pretty */
26 /* handy for many other simple uses of the library. */
28 /*************************************************************************/
31 #include <freetype/ftglyph.h>
32 #include <freetype/ftoutln.h>
33 #include <freetype/internal/ftobjs.h>
36 /*************************************************************************/
38 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
39 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
40 /* messages during execution. */
43 #define FT_COMPONENT trace_glyph
46 /*************************************************************************/
47 /*************************************************************************/
49 /**** Convenience functions ****/
51 /*************************************************************************/
52 /*************************************************************************/
55 /*************************************************************************/
58 /* FT_Matrix_Multiply */
61 /* Performs the matrix operation `b = a*b'. */
64 /* a :: A pointer to matrix `a'. */
67 /* b :: A pointer to matrix `b'. */
73 /* The result is undefined if either `a' or `b' is zero. */
75 FT_EXPORT_FUNC( void ) FT_Matrix_Multiply( FT_Matrix
* a
,
78 FT_Fixed xx
, xy
, yx
, yy
;
84 xx
= FT_MulFix( a
->xx
, b
->xx
) + FT_MulFix( a
->xy
, b
->yx
);
85 xy
= FT_MulFix( a
->xx
, b
->xy
) + FT_MulFix( a
->xy
, b
->yy
);
86 yx
= FT_MulFix( a
->yx
, b
->xx
) + FT_MulFix( a
->yy
, b
->yx
);
87 yy
= FT_MulFix( a
->yx
, b
->xy
) + FT_MulFix( a
->yy
, b
->yy
);
89 b
->xx
= xx
; b
->xy
= xy
;
90 b
->yx
= yx
; b
->yy
= yy
;
94 /*************************************************************************/
97 /* FT_Matrix_Invert */
100 /* Inverts a 2x2 matrix. Returns an error if it can't be inverted. */
103 /* matrix :: A pointer to the target matrix. Remains untouched in */
107 /* FreeType error code. 0 means success. */
112 FT_EXPORT_FUNC( FT_Error
) FT_Matrix_Invert( FT_Matrix
* matrix
)
114 FT_Pos delta
, xx
, yy
;
118 return FT_Err_Invalid_Argument
;
120 /* compute discriminant */
121 delta
= FT_MulFix( matrix
->xx
, matrix
->yy
) -
122 FT_MulFix( matrix
->xy
, matrix
->yx
);
125 return FT_Err_Invalid_Argument
; /* matrix can't be inverted */
127 matrix
->xy
= - FT_DivFix( matrix
->xy
, delta
);
128 matrix
->yx
= - FT_DivFix( matrix
->yx
, delta
);
133 matrix
->xx
= FT_DivFix( yy
, delta
);
134 matrix
->yy
= FT_DivFix( xx
, delta
);
140 /*************************************************************************/
141 /*************************************************************************/
143 /**** FT_BitmapGlyph support ****/
145 /*************************************************************************/
146 /*************************************************************************/
149 FT_Error
ft_bitmap_copy( FT_Memory memory
,
154 FT_Int pitch
= source
->pitch
;
163 size
= (FT_ULong
)( pitch
* source
->rows
);
165 if ( !ALLOC( target
->buffer
, size
) )
166 MEM_Copy( source
->buffer
, target
->buffer
, size
);
173 FT_Error
ft_bitmap_glyph_init( FT_BitmapGlyph glyph
,
176 FT_Error error
= FT_Err_Ok
;
177 FT_Library library
= FT_GLYPH(glyph
)->library
;
178 FT_Memory memory
= library
->memory
;
181 if ( slot
->format
!= ft_glyph_format_bitmap
)
183 error
= FT_Err_Invalid_Glyph_Format
;
187 /* grab the bitmap in the slot - do lazy copying whenever possible */
188 glyph
->bitmap
= slot
->bitmap
;
189 glyph
->left
= slot
->bitmap_left
;
190 glyph
->top
= slot
->bitmap_top
;
192 if ( slot
->flags
& ft_glyph_own_bitmap
)
193 slot
->flags
&= ~ft_glyph_own_bitmap
;
196 /* copy the bitmap into a new buffer */
197 error
= ft_bitmap_copy( memory
, &slot
->bitmap
, &glyph
->bitmap
);
206 FT_Error
ft_bitmap_glyph_copy( FT_BitmapGlyph source
,
207 FT_BitmapGlyph target
)
209 FT_Memory memory
= source
->root
.library
->memory
;
212 target
->left
= source
->left
;
213 target
->top
= source
->top
;
215 return ft_bitmap_copy( memory
, &source
->bitmap
, &target
->bitmap
);
220 void ft_bitmap_glyph_done( FT_BitmapGlyph glyph
)
222 FT_Memory memory
= FT_GLYPH(glyph
)->library
->memory
;
225 FREE( glyph
->bitmap
.buffer
);
230 void ft_bitmap_glyph_bbox( FT_BitmapGlyph glyph
,
233 cbox
->xMin
= glyph
->left
<< 6;
234 cbox
->xMax
= cbox
->xMin
+ ( glyph
->bitmap
.width
<< 6 );
235 cbox
->yMax
= glyph
->top
<< 6;
236 cbox
->yMin
= cbox
->xMax
- ( glyph
->bitmap
.rows
<< 6 );
240 const FT_Glyph_Class ft_bitmap_glyph_class
=
242 sizeof( FT_BitmapGlyphRec
),
243 ft_glyph_format_bitmap
,
245 (FT_Glyph_Init_Func
) ft_bitmap_glyph_init
,
246 (FT_Glyph_Done_Func
) ft_bitmap_glyph_done
,
247 (FT_Glyph_Copy_Func
) ft_bitmap_glyph_copy
,
248 (FT_Glyph_Transform_Func
)0,
249 (FT_Glyph_BBox_Func
) ft_bitmap_glyph_bbox
,
250 (FT_Glyph_Prepare_Func
) 0
254 /*************************************************************************/
255 /*************************************************************************/
257 /**** FT_OutlineGlyph support ****/
259 /*************************************************************************/
260 /*************************************************************************/
264 FT_Error
ft_outline_glyph_init( FT_OutlineGlyph glyph
,
267 FT_Error error
= FT_Err_Ok
;
268 FT_Library library
= FT_GLYPH(glyph
)->library
;
269 FT_Outline
* source
= &slot
->outline
;
270 FT_Outline
* target
= &glyph
->outline
;
273 /* check format in glyph slot */
274 if ( slot
->format
!= ft_glyph_format_outline
)
276 error
= FT_Err_Invalid_Glyph_Format
;
280 /* allocate new outline */
281 error
= FT_Outline_New( library
, source
->n_points
, source
->n_contours
,
287 MEM_Copy( target
->points
, source
->points
,
288 source
->n_points
* sizeof ( FT_Vector
) );
290 MEM_Copy( target
->tags
, source
->tags
,
291 source
->n_points
* sizeof ( FT_Byte
) );
293 MEM_Copy( target
->contours
, source
->contours
,
294 source
->n_contours
* sizeof ( FT_Short
) );
296 /* copy all flags, except the `ft_outline_owner' one */
297 target
->flags
= source
->flags
| ft_outline_owner
;
305 void ft_outline_glyph_done( FT_OutlineGlyph glyph
)
307 FT_Outline_Done( FT_GLYPH( glyph
)->library
, &glyph
->outline
);
312 FT_Error
ft_outline_glyph_copy( FT_OutlineGlyph source
,
313 FT_OutlineGlyph target
)
316 FT_Library library
= FT_GLYPH( source
)->library
;
319 error
= FT_Outline_New( library
, source
->outline
.n_points
,
320 source
->outline
.n_contours
, &target
->outline
);
322 FT_Outline_Copy( &source
->outline
, &target
->outline
);
329 void ft_outline_glyph_transform( FT_OutlineGlyph glyph
,
334 FT_Outline_Transform( &glyph
->outline
, matrix
);
337 FT_Outline_Translate( &glyph
->outline
, delta
->x
, delta
->y
);
342 void ft_outline_glyph_bbox( FT_OutlineGlyph glyph
,
345 FT_Outline_Get_CBox( &glyph
->outline
, bbox
);
350 FT_Error
ft_outline_glyph_prepare( FT_OutlineGlyph glyph
,
353 slot
->format
= ft_glyph_format_outline
;
354 slot
->outline
= glyph
->outline
;
355 slot
->outline
.flags
&= ~ft_outline_owner
;
361 const FT_Glyph_Class ft_outline_glyph_class
=
363 sizeof( FT_OutlineGlyphRec
),
364 ft_glyph_format_outline
,
366 (FT_Glyph_Init_Func
) ft_outline_glyph_init
,
367 (FT_Glyph_Done_Func
) ft_outline_glyph_done
,
368 (FT_Glyph_Copy_Func
) ft_outline_glyph_copy
,
369 (FT_Glyph_Transform_Func
)ft_outline_glyph_transform
,
370 (FT_Glyph_BBox_Func
) ft_outline_glyph_bbox
,
371 (FT_Glyph_Prepare_Func
) ft_outline_glyph_prepare
375 /*************************************************************************/
376 /*************************************************************************/
378 /**** FT_Glyph class and API ****/
380 /*************************************************************************/
381 /*************************************************************************/
384 FT_Error
ft_new_glyph( FT_Library library
,
385 const FT_Glyph_Class
* clazz
,
388 FT_Memory memory
= library
->memory
;
395 if ( !ALLOC( glyph
, clazz
->glyph_size
) )
397 glyph
->library
= library
;
398 glyph
->clazz
= clazz
;
399 glyph
->format
= clazz
->glyph_format
;
408 /*************************************************************************/
414 /* A function used to copy a glyph image. */
417 /* source :: A handle to the source glyph object. */
420 /* target :: A handle to the target glyph object. 0 in case of */
424 /* FreeType error code. 0 means success. */
426 FT_EXPORT_FUNC( FT_Error
) FT_Glyph_Copy( FT_Glyph source
,
431 const FT_Glyph_Class
* clazz
;
434 /* check arguments */
435 if ( !target
|| !source
|| !source
->clazz
)
437 error
= FT_Err_Invalid_Argument
;
443 clazz
= source
->clazz
;
444 error
= ft_new_glyph( source
->library
, clazz
, ©
);
448 if ( clazz
->glyph_copy
)
449 error
= clazz
->glyph_copy( source
, copy
);
452 FT_Done_Glyph( copy
);
461 /*************************************************************************/
467 /* A function used to extract a glyph image from a slot. */
470 /* slot :: A handle to the source glyph slot. */
473 /* aglyph :: A handle to the glyph object. */
476 /* FreeType error code. 0 means success. */
478 FT_EXPORT_FUNC( FT_Error
) FT_Get_Glyph( FT_GlyphSlot slot
,
481 FT_Library library
= slot
->library
;
485 const FT_Glyph_Class
* clazz
= 0;
489 return FT_Err_Invalid_Slot_Handle
;
492 return FT_Err_Invalid_Argument
;
494 /* if it is a bitmap, that's easy :-) */
495 if ( slot
->format
== ft_glyph_format_bitmap
)
496 clazz
= &ft_bitmap_glyph_class
;
498 /* it it is an outline too */
499 else if ( slot
->format
== ft_glyph_format_outline
)
500 clazz
= &ft_outline_glyph_class
;
504 /* try to find a renderer that supports the glyph image format */
505 FT_Renderer render
= FT_Lookup_Renderer( library
, slot
->format
, 0 );
509 clazz
= &render
->glyph_class
;
514 error
= FT_Err_Invalid_Glyph_Format
;
518 /* create FT_Glyph object */
519 error
= ft_new_glyph( library
, clazz
, &glyph
);
523 /* copy advance while converting it to 16.16 format */
524 glyph
->advance
.x
= slot
->advance
.x
<< 10;
525 glyph
->advance
.y
= slot
->advance
.y
<< 10;
527 /* now import the image from the glyph slot */
528 error
= clazz
->glyph_init( glyph
, slot
);
530 /* if an error occurred, destroy the glyph */
532 FT_Done_Glyph( glyph
);
541 /*************************************************************************/
544 /* FT_Glyph_Transform */
547 /* Transforms a glyph image if its format is scalable. */
550 /* glyph :: A handle to the target glyph object. */
552 /* matrix :: A pointer to a 2x2 matrix to apply. */
554 /* delta :: A pointer to a 2d vector to apply. Coordinates are */
555 /* expressed in 1/64th of a pixel. */
558 /* FreeType error code (the glyph format is not scalable if it is */
562 /* The 2x2 transformation matrix is also applied to the glyph's */
563 /* advance vector. */
565 FT_EXPORT_FUNC( FT_Error
) FT_Glyph_Transform( FT_Glyph glyph
,
569 const FT_Glyph_Class
* clazz
;
570 FT_Error error
= FT_Err_Ok
;
573 if ( !glyph
|| !glyph
->clazz
)
574 error
= FT_Err_Invalid_Argument
;
577 clazz
= glyph
->clazz
;
578 if ( clazz
->glyph_transform
)
580 /* transform glyph image */
581 clazz
->glyph_transform( glyph
, matrix
, delta
);
583 /* transform advance vector */
585 FT_Vector_Transform( &glyph
->advance
, matrix
);
588 error
= FT_Err_Invalid_Glyph_Format
;
594 /*************************************************************************/
597 /* FT_Glyph_Get_CBox */
600 /* Returns the glyph image's bounding box. */
603 /* glyph :: A handle to the source glyph object. */
605 /* mode :: A set of bit flags that indicate how to interpret the */
606 /* returned bounding box values. */
609 /* box :: The glyph bounding box. Coordinates are expressed in */
610 /* 1/64th of pixels if it is grid-fitted. */
613 /* Coordinates are relative to the glyph origin, using the Y-upwards */
616 /* If `ft_glyph_bbox_subpixels' is set in `mode', the bbox */
617 /* coordinates are returned in 26.6 pixels (i.e. 1/64th of pixels). */
618 /* Otherwise, coordinates are expressed in integer pixels. */
620 /* Note that the maximum coordinates are exclusive, which means that */
621 /* one can compute the width and height of the glyph image (be it in */
622 /* integer or 26.6 pixels) as: */
624 /* width = bbox.xMax - bbox.xMin; */
625 /* height = bbox.yMax - bbox.yMin; */
627 /* Note also that for 26.6 coordinates, if the */
628 /* `ft_glyph_bbox_gridfit' flag is set in `mode;, the coordinates */
629 /* will also be grid-fitted, which corresponds to: */
631 /* bbox.xMin = FLOOR(bbox.xMin); */
632 /* bbox.yMin = FLOOR(bbox.yMin); */
633 /* bbox.xMax = CEILING(bbox.xMax); */
634 /* bbox.yMax = CEILING(bbox.yMax); */
636 /* The default value (0) for `bbox_mode' is `ft_glyph_bbox_pixels'. */
638 FT_EXPORT_FUNC( void ) FT_Glyph_Get_CBox( FT_Glyph glyph
,
642 const FT_Glyph_Class
* clazz
;
643 FT_Error error
= FT_Err_Ok
;
646 if ( !cbox
|| !glyph
|| !glyph
->clazz
)
647 error
= FT_Err_Invalid_Argument
;
650 clazz
= glyph
->clazz
;
651 if ( !clazz
->glyph_bbox
)
652 error
= FT_Err_Invalid_Glyph_Format
;
655 /* retrieve bbox in 26.6 coordinates */
656 clazz
->glyph_bbox( glyph
, cbox
);
658 /* perform grid fitting if needed */
659 if ( bbox_mode
& ft_glyph_bbox_gridfit
)
663 cbox
->xMax
= ( cbox
->xMax
+ 63 ) & -64;
664 cbox
->yMax
= ( cbox
->yMax
+ 63 ) & -64;
667 /* convert to integer pixels if needed */
668 if ( !( bbox_mode
& ft_glyph_bbox_subpixels
) )
681 /*************************************************************************/
684 /* FT_Glyph_To_Bitmap */
687 /* Converts a given glyph object to a bitmap glyph object. */
690 /* glyph :: A pointer to a handle to the target glyph. */
693 /* render_mode :: A set of bit flags that describe how the data is */
696 /* origin :: A pointer to a vector used to translate the glyph */
697 /* image before rendering. Can be 0 (if no */
698 /* translation). The origin is expressed in */
701 /* destroy :: A boolean that indicates that the original glyph */
702 /* image should be destroyed by this function. It is */
703 /* never destroyed in case of error. */
706 /* FreeType error code. 0 means success. */
709 /* The glyph image is translated with the `origin' vector before */
710 /* rendering. In case of error, it it translated back to its */
711 /* original position and the glyph is left untouched. */
713 /* The first parameter is a pointer to a FT_Glyph handle, that will */
714 /* be replaced by this function. Typically, you would use (omitting */
715 /* error handling): */
719 /* FT_Glyph glyph; */
720 /* FT_BitmapGlyph glyph_bitmap; */
724 /* error = FT_Load_Char( face, glyph_index, FT_LOAD_DEFAUT ); */
726 /* // extract glyph image */
727 /* error = FT_Get_Glyph( face->glyph, &glyph ); */
729 /* // convert to a bitmap (default render mode + destroy old) */
730 /* if ( glyph->format != ft_glyph_format_bitmap ) */
732 /* error = FT_Glyph_To_Bitmap( &glyph, ft_render_mode_default, */
734 /* if ( error ) // glyph unchanged */
738 /* // access bitmap content by typecasting */
739 /* glyph_bitmap = (FT_BitmapGlyph)glyph; */
741 /* // do funny stuff with it, like blitting/drawing */
744 /* // discard glyph image (bitmap or not) */
745 /* FT_Done_Glyph( glyph ); */
749 /* This function will always fail if the glyph's format isn't */
752 FT_EXPORT_FUNC( FT_Error
) FT_Glyph_To_Bitmap( FT_Glyph
* the_glyph
,
753 FT_ULong render_mode
,
757 FT_GlyphSlotRec dummy
;
760 FT_BitmapGlyph bitmap
;
762 const FT_Glyph_Class
* clazz
;
769 /* we render the glyph into a glyph bitmap using a `dummy' glyph slot */
770 /* then calling FT_Render_Glyph_Internal() */
776 clazz
= glyph
->clazz
;
777 if ( !clazz
|| !clazz
->glyph_prepare
)
780 MEM_Set( &dummy
, 0, sizeof ( dummy
) );
781 dummy
.library
= glyph
->library
;
782 dummy
.format
= clazz
->glyph_format
;
784 /* if `origin' is set, translate the glyph image */
786 FT_Glyph_Transform( glyph
, 0, origin
);
788 /* create result bitmap glyph */
789 error
= ft_new_glyph( glyph
->library
, &ft_bitmap_glyph_class
,
790 (FT_Glyph
*)&bitmap
);
794 /* prepare dummy slot for rendering */
795 error
= clazz
->glyph_prepare( glyph
, &dummy
) ||
796 FT_Render_Glyph_Internal( glyph
->library
, &dummy
, render_mode
);
798 if ( !destroy
&& origin
)
805 FT_Glyph_Transform( glyph
, 0, &v
);
808 /* in case of succes, copy the bitmap to the glyph bitmap */
811 error
= ft_bitmap_glyph_init( bitmap
, &dummy
);
814 /* this should never happen, but let's be safe */
815 FT_Done_Glyph( FT_GLYPH( bitmap
) );
820 FT_Done_Glyph( glyph
);
822 *the_glyph
= FT_GLYPH( bitmap
);
829 error
= FT_Err_Invalid_Argument
;
834 /*************************************************************************/
840 /* Destroys a given glyph. */
843 /* glyph :: A handle to the target glyph object. */
845 FT_EXPORT_FUNC( void ) FT_Done_Glyph( FT_Glyph glyph
)
849 FT_Memory memory
= glyph
->library
->memory
;
850 const FT_Glyph_Class
* clazz
= glyph
->clazz
;
853 if ( clazz
->glyph_done
)
854 clazz
->glyph_done( glyph
);
863 /*************************************************************************/
864 /*************************************************************************/
866 /**** EXPERIMENTAL EMBOLDENING/OUTLINING SUPPORT ****/
868 /*************************************************************************/
869 /*************************************************************************/
871 /* Compute the norm of a vector */
873 #ifdef FT_CONFIG_OPTION_OLD_CALCS
876 FT_Pos
ft_norm( FT_Vector
* vec
)
881 MUL_64( vec
->x
, vec
->x
, t1
);
882 MUL_64( vec
->y
, vec
->y
, t2
);
883 ADD_64( t1
, t2
, t1
);
885 return (FT_Pos
)SQRT_64( t1
);
888 #else /* FT_CONFIG_OPTION_OLD_CALCS */
891 FT_Pos
ft_norm( FT_Vector
* vec
)
895 FT_ULong H
, L
, L2
, hi
, lo
, med
;
898 u
= vec
->x
; if ( u
< 0 ) u
= -u
;
899 v
= vec
->y
; if ( v
< 0 ) v
= -v
;
908 /* check that we are not trying to normalize zero! */
912 /* compute (u*u + v*v) on 64 bits with two 32-bit registers [H:L] */
913 hi
= (FT_ULong
)u
>> 16;
914 lo
= (FT_ULong
)u
& 0xFFFF;
917 H
= hi
* hi
+ ( med
>> 15 );
923 hi
= (FT_ULong
)v
>> 16;
924 lo
= (FT_ULong
)v
& 0xFFFF;
927 H
+= hi
* hi
+ ( med
>> 15 );
937 /* if the value is smaller than 32 bits */
941 while ( ( L
& 0xC0000000UL
) == 0 )
946 return ( FT_Sqrt32( L
) >> shift
);
952 L
= ( L
>> 2 ) | ( H
<< 30 );
956 return ( FT_Sqrt32( L
) << shift
);
960 #endif /* FT_CONFIG_OPTION_OLD_CALCS */
964 int ft_test_extrema( FT_Outline
* outline
,
967 FT_Vector
*prev
, *cur
, *next
;
972 /* we need to compute the `previous' and `next' point */
973 /* for these extrema. */
974 cur
= outline
->points
+ n
;
979 for ( c
= 0; c
< outline
->n_contours
; c
++ )
981 last
= outline
->contours
[c
];
984 prev
= outline
->points
+ last
;
987 next
= outline
->points
+ first
;
992 product
= FT_MulDiv( cur
->x
- prev
->x
, /* in.x */
993 next
->y
- cur
->y
, /* out.y */
996 FT_MulDiv( cur
->y
- prev
->y
, /* in.y */
997 next
->x
- cur
->x
, /* out.x */
1001 product
= product
> 0 ? 1 : -1;
1007 /* Compute the orientation of path filling. It differs between TrueType */
1008 /* and Type1 formats. We could use the `ft_outline_reverse_fill' flag, */
1009 /* but it is better to re-compute it directly (it seems that this flag */
1010 /* isn't correctly set for some weird composite glyphs currently). */
1012 /* We do this by computing bounding box points, and computing their */
1015 /* The function returns either 1 or -1. */
1018 int ft_get_orientation( FT_Outline
* outline
)
1030 box
.xMin
= box
.yMin
= 32767;
1031 box
.xMax
= box
.yMax
= -32768;
1034 if ( outline
->n_contours
< 1 )
1037 last
= outline
->contours
[outline
->n_contours
- 1];
1039 for ( n
= 0; n
<= last
; n
++ )
1044 x
= outline
->points
[n
].x
;
1056 y
= outline
->points
[n
].y
;
1069 /* test orientation of the xmin */
1070 return ft_test_extrema( outline
, indices
.xMin
) ||
1071 ft_test_extrema( outline
, indices
.yMin
) ||
1072 ft_test_extrema( outline
, indices
.xMax
) ||
1073 ft_test_extrema( outline
, indices
.yMax
) ||
1074 1; /* this is an empty glyph? */
1079 FT_Error
ft_embolden( FT_Face original
,
1080 FT_Outline
* outline
,
1085 FT_Vector cur
, prev
, next
;
1087 int c
, n
, first
, orientation
;
1089 FT_UNUSED( advance
);
1092 /* compute control distance */
1093 distance
= FT_MulFix( original
->em_size
/ 60,
1094 original
->size
->metrics
.y_scale
);
1096 orientation
= ft_get_orientation( &original
->glyph
->outline
);
1098 points
= original
->glyph
->outline
.points
;
1101 for ( c
= 0; c
< outline
->n_contours
; c
++ )
1103 int last
= outline
->contours
[c
];
1106 prev
= points
[last
];
1108 for ( n
= first
; n
<= last
; n
++ )
1110 FT_Pos norm
, delta
, d
;
1115 if ( n
< last
) next
= points
[n
+ 1];
1116 else next
= points
[first
];
1118 /* compute the in and out vectors */
1119 in
.x
= cur
.x
- prev
.x
;
1120 in
.y
= cur
.y
- prev
.y
;
1122 out
.x
= next
.x
- cur
.x
;
1123 out
.y
= next
.y
- cur
.y
;
1125 /* compute U and V */
1126 norm
= ft_norm( &in
);
1127 u
.x
= orientation
* FT_DivFix( in
.y
, norm
);
1128 u
.y
= orientation
* -FT_DivFix( in
.x
, norm
);
1130 norm
= ft_norm( &out
);
1131 v
.x
= orientation
* FT_DivFix( out
.y
, norm
);
1132 v
.y
= orientation
* -FT_DivFix( out
.x
, norm
);
1136 if ( ( outline
->flags
[n
] & FT_Curve_Tag_On
) == 0 )
1139 /* Check discriminant for parallel vectors */
1140 delta
= FT_MulFix( u
.x
, v
.y
) - FT_MulFix( u
.y
, v
.x
);
1141 if ( delta
> FT_BOLD_THRESHOLD
|| delta
< -FT_BOLD_THRESHOLD
)
1143 /* Move point -- compute A and B */
1147 A
= d
+ FT_MulFix( cur
.x
, u
.x
) + FT_MulFix( cur
.y
, u
.y
);
1148 B
= d
+ FT_MulFix( cur
.x
, v
.x
) + FT_MulFix( cur
.y
, v
.y
);
1150 x
= FT_MulFix( A
, v
.y
) - FT_MulFix( B
, u
.y
);
1151 y
= FT_MulFix( B
, u
.x
) - FT_MulFix( A
, v
.x
);
1153 outline
->points
[n
].x
= distance
+ FT_DivFix( x
, delta
);
1154 outline
->points
[n
].y
= distance
+ FT_DivFix( y
, delta
);
1158 /* Vectors are nearly parallel */
1162 x
= distance
+ cur
.x
+ FT_MulFix( d
, u
.x
+ v
.x
) / 2;
1163 y
= distance
+ cur
.y
+ FT_MulFix( d
, u
.y
+ v
.y
) / 2;
1165 outline
->points
[n
].x
= x
;
1166 outline
->points
[n
].y
= y
;
1176 *advance
= ( *advance
+ distance
* 4 ) & -64;
1181 #endif /* 0 -- EXPERIMENTAL STUFF! */