ref: 499053c1c545118585bc9d4d61375c61b7bf97d4
parent: 1ffb911d5067cb0e2be0f2844d4369bf33624d8c
author: Werner Lemberg <[email protected]>
date: Sat Jun 7 00:02:21 EDT 2003
* include/freetype/ftstroker.h: Renamed to... * include/freetype/ftstroke.h: This. * src/base/ftstroker.c: Renamed to... * src/base/ftstroke.c: This. * include/freetype/config/ftheader.h (FT_STROKER_H): Updated. * src/base/descrip.mms, src/base/Jamfile, src/base/rules.mk: Updated. * src/pcf/pcfdriver.c: Renamed to... * src/pcf/pcfdrivr.c: This. * src/pcf/pcfdriver.h: Renamed to... * src/pcf/pcfdrivr.h: This. * src/pcf/Jamfile, src/pcf/rules.mk: Updated.
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,23 @@
+2003-06-06 Werner Lemberg <[email protected]>
+
+ * include/freetype/ftstroker.h: Renamed to...
+ * include/freetype/ftstroke.h: This.
+
+ * src/base/ftstroker.c: Renamed to...
+ * src/base/ftstroke.c: This.
+
+ * include/freetype/config/ftheader.h (FT_STROKER_H): Updated.
+
+ * src/base/descrip.mms, src/base/Jamfile, src/base/rules.mk:
+ Updated.
+
+ * src/pcf/pcfdriver.c: Renamed to...
+ * src/pcf/pcfdrivr.c: This.
+ * src/pcf/pcfdriver.h: Renamed to...
+ * src/pcf/pcfdrivr.h: This.
+
+ * src/pcf/Jamfile, src/pcf/rules.mk: Updated.
+
2003-06-05 Wenlin Institute (Tom Bishop) <[email protected]>
* src/base/ftmac.c (file_spec_from_path) [TARGET_API_MAC_CARBON]:
--- a/include/freetype/config/ftheader.h
+++ b/include/freetype/config/ftheader.h
@@ -509,7 +509,7 @@
/* */
#define FT_TRIGONOMETRY_H <freetype/fttrigon.h>
-#define FT_STROKER_H <freetype/ftstroker.h>
+#define FT_STROKER_H <freetype/ftstroke.h>
#define FT_SYNTHESIS_H <freetype/ftsynth.h>
#define FT_ERROR_DEFINITIONS_H <freetype/fterrdef.h>
--- /dev/null
+++ b/include/freetype/ftstroke.h
@@ -1,0 +1,160 @@
+/***************************************************************************/
+/* */
+/* ftstroke.h */
+/* */
+/* FreeType path stroker (specification). */
+/* */
+/* Copyright 2002, 2003 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __FT_STROKE_H__
+#define __FT_STROKE_H__
+
+#include <ft2build.h>
+#include FT_OUTLINE_H
+
+FT_BEGIN_HEADER
+
+/*@*************************************************************
+ *
+ * @type: FT_Stroker
+ *
+ * @description:
+ * opaque handler to a path stroker object
+ */
+ typedef struct FT_StrokerRec_* FT_Stroker;
+
+
+/*@*************************************************************
+ *
+ * @enum: FT_Stroker_LineJoin
+ *
+ * @description:
+ * these values determine how two joining lines are rendered
+ * in a stroker.
+ *
+ * @values:
+ * FT_STROKER_LINEJOIN_ROUND ::
+ * used to render rounded line joins. circular arcs are used
+ * to join two lines smoothly
+ *
+ * FT_STROKER_LINEJOIN_BEVEL ::
+ * used to render beveled line joins; i.e. the two joining lines
+ * are extended until they intersect
+ *
+ * FT_STROKER_LINEJOIN_MITER ::
+ * same as beveled rendering, except that an additional line
+ * break is added if the angle between the two joining lines
+ * is too closed (this is useful to avoid unpleasant spikes
+ * in beveled rendering).
+ */
+ typedef enum
+ {
+ FT_STROKER_LINEJOIN_ROUND = 0,
+ FT_STROKER_LINEJOIN_BEVEL,
+ FT_STROKER_LINEJOIN_MITER
+
+ } FT_Stroker_LineJoin;
+
+
+/*@*************************************************************
+ *
+ * @enum: FT_Stroker_LineCap
+ *
+ * @description:
+ * these values determine how the end of opened sub-paths are
+ * rendered in a stroke
+ *
+ * @values:
+ * FT_STROKER_LINECAP_BUTT ::
+ * the end of lines is rendered as a full stop on the last
+ * point itself
+ *
+ * FT_STROKER_LINECAP_ROUND ::
+ * the end of lines is rendered as a half-circle around the
+ * last point
+ *
+ * FT_STROKER_LINECAP_SQUARE ::
+ * the end of lines is rendered as a square around the
+ * last point
+ */
+ typedef enum
+ {
+ FT_STROKER_LINECAP_BUTT = 0,
+ FT_STROKER_LINECAP_ROUND,
+ FT_STROKER_LINECAP_SQUARE
+
+ } FT_Stroker_LineCap;
+
+ /* */
+
+ FT_EXPORT( FT_Error )
+ FT_Stroker_New( FT_Memory memory,
+ FT_Stroker *astroker );
+
+ FT_EXPORT( void )
+ FT_Stroker_Set( FT_Stroker stroker,
+ FT_Fixed radius,
+ FT_Stroker_LineCap line_cap,
+ FT_Stroker_LineJoin line_join,
+ FT_Fixed miter_limit );
+
+
+ FT_EXPORT( FT_Error )
+ FT_Stroker_ParseOutline( FT_Stroker stroker,
+ FT_Outline* outline,
+ FT_Bool opened );
+
+ FT_EXPORT( FT_Error )
+ FT_Stroker_BeginSubPath( FT_Stroker stroker,
+ FT_Vector* to,
+ FT_Bool open );
+
+ FT_EXPORT( FT_Error )
+ FT_Stroker_EndSubPath( FT_Stroker stroker );
+
+
+ FT_EXPORT( FT_Error )
+ FT_Stroker_LineTo( FT_Stroker stroker,
+ FT_Vector* to );
+
+ FT_EXPORT( FT_Error )
+ FT_Stroker_ConicTo( FT_Stroker stroker,
+ FT_Vector* control,
+ FT_Vector* to );
+
+ FT_EXPORT( FT_Error )
+ FT_Stroker_CubicTo( FT_Stroker stroker,
+ FT_Vector* control1,
+ FT_Vector* control2,
+ FT_Vector* to );
+
+
+ FT_EXPORT( FT_Error )
+ FT_Stroker_GetCounts( FT_Stroker stroker,
+ FT_UInt *anum_points,
+ FT_UInt *anum_contours );
+
+ FT_EXPORT( void )
+ FT_Stroker_Export( FT_Stroker stroker,
+ FT_Outline* outline );
+
+ FT_EXPORT( void )
+ FT_Stroker_Done( FT_Stroker stroker );
+
+
+FT_END_HEADER
+
+#endif /* __FT_STROKE_H__ */
+
+
+/* END */
--- a/include/freetype/ftstroker.h
+++ /dev/null
@@ -1,139 +1,0 @@
-#ifndef __FT_STROKER_H__
-#define __FT_STROKER_H__
-
-#include <ft2build.h>
-#include FT_OUTLINE_H
-
-FT_BEGIN_HEADER
-
-/*@*************************************************************
- *
- * @type: FT_Stroker
- *
- * @description:
- * opaque handler to a path stroker object
- */
- typedef struct FT_StrokerRec_* FT_Stroker;
-
-
-/*@*************************************************************
- *
- * @enum: FT_Stroker_LineJoin
- *
- * @description:
- * these values determine how two joining lines are rendered
- * in a stroker.
- *
- * @values:
- * FT_STROKER_LINEJOIN_ROUND ::
- * used to render rounded line joins. circular arcs are used
- * to join two lines smoothly
- *
- * FT_STROKER_LINEJOIN_BEVEL ::
- * used to render beveled line joins; i.e. the two joining lines
- * are extended until they intersect
- *
- * FT_STROKER_LINEJOIN_MITER ::
- * same as beveled rendering, except that an additional line
- * break is added if the angle between the two joining lines
- * is too closed (this is useful to avoid unpleasant spikes
- * in beveled rendering).
- */
- typedef enum
- {
- FT_STROKER_LINEJOIN_ROUND = 0,
- FT_STROKER_LINEJOIN_BEVEL,
- FT_STROKER_LINEJOIN_MITER
-
- } FT_Stroker_LineJoin;
-
-
-/*@*************************************************************
- *
- * @enum: FT_Stroker_LineCap
- *
- * @description:
- * these values determine how the end of opened sub-paths are
- * rendered in a stroke
- *
- * @values:
- * FT_STROKER_LINECAP_BUTT ::
- * the end of lines is rendered as a full stop on the last
- * point itself
- *
- * FT_STROKER_LINECAP_ROUND ::
- * the end of lines is rendered as a half-circle around the
- * last point
- *
- * FT_STROKER_LINECAP_SQUARE ::
- * the end of lines is rendered as a square around the
- * last point
- */
- typedef enum
- {
- FT_STROKER_LINECAP_BUTT = 0,
- FT_STROKER_LINECAP_ROUND,
- FT_STROKER_LINECAP_SQUARE
-
- } FT_Stroker_LineCap;
-
- /* */
-
- FT_EXPORT( FT_Error )
- FT_Stroker_New( FT_Memory memory,
- FT_Stroker *astroker );
-
- FT_EXPORT( void )
- FT_Stroker_Set( FT_Stroker stroker,
- FT_Fixed radius,
- FT_Stroker_LineCap line_cap,
- FT_Stroker_LineJoin line_join,
- FT_Fixed miter_limit );
-
-
- FT_EXPORT( FT_Error )
- FT_Stroker_ParseOutline( FT_Stroker stroker,
- FT_Outline* outline,
- FT_Bool opened );
-
- FT_EXPORT( FT_Error )
- FT_Stroker_BeginSubPath( FT_Stroker stroker,
- FT_Vector* to,
- FT_Bool open );
-
- FT_EXPORT( FT_Error )
- FT_Stroker_EndSubPath( FT_Stroker stroker );
-
-
- FT_EXPORT( FT_Error )
- FT_Stroker_LineTo( FT_Stroker stroker,
- FT_Vector* to );
-
- FT_EXPORT( FT_Error )
- FT_Stroker_ConicTo( FT_Stroker stroker,
- FT_Vector* control,
- FT_Vector* to );
-
- FT_EXPORT( FT_Error )
- FT_Stroker_CubicTo( FT_Stroker stroker,
- FT_Vector* control1,
- FT_Vector* control2,
- FT_Vector* to );
-
-
- FT_EXPORT( FT_Error )
- FT_Stroker_GetCounts( FT_Stroker stroker,
- FT_UInt *anum_points,
- FT_UInt *anum_contours );
-
- FT_EXPORT( void )
- FT_Stroker_Export( FT_Stroker stroker,
- FT_Outline* outline );
-
- FT_EXPORT( void )
- FT_Stroker_Done( FT_Stroker stroker );
-
-
-FT_END_HEADER
-
-#endif /* __FT_STROKER_H__ */
--- a/src/base/Jamfile
+++ b/src/base/Jamfile
@@ -1,4 +1,4 @@
-# FreeType 2 src/base Jamfile (c) 2001, 2002 David Turner
+# FreeType 2 src/base Jamfile (c) 2001, 2002, 2003 David Turner
#
SubDir FT2_TOP $(FT2_SRC_DIR) base ;
@@ -24,7 +24,7 @@
#
Library $(FT2_LIB) : ftsystem.c ftinit.c ftglyph.c ftmm.c ftbdf.c
ftbbox.c ftdebug.c ftxf86.c fttype1.c ftpfr.c
- ftstroker.c ftwinfnt.c
+ ftstroke.c ftwinfnt.c
;
# Add Macintosh-specific file to the library when necessary.
--- a/src/base/descrip.mms
+++ b/src/base/descrip.mms
@@ -3,7 +3,7 @@
#
-# Copyright 2001 by
+# Copyright 2001, 2003 by
# David Turner, Robert Wilhelm, and Werner Lemberg.
#
# This file is part of the FreeType project, and may only be used, modified,
@@ -15,7 +15,7 @@
CFLAGS=$(COMP_FLAGS)$(DEBUG)/include=([--.builds.vms],[--.include],[--.src.base])
-OBJS=ftbase.obj,ftinit.obj,ftglyph.obj,ftdebug.obj,ftbdf.obj,ftmm.obj,fttype1.obj,ftxf86.obj,ftpfr.obj,ftstroker.obj,ftwinfnt.obj
+OBJS=ftbase.obj,ftinit.obj,ftglyph.obj,ftdebug.obj,ftbdf.obj,ftmm.obj,fttype1.obj,ftxf86.obj,ftpfr.obj,ftstroke.obj,ftwinfnt.obj
all : $(OBJS)
library [--.lib]freetype.olb $(OBJS)
--- /dev/null
+++ b/src/base/ftstroke.c
@@ -1,0 +1,1667 @@
+/***************************************************************************/
+/* */
+/* ftstroke.c */
+/* */
+/* FreeType path stroker (body). */
+/* */
+/* Copyright 2002, 2003 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_STROKER_H
+#include FT_TRIGONOMETRY_H
+#include FT_INTERNAL_MEMORY_H
+#include FT_INTERNAL_DEBUG_H
+
+
+ /***************************************************************************/
+ /***************************************************************************/
+ /***** *****/
+ /***** BEZIER COMPUTATIONS *****/
+ /***** *****/
+ /***************************************************************************/
+ /***************************************************************************/
+
+#define FT_SMALL_CONIC_THRESHOLD ( FT_ANGLE_PI / 6 )
+#define FT_SMALL_CUBIC_THRESHOLD ( FT_ANGLE_PI / 6 )
+#define FT_EPSILON 2
+
+#define FT_IS_SMALL( x ) ( (x) > -FT_EPSILON && (x) < FT_EPSILON )
+
+
+ static FT_Pos
+ ft_pos_abs( FT_Pos x )
+ {
+ return x >= 0 ? x : -x ;
+ }
+
+
+ static void
+ ft_conic_split( FT_Vector* base )
+ {
+ FT_Pos a, b;
+
+
+ base[4].x = base[2].x;
+ b = base[1].x;
+ a = base[3].x = ( base[2].x + b ) / 2;
+ b = base[1].x = ( base[0].x + b ) / 2;
+ base[2].x = ( a + b ) / 2;
+
+ base[4].y = base[2].y;
+ b = base[1].y;
+ a = base[3].y = ( base[2].y + b ) / 2;
+ b = base[1].y = ( base[0].y + b ) / 2;
+ base[2].y = ( a + b ) / 2;
+ }
+
+
+ static FT_Bool
+ ft_conic_is_small_enough( FT_Vector* base,
+ FT_Angle *angle_in,
+ FT_Angle *angle_out )
+ {
+ FT_Vector d1, d2;
+ FT_Angle theta;
+ FT_Int close1, close2;
+
+
+ d1.x = base[1].x - base[2].x;
+ d1.y = base[1].y - base[2].y;
+ d2.x = base[0].x - base[1].x;
+ d2.y = base[0].y - base[1].y;
+
+ close1 = FT_IS_SMALL( d1.x ) && FT_IS_SMALL( d1.y );
+ close2 = FT_IS_SMALL( d2.x ) && FT_IS_SMALL( d2.y );
+
+ if ( close1 )
+ {
+ if ( close2 )
+ *angle_in = *angle_out = 0;
+ else
+ *angle_in = *angle_out = FT_Atan2( d2.x, d2.y );
+ }
+ else if ( close2 )
+ {
+ *angle_in = *angle_out = FT_Atan2( d1.x, d1.y );
+ }
+ else
+ {
+ *angle_in = FT_Atan2( d1.x, d1.y );
+ *angle_out = FT_Atan2( d2.x, d2.y );
+ }
+
+ theta = ft_pos_abs( FT_Angle_Diff( *angle_in, *angle_out ) );
+
+ return FT_BOOL( theta < FT_SMALL_CONIC_THRESHOLD );
+ }
+
+
+ static void
+ ft_cubic_split( FT_Vector* base )
+ {
+ FT_Pos a, b, c, d;
+
+
+ base[6].x = base[3].x;
+ c = base[1].x;
+ d = base[2].x;
+ base[1].x = a = ( base[0].x + c ) / 2;
+ base[5].x = b = ( base[3].x + d ) / 2;
+ c = ( c + d ) / 2;
+ base[2].x = a = ( a + c ) / 2;
+ base[4].x = b = ( b + c ) / 2;
+ base[3].x = ( a + b ) / 2;
+
+ base[6].y = base[3].y;
+ c = base[1].y;
+ d = base[2].y;
+ base[1].y = a = ( base[0].y + c ) / 2;
+ base[5].y = b = ( base[3].y + d ) / 2;
+ c = ( c + d ) / 2;
+ base[2].y = a = ( a + c ) / 2;
+ base[4].y = b = ( b + c ) / 2;
+ base[3].y = ( a + b ) / 2;
+ }
+
+
+ static FT_Bool
+ ft_cubic_is_small_enough( FT_Vector* base,
+ FT_Angle *angle_in,
+ FT_Angle *angle_mid,
+ FT_Angle *angle_out )
+ {
+ FT_Vector d1, d2, d3;
+ FT_Angle theta1, theta2;
+ FT_Int close1, close2, close3;
+
+
+ d1.x = base[2].x - base[3].x;
+ d1.y = base[2].y - base[3].y;
+ d2.x = base[1].x - base[2].x;
+ d2.y = base[1].y - base[2].y;
+ d3.x = base[0].x - base[1].x;
+ d3.y = base[0].y - base[1].y;
+
+ close1 = FT_IS_SMALL( d1.x ) && FT_IS_SMALL( d1.y );
+ close2 = FT_IS_SMALL( d2.x ) && FT_IS_SMALL( d2.y );
+ close3 = FT_IS_SMALL( d3.x ) && FT_IS_SMALL( d3.y );
+
+ if ( close1 || close3 )
+ {
+ if ( close2 )
+ {
+ /* basically a point */
+ *angle_in = *angle_out = *angle_mid = 0;
+ }
+ else if ( close1 )
+ {
+ *angle_in = *angle_mid = FT_Atan2( d2.x, d2.y );
+ *angle_out = FT_Atan2( d3.x, d3.y );
+ }
+ else /* close2 */
+ {
+ *angle_in = FT_Atan2( d1.x, d1.y );
+ *angle_mid = *angle_out = FT_Atan2( d2.x, d2.y );
+ }
+ }
+ else if ( close2 )
+ {
+ *angle_in = *angle_mid = FT_Atan2( d1.x, d1.y );
+ *angle_out = FT_Atan2( d3.x, d3.y );
+ }
+ else
+ {
+ *angle_in = FT_Atan2( d1.x, d1.y );
+ *angle_mid = FT_Atan2( d2.x, d2.y );
+ *angle_out = FT_Atan2( d3.x, d3.y );
+ }
+
+ theta1 = ft_pos_abs( FT_Angle_Diff( *angle_in, *angle_mid ) );
+ theta2 = ft_pos_abs( FT_Angle_Diff( *angle_mid, *angle_out ) );
+
+ return FT_BOOL( theta1 < FT_SMALL_CUBIC_THRESHOLD &&
+ theta2 < FT_SMALL_CUBIC_THRESHOLD );
+ }
+
+
+ /***************************************************************************/
+ /***************************************************************************/
+ /***** *****/
+ /***** STROKE BORDERS *****/
+ /***** *****/
+ /***************************************************************************/
+ /***************************************************************************/
+
+ typedef enum
+ {
+ FT_STROKE_TAG_ON = 1, /* on-curve point */
+ FT_STROKE_TAG_CUBIC = 2, /* cubic off-point */
+ FT_STROKE_TAG_BEGIN = 4, /* sub-path start */
+ FT_STROKE_TAG_END = 8 /* sub-path end */
+
+ } FT_StrokeTags;
+
+
+ typedef struct FT_StrokeBorderRec_
+ {
+ FT_UInt num_points;
+ FT_UInt max_points;
+ FT_Vector* points;
+ FT_Byte* tags;
+ FT_Bool movable;
+ FT_Int start; /* index of current sub-path start point */
+ FT_Memory memory;
+
+ } FT_StrokeBorderRec, *FT_StrokeBorder;
+
+
+ static FT_Error
+ ft_stroke_border_grow( FT_StrokeBorder border,
+ FT_UInt new_points )
+ {
+ FT_UInt old_max = border->max_points;
+ FT_UInt new_max = border->num_points + new_points;
+ FT_Error error = 0;
+
+
+ if ( new_max > old_max )
+ {
+ FT_UInt cur_max = old_max;
+ FT_Memory memory = border->memory;
+
+
+ while ( cur_max < new_max )
+ cur_max += ( cur_max >> 1 ) + 16;
+
+ if ( FT_RENEW_ARRAY( border->points, old_max, cur_max ) ||
+ FT_RENEW_ARRAY( border->tags, old_max, cur_max ) )
+ goto Exit;
+
+ border->max_points = cur_max;
+ }
+ Exit:
+ return error;
+ }
+
+
+ static void
+ ft_stroke_border_close( FT_StrokeBorder border )
+ {
+ FT_ASSERT( border->start >= 0 );
+
+ /* don't record empty paths! */
+ if ( border->num_points > (FT_UInt)border->start )
+ {
+ border->tags[border->start ] |= FT_STROKE_TAG_BEGIN;
+ border->tags[border->num_points - 1] |= FT_STROKE_TAG_END;
+ }
+
+ border->start = -1;
+ border->movable = 0;
+ }
+
+
+ static FT_Error
+ ft_stroke_border_lineto( FT_StrokeBorder border,
+ FT_Vector* to,
+ FT_Bool movable )
+ {
+ FT_Error error = 0;
+
+
+ FT_ASSERT( border->start >= 0 );
+
+ if ( border->movable )
+ {
+ /* move last point */
+ border->points[border->num_points - 1] = *to;
+ }
+ else
+ {
+ /* add one point */
+ error = ft_stroke_border_grow( border, 1 );
+ if ( !error )
+ {
+ FT_Vector* vec = border->points + border->num_points;
+ FT_Byte* tag = border->tags + border->num_points;
+
+
+ vec[0] = *to;
+ tag[0] = FT_STROKE_TAG_ON;
+
+ border->num_points += 1;
+ }
+ }
+ border->movable = movable;
+ return error;
+ }
+
+
+ static FT_Error
+ ft_stroke_border_conicto( FT_StrokeBorder border,
+ FT_Vector* control,
+ FT_Vector* to )
+ {
+ FT_Error error;
+
+
+ FT_ASSERT( border->start >= 0 );
+
+ error = ft_stroke_border_grow( border, 2 );
+ if ( !error )
+ {
+ FT_Vector* vec = border->points + border->num_points;
+ FT_Byte* tag = border->tags + border->num_points;
+
+ vec[0] = *control;
+ vec[1] = *to;
+
+ tag[0] = 0;
+ tag[1] = FT_STROKE_TAG_ON;
+
+ border->num_points += 2;
+ }
+ border->movable = 0;
+ return error;
+ }
+
+
+ static FT_Error
+ ft_stroke_border_cubicto( FT_StrokeBorder border,
+ FT_Vector* control1,
+ FT_Vector* control2,
+ FT_Vector* to )
+ {
+ FT_Error error;
+
+
+ FT_ASSERT( border->start >= 0 );
+
+ error = ft_stroke_border_grow( border, 3 );
+ if ( !error )
+ {
+ FT_Vector* vec = border->points + border->num_points;
+ FT_Byte* tag = border->tags + border->num_points;
+
+
+ vec[0] = *control1;
+ vec[1] = *control2;
+ vec[2] = *to;
+
+ tag[0] = FT_STROKE_TAG_CUBIC;
+ tag[1] = FT_STROKE_TAG_CUBIC;
+ tag[2] = FT_STROKE_TAG_ON;
+
+ border->num_points += 3;
+ }
+ border->movable = 0;
+ return error;
+ }
+
+
+#define FT_ARC_CUBIC_ANGLE ( FT_ANGLE_PI / 2 )
+
+
+ static FT_Error
+ ft_stroke_border_arcto( FT_StrokeBorder border,
+ FT_Vector* center,
+ FT_Fixed radius,
+ FT_Angle angle_start,
+ FT_Angle angle_diff )
+ {
+ FT_Angle total, angle, step, rotate, next, theta;
+ FT_Vector a, b, a2, b2;
+ FT_Fixed length;
+ FT_Error error = 0;
+
+
+ /* compute start point */
+ FT_Vector_From_Polar( &a, radius, angle_start );
+ a.x += center->x;
+ a.y += center->y;
+
+ total = angle_diff;
+ angle = angle_start;
+ rotate = ( angle_diff >= 0 ) ? FT_ANGLE_PI2 : -FT_ANGLE_PI2;
+
+ while ( total != 0 )
+ {
+ step = total;
+ if ( step > FT_ARC_CUBIC_ANGLE )
+ step = FT_ARC_CUBIC_ANGLE;
+
+ else if ( step < -FT_ARC_CUBIC_ANGLE )
+ step = -FT_ARC_CUBIC_ANGLE;
+
+ next = angle + step;
+ theta = step;
+ if ( theta < 0 )
+ theta = -theta;
+
+ theta >>= 1;
+
+ /* compute end point */
+ FT_Vector_From_Polar( &b, radius, next );
+ b.x += center->x;
+ b.y += center->y;
+
+ /* compute first and second control points */
+ length = FT_MulDiv( radius, FT_Sin( theta ) * 4,
+ ( 0x10000L + FT_Cos( theta ) ) * 3 );
+
+ FT_Vector_From_Polar( &a2, length, angle + rotate );
+ a2.x += a.x;
+ a2.y += a.y;
+
+ FT_Vector_From_Polar( &b2, length, next - rotate );
+ b2.x += b.x;
+ b2.y += b.y;
+
+ /* add cubic arc */
+ error = ft_stroke_border_cubicto( border, &a2, &b2, &b );
+ if ( error )
+ break;
+
+ /* process the rest of the arc ?? */
+ a = b;
+ total -= step;
+ angle = next;
+ }
+
+ return error;
+ }
+
+
+ static FT_Error
+ ft_stroke_border_moveto( FT_StrokeBorder border,
+ FT_Vector* to )
+ {
+ /* close current open path if any ? */
+ if ( border->start >= 0 )
+ ft_stroke_border_close( border );
+
+ border->start = border->num_points;
+ border->movable = 0;
+
+ return ft_stroke_border_lineto( border, to, 0 );
+ }
+
+
+ static void
+ ft_stroke_border_init( FT_StrokeBorder border,
+ FT_Memory memory )
+ {
+ border->memory = memory;
+ border->points = NULL;
+ border->tags = NULL;
+
+ border->num_points = 0;
+ border->max_points = 0;
+ border->start = -1;
+ }
+
+
+ static void
+ ft_stroke_border_reset( FT_StrokeBorder border )
+ {
+ border->num_points = 0;
+ border->start = -1;
+ }
+
+
+ static void
+ ft_stroke_border_done( FT_StrokeBorder border )
+ {
+ FT_Memory memory = border->memory;
+
+
+ FT_FREE( border->points );
+ FT_FREE( border->tags );
+
+ border->num_points = 0;
+ border->max_points = 0;
+ border->start = -1;
+ }
+
+
+ static FT_Error
+ ft_stroke_border_get_counts( FT_StrokeBorder border,
+ FT_UInt *anum_points,
+ FT_UInt *anum_contours )
+ {
+ FT_Error error = 0;
+ FT_UInt num_points = 0;
+ FT_UInt num_contours = 0;
+
+ FT_UInt count = border->num_points;
+ FT_Vector* point = border->points;
+ FT_Byte* tags = border->tags;
+ FT_Int in_contour = 0;
+
+
+ for ( ; count > 0; count--, num_points++, point++, tags++ )
+ {
+ if ( tags[0] & FT_STROKE_TAG_BEGIN )
+ {
+ if ( in_contour != 0 )
+ goto Fail;
+
+ in_contour = 1;
+ }
+ else if ( in_contour == 0 )
+ goto Fail;
+
+ if ( tags[0] & FT_STROKE_TAG_END )
+ {
+ if ( in_contour == 0 )
+ goto Fail;
+
+ in_contour = 0;
+ num_contours++;
+ }
+ }
+
+ if ( in_contour != 0 )
+ goto Fail;
+
+ Exit:
+ *anum_points = num_points;
+ *anum_contours = num_contours;
+ return error;
+
+ Fail:
+ num_points = 0;
+ num_contours = 0;
+ goto Exit;
+ }
+
+
+ static void
+ ft_stroke_border_export( FT_StrokeBorder border,
+ FT_Outline* outline )
+ {
+ /* copy point locations */
+ FT_MEM_COPY( outline->points + outline->n_points,
+ border->points,
+ border->num_points * sizeof ( FT_Vector ) );
+
+ /* copy tags */
+ {
+ FT_UInt count = border->num_points;
+ FT_Byte* read = border->tags;
+ FT_Byte* write = (FT_Byte*)outline->tags + outline->n_points;
+
+
+ for ( ; count > 0; count--, read++, write++ )
+ {
+ if ( *read & FT_STROKE_TAG_ON )
+ *write = FT_CURVE_TAG_ON;
+ else if ( *read & FT_STROKE_TAG_CUBIC )
+ *write = FT_CURVE_TAG_CUBIC;
+ else
+ *write = FT_CURVE_TAG_CONIC;
+ }
+ }
+
+ /* copy contours */
+ {
+ FT_UInt count = border->num_points;
+ FT_Byte* tags = border->tags;
+ FT_Short* write = outline->contours + outline->n_contours;
+ FT_Short idx = (FT_Short)outline->n_points;
+
+
+ for ( ; count > 0; count--, tags++, idx++ )
+ {
+ if ( *tags & FT_STROKE_TAG_END )
+ {
+ *write++ = idx;
+ outline->n_contours++;
+ }
+ }
+ }
+
+ outline->n_points = (short)( outline->n_points + border->num_points );
+
+ FT_ASSERT( FT_Outline_Check( outline ) == 0 );
+ }
+
+
+ /***************************************************************************/
+ /***************************************************************************/
+ /***** *****/
+ /***** STROKER *****/
+ /***** *****/
+ /***************************************************************************/
+ /***************************************************************************/
+
+#define FT_SIDE_TO_ROTATE( s ) ( FT_ANGLE_PI2 - (s) * FT_ANGLE_PI )
+
+ typedef struct FT_StrokerRec_
+ {
+ FT_Angle angle_in;
+ FT_Angle angle_out;
+ FT_Vector center;
+ FT_Bool first_point;
+ FT_Bool subpath_open;
+ FT_Angle subpath_angle;
+ FT_Vector subpath_start;
+
+ FT_Stroker_LineCap line_cap;
+ FT_Stroker_LineJoin line_join;
+ FT_Fixed miter_limit;
+ FT_Fixed radius;
+
+ FT_Bool valid;
+ FT_StrokeBorderRec borders[2];
+ FT_Memory memory;
+
+ } FT_StrokerRec;
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Stroker_New( FT_Memory memory,
+ FT_Stroker *astroker )
+ {
+ FT_Error error;
+ FT_Stroker stroker;
+
+
+ if ( !FT_NEW( stroker ) )
+ {
+ stroker->memory = memory;
+
+ ft_stroke_border_init( &stroker->borders[0], memory );
+ ft_stroke_border_init( &stroker->borders[1], memory );
+ }
+ *astroker = stroker;
+ return error;
+ }
+
+
+ FT_EXPORT_DEF( void )
+ FT_Stroker_Set( FT_Stroker stroker,
+ FT_Fixed radius,
+ FT_Stroker_LineCap line_cap,
+ FT_Stroker_LineJoin line_join,
+ FT_Fixed miter_limit )
+ {
+ stroker->radius = radius;
+ stroker->line_cap = line_cap;
+ stroker->line_join = line_join;
+ stroker->miter_limit = miter_limit;
+
+ stroker->valid = 0;
+
+ ft_stroke_border_reset( &stroker->borders[0] );
+ ft_stroke_border_reset( &stroker->borders[1] );
+ }
+
+
+ FT_EXPORT_DEF( void )
+ FT_Stroker_Done( FT_Stroker stroker )
+ {
+ if ( stroker )
+ {
+ FT_Memory memory = stroker->memory;
+
+
+ ft_stroke_border_done( &stroker->borders[0] );
+ ft_stroke_border_done( &stroker->borders[1] );
+
+ stroker->memory = NULL;
+ FT_FREE( stroker );
+ }
+ }
+
+
+ /* creates a circular arc at a corner or cap */
+ static FT_Error
+ ft_stroker_arcto( FT_Stroker stroker,
+ FT_Int side )
+ {
+ FT_Angle total, rotate;
+ FT_Fixed radius = stroker->radius;
+ FT_Error error = 0;
+ FT_StrokeBorder border = stroker->borders + side;
+
+
+ rotate = FT_SIDE_TO_ROTATE( side );
+
+ total = FT_Angle_Diff( stroker->angle_in, stroker->angle_out );
+ if ( total == FT_ANGLE_PI )
+ total = -rotate * 2;
+
+ error = ft_stroke_border_arcto( border,
+ &stroker->center,
+ radius,
+ stroker->angle_in + rotate,
+ total );
+ border->movable = 0;
+ return error;
+ }
+
+
+ /* adds a cap at the end of an opened path */
+ static FT_Error
+ ft_stroker_cap( FT_Stroker stroker,
+ FT_Angle angle,
+ FT_Int side )
+ {
+ FT_Error error = 0;
+
+
+ if ( stroker->line_cap == FT_STROKER_LINECAP_ROUND )
+ {
+ /* add a round cap */
+ stroker->angle_in = angle;
+ stroker->angle_out = angle + FT_ANGLE_PI;
+ error = ft_stroker_arcto( stroker, side );
+ }
+ else if ( stroker->line_cap == FT_STROKER_LINECAP_SQUARE )
+ {
+ /* add a square cap */
+ FT_Vector delta, delta2;
+ FT_Angle rotate = FT_SIDE_TO_ROTATE( side );
+ FT_Fixed radius = stroker->radius;
+ FT_StrokeBorder border = stroker->borders + side;
+
+
+ FT_Vector_From_Polar( &delta2, radius, angle + rotate );
+ FT_Vector_From_Polar( &delta, radius, angle );
+
+ delta.x += stroker->center.x + delta2.x;
+ delta.y += stroker->center.y + delta2.y;
+
+ error = ft_stroke_border_lineto( border, &delta, 0 );
+ if ( error )
+ goto Exit;
+
+ FT_Vector_From_Polar( &delta2, radius, angle - rotate );
+ FT_Vector_From_Polar( &delta, radius, angle );
+
+ delta.x += delta2.x + stroker->center.x;
+ delta.y += delta2.y + stroker->center.y;
+
+ error = ft_stroke_border_lineto( border, &delta, 0 );
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ /* process an inside corner, i.e. compute intersection */
+ static FT_Error
+ ft_stroker_inside( FT_Stroker stroker,
+ FT_Int side)
+ {
+ FT_StrokeBorder border = stroker->borders + side;
+ FT_Angle phi, theta, rotate;
+ FT_Fixed length, thcos, sigma;
+ FT_Vector delta;
+ FT_Error error = 0;
+
+
+ rotate = FT_SIDE_TO_ROTATE( side );
+
+ /* compute median angle */
+ theta = FT_Angle_Diff( stroker->angle_in, stroker->angle_out );
+ if ( theta == FT_ANGLE_PI )
+ theta = rotate;
+ else
+ theta = theta / 2;
+
+ phi = stroker->angle_in + theta;
+
+ thcos = FT_Cos( theta );
+ sigma = FT_MulFix( stroker->miter_limit, thcos );
+
+ if ( sigma < 0x10000L )
+ {
+ FT_Vector_From_Polar( &delta, stroker->radius,
+ stroker->angle_out + rotate );
+ delta.x += stroker->center.x;
+ delta.y += stroker->center.y;
+ border->movable = 0;
+ }
+ else
+ {
+ length = FT_DivFix( stroker->radius, thcos );
+
+ FT_Vector_From_Polar( &delta, length, phi + rotate );
+ delta.x += stroker->center.x;
+ delta.y += stroker->center.y;
+ }
+
+ error = ft_stroke_border_lineto( border, &delta, 0 );
+
+ return error;
+ }
+
+
+ /* process an outside corner, i.e. compute bevel/miter/round */
+ static FT_Error
+ ft_stroker_outside( FT_Stroker stroker,
+ FT_Int side )
+ {
+ FT_StrokeBorder border = stroker->borders + side;
+ FT_Error error;
+ FT_Angle rotate;
+
+
+ if ( stroker->line_join == FT_STROKER_LINEJOIN_ROUND )
+ {
+ error = ft_stroker_arcto( stroker, side );
+ }
+ else
+ {
+ /* this is a mitered or beveled corner */
+ FT_Fixed sigma, radius = stroker->radius;
+ FT_Angle theta, phi;
+ FT_Fixed thcos;
+ FT_Bool miter;
+
+
+ rotate = FT_SIDE_TO_ROTATE( side );
+ miter = FT_BOOL( stroker->line_join == FT_STROKER_LINEJOIN_MITER );
+
+ theta = FT_Angle_Diff( stroker->angle_in, stroker->angle_out );
+ if ( theta == FT_ANGLE_PI )
+ {
+ theta = rotate;
+ phi = stroker->angle_in;
+ }
+ else
+ {
+ theta = theta / 2;
+ phi = stroker->angle_in + theta + rotate;
+ }
+
+ thcos = FT_Cos( theta );
+ sigma = FT_MulFix( stroker->miter_limit, thcos );
+
+ if ( sigma >= 0x10000L )
+ miter = 0;
+
+ if ( miter ) /* this is a miter (broken angle) */
+ {
+ FT_Vector middle, delta;
+ FT_Fixed length;
+
+
+ /* compute middle point */
+ FT_Vector_From_Polar( &middle,
+ FT_MulFix( radius, stroker->miter_limit ),
+ phi );
+ middle.x += stroker->center.x;
+ middle.y += stroker->center.y;
+
+ /* compute first angle point */
+ length = FT_MulFix( radius,
+ FT_DivFix( 0x10000L - sigma,
+ ft_pos_abs( FT_Sin( theta ) ) ) );
+
+ FT_Vector_From_Polar( &delta, length, phi + rotate );
+ delta.x += middle.x;
+ delta.y += middle.y;
+
+ error = ft_stroke_border_lineto( border, &delta, 0 );
+ if ( error )
+ goto Exit;
+
+ /* compute second angle point */
+ FT_Vector_From_Polar( &delta, length, phi - rotate );
+ delta.x += middle.x;
+ delta.y += middle.y;
+
+ error = ft_stroke_border_lineto( border, &delta, 0 );
+ if ( error )
+ goto Exit;
+
+ /* finally, add a movable end point */
+ FT_Vector_From_Polar( &delta, radius, stroker->angle_out + rotate );
+ delta.x += stroker->center.x;
+ delta.y += stroker->center.y;
+
+ error = ft_stroke_border_lineto( border, &delta, 1 );
+ }
+
+ else /* this is a bevel (intersection) */
+ {
+ FT_Fixed length;
+ FT_Vector delta;
+
+
+ length = FT_DivFix( stroker->radius, thcos );
+
+ FT_Vector_From_Polar( &delta, length, phi );
+ delta.x += stroker->center.x;
+ delta.y += stroker->center.y;
+
+ error = ft_stroke_border_lineto( border, &delta, 0 );
+ if (error) goto Exit;
+
+ /* now add end point */
+ FT_Vector_From_Polar( &delta, stroker->radius,
+ stroker->angle_out + rotate );
+ delta.x += stroker->center.x;
+ delta.y += stroker->center.y;
+
+ error = ft_stroke_border_lineto( border, &delta, 1 );
+ }
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ static FT_Error
+ ft_stroker_process_corner( FT_Stroker stroker )
+ {
+ FT_Error error = 0;
+ FT_Angle turn;
+ FT_Int inside_side;
+
+
+ turn = FT_Angle_Diff( stroker->angle_in, stroker->angle_out );
+
+ /* no specific corner processing is required if the turn is 0 */
+ if ( turn == 0 )
+ goto Exit;
+
+ /* when we turn to the right, the inside side is 0 */
+ inside_side = 0;
+
+ /* otherwise, the inside side is 1 */
+ if ( turn < 0 )
+ inside_side = 1;
+
+ /* process the inside side */
+ error = ft_stroker_inside( stroker, inside_side );
+ if ( error )
+ goto Exit;
+
+ /* process the outside side */
+ error = ft_stroker_outside( stroker, 1 - inside_side );
+
+ Exit:
+ return error;
+ }
+
+
+ /* add two points to the left and right borders corresponding to the */
+ /* start of the subpath.. */
+ static FT_Error
+ ft_stroker_subpath_start( FT_Stroker stroker,
+ FT_Angle start_angle )
+ {
+ FT_Vector delta;
+ FT_Vector point;
+ FT_Error error;
+ FT_StrokeBorder border;
+
+
+ FT_Vector_From_Polar( &delta, stroker->radius,
+ start_angle + FT_ANGLE_PI2 );
+
+ point.x = stroker->center.x + delta.x;
+ point.y = stroker->center.y + delta.y;
+
+ border = stroker->borders;
+ error = ft_stroke_border_moveto( border, &point );
+ if ( error )
+ goto Exit;
+
+ point.x = stroker->center.x - delta.x;
+ point.y = stroker->center.y - delta.y;
+
+ border++;
+ error = ft_stroke_border_moveto( border, &point );
+
+ /* save angle for last cap */
+ stroker->subpath_angle = start_angle;
+ stroker->first_point = 0;
+
+ Exit:
+ return error;
+ }
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Stroker_LineTo( FT_Stroker stroker,
+ FT_Vector* to )
+ {
+ FT_Error error = 0;
+ FT_StrokeBorder border;
+ FT_Vector delta;
+ FT_Angle angle;
+ FT_Int side;
+
+ delta.x = to->x - stroker->center.x;
+ delta.y = to->y - stroker->center.y;
+
+ angle = FT_Atan2( delta.x, delta.y );
+ FT_Vector_From_Polar( &delta, stroker->radius, angle + FT_ANGLE_PI2 );
+
+ /* process corner if necessary */
+ if ( stroker->first_point )
+ {
+ /* This is the first segment of a subpath. We need to */
+ /* add a point to each border at their respective starting */
+ /* point locations. */
+ error = ft_stroker_subpath_start( stroker, angle );
+ if ( error )
+ goto Exit;
+ }
+ else
+ {
+ /* process the current corner */
+ stroker->angle_out = angle;
+ error = ft_stroker_process_corner( stroker );
+ if ( error )
+ goto Exit;
+ }
+
+ /* now add a line segment to both the "inside" and "outside" paths */
+
+ for ( border = stroker->borders, side = 1; side >= 0; side--, border++ )
+ {
+ FT_Vector point;
+
+
+ point.x = to->x + delta.x;
+ point.y = to->y + delta.y;
+
+ error = ft_stroke_border_lineto( border, &point, 1 );
+ if ( error )
+ goto Exit;
+
+ delta.x = -delta.x;
+ delta.y = -delta.y;
+ }
+
+ stroker->angle_in = angle;
+ stroker->center = *to;
+
+ Exit:
+ return error;
+ }
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Stroker_ConicTo( FT_Stroker stroker,
+ FT_Vector* control,
+ FT_Vector* to )
+ {
+ FT_Error error = 0;
+ FT_Vector bez_stack[34];
+ FT_Vector* arc;
+ FT_Vector* limit = bez_stack + 30;
+ FT_Angle start_angle;
+ FT_Bool first_arc = 1;
+
+
+ arc = bez_stack;
+ arc[0] = *to;
+ arc[1] = *control;
+ arc[2] = stroker->center;
+
+ while ( arc >= bez_stack )
+ {
+ FT_Angle angle_in, angle_out;
+
+
+ angle_in = angle_out = 0; /* remove compiler warnings */
+
+ if ( arc < limit &&
+ !ft_conic_is_small_enough( arc, &angle_in, &angle_out ) )
+ {
+ ft_conic_split( arc );
+ arc += 2;
+ continue;
+ }
+
+ if ( first_arc )
+ {
+ first_arc = 0;
+
+ start_angle = angle_in;
+
+ /* process corner if necessary */
+ if ( stroker->first_point )
+ error = ft_stroker_subpath_start( stroker, start_angle );
+ else
+ {
+ stroker->angle_out = start_angle;
+ error = ft_stroker_process_corner( stroker );
+ }
+ }
+
+ /* the arc's angle is small enough; we can add it directly to each */
+ /* border */
+ {
+ FT_Vector ctrl, end;
+ FT_Angle theta, phi, rotate;
+ FT_Fixed length;
+ FT_Int side;
+
+
+ theta = FT_Angle_Diff( angle_in, angle_out ) / 2;
+ phi = angle_in + theta;
+ length = FT_DivFix( stroker->radius, FT_Cos( theta ) );
+
+ for ( side = 0; side <= 1; side++ )
+ {
+ rotate = FT_SIDE_TO_ROTATE( side );
+
+ /* compute control point */
+ FT_Vector_From_Polar( &ctrl, length, phi + rotate );
+ ctrl.x += arc[1].x;
+ ctrl.y += arc[1].y;
+
+ /* compute end point */
+ FT_Vector_From_Polar( &end, stroker->radius, angle_out + rotate );
+ end.x += arc[0].x;
+ end.y += arc[0].y;
+
+ error = ft_stroke_border_conicto( stroker->borders + side,
+ &ctrl, &end );
+ if ( error )
+ goto Exit;
+ }
+ }
+
+ arc -= 2;
+
+ if ( arc < bez_stack )
+ stroker->angle_in = angle_out;
+ }
+
+ stroker->center = *to;
+
+ Exit:
+ return error;
+ }
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Stroker_CubicTo( FT_Stroker stroker,
+ FT_Vector* control1,
+ FT_Vector* control2,
+ FT_Vector* to )
+ {
+ FT_Error error = 0;
+ FT_Vector bez_stack[37];
+ FT_Vector* arc;
+ FT_Vector* limit = bez_stack + 32;
+ FT_Angle start_angle;
+ FT_Bool first_arc = 1;
+
+
+ arc = bez_stack;
+ arc[0] = *to;
+ arc[1] = *control2;
+ arc[2] = *control1;
+ arc[3] = stroker->center;
+
+ while ( arc >= bez_stack )
+ {
+ FT_Angle angle_in, angle_mid, angle_out;
+
+
+ /* remove compiler warnings */
+ angle_in = angle_out = angle_mid = 0;
+
+ if ( arc < limit &&
+ !ft_cubic_is_small_enough( arc, &angle_in,
+ &angle_mid, &angle_out ) )
+ {
+ ft_cubic_split( arc );
+ arc += 3;
+ continue;
+ }
+
+ if ( first_arc )
+ {
+ first_arc = 0;
+
+ /* process corner if necessary */
+ start_angle = angle_in;
+
+ if ( stroker->first_point )
+ error = ft_stroker_subpath_start( stroker, start_angle );
+ else
+ {
+ stroker->angle_out = start_angle;
+ error = ft_stroker_process_corner( stroker );
+ }
+ if ( error )
+ goto Exit;
+ }
+
+ /* the arc's angle is small enough; we can add it directly to each */
+ /* border */
+ {
+ FT_Vector ctrl1, ctrl2, end;
+ FT_Angle theta1, phi1, theta2, phi2, rotate;
+ FT_Fixed length1, length2;
+ FT_Int side;
+
+
+ theta1 = ft_pos_abs( angle_mid - angle_in ) / 2;
+ theta2 = ft_pos_abs( angle_out - angle_mid ) / 2;
+ phi1 = (angle_mid + angle_in ) / 2;
+ phi2 = (angle_mid + angle_out ) / 2;
+ length1 = FT_DivFix( stroker->radius, FT_Cos( theta1 ) );
+ length2 = FT_DivFix( stroker->radius, FT_Cos(theta2) );
+
+ for ( side = 0; side <= 1; side++ )
+ {
+ rotate = FT_SIDE_TO_ROTATE( side );
+
+ /* compute control points */
+ FT_Vector_From_Polar( &ctrl1, length1, phi1 + rotate );
+ ctrl1.x += arc[2].x;
+ ctrl1.y += arc[2].y;
+
+ FT_Vector_From_Polar( &ctrl2, length2, phi2 + rotate );
+ ctrl2.x += arc[1].x;
+ ctrl2.y += arc[1].y;
+
+ /* compute end point */
+ FT_Vector_From_Polar( &end, stroker->radius, angle_out + rotate );
+ end.x += arc[0].x;
+ end.y += arc[0].y;
+
+ error = ft_stroke_border_cubicto( stroker->borders + side,
+ &ctrl1, &ctrl2, &end );
+ if ( error )
+ goto Exit;
+ }
+ }
+
+ arc -= 3;
+ if ( arc < bez_stack )
+ stroker->angle_in = angle_out;
+ }
+
+ stroker->center = *to;
+
+ Exit:
+ return error;
+ }
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Stroker_BeginSubPath( FT_Stroker stroker,
+ FT_Vector* to,
+ FT_Bool open )
+ {
+ /* We cannot process the first point, because there is not enough */
+ /* information regarding its corner/cap. The latter will be processed */
+ /* in the "end_subpath" routine. */
+ /* */
+ stroker->first_point = 1;
+ stroker->center = *to;
+ stroker->subpath_open = open;
+
+ /* record the subpath start point index for each border */
+ stroker->subpath_start = *to;
+ return 0;
+ }
+
+
+ static FT_Error
+ ft_stroker_add_reverse_left( FT_Stroker stroker,
+ FT_Bool open )
+ {
+ FT_StrokeBorder right = stroker->borders + 0;
+ FT_StrokeBorder left = stroker->borders + 1;
+ FT_Int new_points;
+ FT_Error error = 0;
+
+
+ FT_ASSERT( left->start >= 0 );
+
+ new_points = left->num_points - left->start;
+ if ( new_points > 0 )
+ {
+ error = ft_stroke_border_grow( right, (FT_UInt)new_points );
+ if ( error )
+ goto Exit;
+
+ {
+ FT_Vector* dst_point = right->points + right->num_points;
+ FT_Byte* dst_tag = right->tags + right->num_points;
+ FT_Vector* src_point = left->points + left->num_points - 1;
+ FT_Byte* src_tag = left->tags + left->num_points - 1;
+
+ while ( src_point >= left->points + left->start )
+ {
+ *dst_point = *src_point;
+ *dst_tag = *src_tag;
+
+ if ( open )
+ dst_tag[0] &= ~( FT_STROKE_TAG_BEGIN | FT_STROKE_TAG_END );
+ else
+ {
+ /* switch begin/end tags if necessary.. */
+ if ( dst_tag[0] & ( FT_STROKE_TAG_BEGIN | FT_STROKE_TAG_END ) )
+ dst_tag[0] ^= ( FT_STROKE_TAG_BEGIN | FT_STROKE_TAG_END );
+ }
+
+ src_point--;
+ src_tag--;
+ dst_point++;
+ dst_tag++;
+ }
+ }
+
+ left->num_points = left->start;
+ right->num_points += new_points;
+
+ right->movable = 0;
+ left->movable = 0;
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ /* there's a lot of magic in this function! */
+ FT_EXPORT_DEF( FT_Error )
+ FT_Stroker_EndSubPath( FT_Stroker stroker )
+ {
+ FT_Error error = 0;
+
+
+ if ( stroker->subpath_open )
+ {
+ FT_StrokeBorder right = stroker->borders;
+
+ /* All right, this is an opened path, we need to add a cap between */
+ /* right & left, add the reverse of left, then add a final cap */
+ /* between left & right. */
+ error = ft_stroker_cap( stroker, stroker->angle_in, 0 );
+ if ( error )
+ goto Exit;
+
+ /* add reversed points from "left" to "right" */
+ error = ft_stroker_add_reverse_left( stroker, 1 );
+ if ( error )
+ goto Exit;
+
+ /* now add the final cap */
+ stroker->center = stroker->subpath_start;
+ error = ft_stroker_cap( stroker,
+ stroker->subpath_angle + FT_ANGLE_PI, 0 );
+ if ( error )
+ goto Exit;
+
+ /* Now end the right subpath accordingly. The left one is */
+ /* rewind and doesn't need further processing. */
+ ft_stroke_border_close( right );
+ }
+ else
+ {
+ FT_Angle turn;
+ FT_Int inside_side;
+
+
+ /* process the corner */
+ stroker->angle_out = stroker->subpath_angle;
+ turn = FT_Angle_Diff( stroker->angle_in,
+ stroker->angle_out );
+
+ /* no specific corner processing is required if the turn is 0 */
+ if ( turn != 0 )
+ {
+ /* when we turn to the right, the inside side is 0 */
+ inside_side = 0;
+
+ /* otherwise, the inside side is 1 */
+ if ( turn < 0 )
+ inside_side = 1;
+
+ /* IMPORTANT: WE DO NOT PROCESS THE INSIDE BORDER HERE! */
+ /* process the inside side */
+ /* error = ft_stroker_inside( stroker, inside_side ); */
+ /* if ( error ) */
+ /* goto Exit; */
+
+ /* process the outside side */
+ error = ft_stroker_outside( stroker, 1 - inside_side );
+ if ( error )
+ goto Exit;
+ }
+
+ /* we will first end our two subpaths */
+ ft_stroke_border_close( stroker->borders + 0 );
+ ft_stroke_border_close( stroker->borders + 1 );
+
+ /* now, add the reversed left subpath to "right" */
+ error = ft_stroker_add_reverse_left( stroker, 0 );
+ if ( error )
+ goto Exit;
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Stroker_GetCounts( FT_Stroker stroker,
+ FT_UInt *anum_points,
+ FT_UInt *anum_contours )
+ {
+ FT_UInt count1, count2, num_points = 0;
+ FT_UInt count3, count4, num_contours = 0;
+ FT_Error error;
+
+
+ error = ft_stroke_border_get_counts( stroker->borders + 0,
+ &count1, &count2 );
+ if ( error )
+ goto Exit;
+
+ error = ft_stroke_border_get_counts( stroker->borders + 1,
+ &count3, &count4 );
+ if ( error )
+ goto Exit;
+
+ num_points = count1 + count3;
+ num_contours = count2 + count4;
+
+ stroker->valid = 1;
+
+ Exit:
+ *anum_points = num_points;
+ *anum_contours = num_contours;
+ return error;
+ }
+
+
+ FT_EXPORT_DEF( void )
+ FT_Stroker_Export( FT_Stroker stroker,
+ FT_Outline* outline )
+ {
+ if ( stroker->valid )
+ {
+ ft_stroke_border_export( stroker->borders + 0, outline );
+ ft_stroke_border_export( stroker->borders + 1, outline );
+ }
+ }
+
+
+ /*
+ * The following is very similar to FT_Outline_Decompose, except
+ * that we do support opened paths, and do not scale the outline.
+ */
+ FT_EXPORT_DEF( FT_Error )
+ FT_Stroker_ParseOutline( FT_Stroker stroker,
+ FT_Outline* outline,
+ FT_Bool opened )
+ {
+ FT_Vector v_last;
+ FT_Vector v_control;
+ FT_Vector v_start;
+
+ FT_Vector* point;
+ FT_Vector* limit;
+ char* tags;
+
+ FT_Error error;
+
+ FT_Int n; /* index of contour in outline */
+ FT_UInt first; /* index of first point in contour */
+ FT_Int tag; /* current point's state */
+
+
+ if ( !outline || !stroker )
+ return FT_Err_Invalid_Argument;
+
+ first = 0;
+
+ for ( n = 0; n < outline->n_contours; n++ )
+ {
+ FT_Int last; /* index of last point in contour */
+
+
+ last = outline->contours[n];
+ limit = outline->points + last;
+
+ v_start = outline->points[first];
+ v_last = outline->points[last];
+
+ v_control = v_start;
+
+ point = outline->points + first;
+ tags = outline->tags + first;
+ tag = FT_CURVE_TAG( tags[0] );
+
+ /* A contour cannot start with a cubic control point! */
+ if ( tag == FT_CURVE_TAG_CUBIC )
+ goto Invalid_Outline;
+
+ /* check first point to determine origin */
+ if ( tag == FT_CURVE_TAG_CONIC )
+ {
+ /* First point is conic control. Yes, this happens. */
+ if ( FT_CURVE_TAG( outline->tags[last] ) == FT_CURVE_TAG_ON )
+ {
+ /* start at last point if it is on the curve */
+ v_start = v_last;
+ limit--;
+ }
+ else
+ {
+ /* if both first and last points are conic, */
+ /* start at their middle and record its position */
+ /* for closure */
+ v_start.x = ( v_start.x + v_last.x ) / 2;
+ v_start.y = ( v_start.y + v_last.y ) / 2;
+
+ v_last = v_start;
+ }
+ point--;
+ tags--;
+ }
+
+ error = FT_Stroker_BeginSubPath( stroker, &v_start, opened );
+ if ( error )
+ goto Exit;
+
+ while ( point < limit )
+ {
+ point++;
+ tags++;
+
+ tag = FT_CURVE_TAG( tags[0] );
+ switch ( tag )
+ {
+ case FT_CURVE_TAG_ON: /* emit a single line_to */
+ {
+ FT_Vector vec;
+
+
+ vec.x = point->x;
+ vec.y = point->y;
+
+ error = FT_Stroker_LineTo( stroker, &vec );
+ if ( error )
+ goto Exit;
+ continue;
+ }
+
+ case FT_CURVE_TAG_CONIC: /* consume conic arcs */
+ v_control.x = point->x;
+ v_control.y = point->y;
+
+ Do_Conic:
+ if ( point < limit )
+ {
+ FT_Vector vec;
+ FT_Vector v_middle;
+
+
+ point++;
+ tags++;
+ tag = FT_CURVE_TAG( tags[0] );
+
+ vec = point[0];
+
+ if ( tag == FT_CURVE_TAG_ON )
+ {
+ error = FT_Stroker_ConicTo( stroker, &v_control, &vec );
+ if ( error )
+ goto Exit;
+ continue;
+ }
+
+ if ( tag != FT_CURVE_TAG_CONIC )
+ goto Invalid_Outline;
+
+ v_middle.x = ( v_control.x + vec.x ) / 2;
+ v_middle.y = ( v_control.y + vec.y ) / 2;
+
+ error = FT_Stroker_ConicTo( stroker, &v_control, &v_middle );
+ if ( error )
+ goto Exit;
+
+ v_control = vec;
+ goto Do_Conic;
+ }
+
+ error = FT_Stroker_ConicTo( stroker, &v_control, &v_start );
+ goto Close;
+
+ default: /* FT_CURVE_TAG_CUBIC */
+ {
+ FT_Vector vec1, vec2;
+
+
+ if ( point + 1 > limit ||
+ FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC )
+ goto Invalid_Outline;
+
+ point += 2;
+ tags += 2;
+
+ vec1 = point[-2];
+ vec2 = point[-1];
+
+ if ( point <= limit )
+ {
+ FT_Vector vec;
+
+
+ vec = point[0];
+
+ error = FT_Stroker_CubicTo( stroker, &vec1, &vec2, &vec );
+ if ( error )
+ goto Exit;
+ continue;
+ }
+
+ error = FT_Stroker_CubicTo( stroker, &vec1, &vec2, &v_start );
+ goto Close;
+ }
+ }
+ }
+
+ Close:
+ if ( error )
+ goto Exit;
+
+ error = FT_Stroker_EndSubPath( stroker );
+ if ( error )
+ goto Exit;
+
+ first = last + 1;
+ }
+
+ return 0;
+
+ Exit:
+ return error;
+
+ Invalid_Outline:
+ return FT_Err_Invalid_Outline;
+ }
+
+
+/* END */
--- a/src/base/ftstroker.c
+++ /dev/null
@@ -1,1667 +1,0 @@
-/***************************************************************************/
-/* */
-/* ftstroker.c */
-/* */
-/* FreeType path stroker (body). */
-/* */
-/* Copyright 2002, 2003 by */
-/* David Turner, Robert Wilhelm, and Werner Lemberg. */
-/* */
-/* This file is part of the FreeType project, and may only be used, */
-/* modified, and distributed under the terms of the FreeType project */
-/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
-/* this file you indicate that you have read the license and */
-/* understand and accept it fully. */
-/* */
-/***************************************************************************/
-
-
-#include <ft2build.h>
-#include FT_STROKER_H
-#include FT_TRIGONOMETRY_H
-#include FT_INTERNAL_MEMORY_H
-#include FT_INTERNAL_DEBUG_H
-
-
- /***************************************************************************/
- /***************************************************************************/
- /***** *****/
- /***** BEZIER COMPUTATIONS *****/
- /***** *****/
- /***************************************************************************/
- /***************************************************************************/
-
-#define FT_SMALL_CONIC_THRESHOLD ( FT_ANGLE_PI / 6 )
-#define FT_SMALL_CUBIC_THRESHOLD ( FT_ANGLE_PI / 6 )
-#define FT_EPSILON 2
-
-#define FT_IS_SMALL( x ) ( (x) > -FT_EPSILON && (x) < FT_EPSILON )
-
-
- static FT_Pos
- ft_pos_abs( FT_Pos x )
- {
- return x >= 0 ? x : -x ;
- }
-
-
- static void
- ft_conic_split( FT_Vector* base )
- {
- FT_Pos a, b;
-
-
- base[4].x = base[2].x;
- b = base[1].x;
- a = base[3].x = ( base[2].x + b ) / 2;
- b = base[1].x = ( base[0].x + b ) / 2;
- base[2].x = ( a + b ) / 2;
-
- base[4].y = base[2].y;
- b = base[1].y;
- a = base[3].y = ( base[2].y + b ) / 2;
- b = base[1].y = ( base[0].y + b ) / 2;
- base[2].y = ( a + b ) / 2;
- }
-
-
- static FT_Bool
- ft_conic_is_small_enough( FT_Vector* base,
- FT_Angle *angle_in,
- FT_Angle *angle_out )
- {
- FT_Vector d1, d2;
- FT_Angle theta;
- FT_Int close1, close2;
-
-
- d1.x = base[1].x - base[2].x;
- d1.y = base[1].y - base[2].y;
- d2.x = base[0].x - base[1].x;
- d2.y = base[0].y - base[1].y;
-
- close1 = FT_IS_SMALL( d1.x ) && FT_IS_SMALL( d1.y );
- close2 = FT_IS_SMALL( d2.x ) && FT_IS_SMALL( d2.y );
-
- if ( close1 )
- {
- if ( close2 )
- *angle_in = *angle_out = 0;
- else
- *angle_in = *angle_out = FT_Atan2( d2.x, d2.y );
- }
- else if ( close2 )
- {
- *angle_in = *angle_out = FT_Atan2( d1.x, d1.y );
- }
- else
- {
- *angle_in = FT_Atan2( d1.x, d1.y );
- *angle_out = FT_Atan2( d2.x, d2.y );
- }
-
- theta = ft_pos_abs( FT_Angle_Diff( *angle_in, *angle_out ) );
-
- return FT_BOOL( theta < FT_SMALL_CONIC_THRESHOLD );
- }
-
-
- static void
- ft_cubic_split( FT_Vector* base )
- {
- FT_Pos a, b, c, d;
-
-
- base[6].x = base[3].x;
- c = base[1].x;
- d = base[2].x;
- base[1].x = a = ( base[0].x + c ) / 2;
- base[5].x = b = ( base[3].x + d ) / 2;
- c = ( c + d ) / 2;
- base[2].x = a = ( a + c ) / 2;
- base[4].x = b = ( b + c ) / 2;
- base[3].x = ( a + b ) / 2;
-
- base[6].y = base[3].y;
- c = base[1].y;
- d = base[2].y;
- base[1].y = a = ( base[0].y + c ) / 2;
- base[5].y = b = ( base[3].y + d ) / 2;
- c = ( c + d ) / 2;
- base[2].y = a = ( a + c ) / 2;
- base[4].y = b = ( b + c ) / 2;
- base[3].y = ( a + b ) / 2;
- }
-
-
- static FT_Bool
- ft_cubic_is_small_enough( FT_Vector* base,
- FT_Angle *angle_in,
- FT_Angle *angle_mid,
- FT_Angle *angle_out )
- {
- FT_Vector d1, d2, d3;
- FT_Angle theta1, theta2;
- FT_Int close1, close2, close3;
-
-
- d1.x = base[2].x - base[3].x;
- d1.y = base[2].y - base[3].y;
- d2.x = base[1].x - base[2].x;
- d2.y = base[1].y - base[2].y;
- d3.x = base[0].x - base[1].x;
- d3.y = base[0].y - base[1].y;
-
- close1 = FT_IS_SMALL( d1.x ) && FT_IS_SMALL( d1.y );
- close2 = FT_IS_SMALL( d2.x ) && FT_IS_SMALL( d2.y );
- close3 = FT_IS_SMALL( d3.x ) && FT_IS_SMALL( d3.y );
-
- if ( close1 || close3 )
- {
- if ( close2 )
- {
- /* basically a point */
- *angle_in = *angle_out = *angle_mid = 0;
- }
- else if ( close1 )
- {
- *angle_in = *angle_mid = FT_Atan2( d2.x, d2.y );
- *angle_out = FT_Atan2( d3.x, d3.y );
- }
- else /* close2 */
- {
- *angle_in = FT_Atan2( d1.x, d1.y );
- *angle_mid = *angle_out = FT_Atan2( d2.x, d2.y );
- }
- }
- else if ( close2 )
- {
- *angle_in = *angle_mid = FT_Atan2( d1.x, d1.y );
- *angle_out = FT_Atan2( d3.x, d3.y );
- }
- else
- {
- *angle_in = FT_Atan2( d1.x, d1.y );
- *angle_mid = FT_Atan2( d2.x, d2.y );
- *angle_out = FT_Atan2( d3.x, d3.y );
- }
-
- theta1 = ft_pos_abs( FT_Angle_Diff( *angle_in, *angle_mid ) );
- theta2 = ft_pos_abs( FT_Angle_Diff( *angle_mid, *angle_out ) );
-
- return FT_BOOL( theta1 < FT_SMALL_CUBIC_THRESHOLD &&
- theta2 < FT_SMALL_CUBIC_THRESHOLD );
- }
-
-
- /***************************************************************************/
- /***************************************************************************/
- /***** *****/
- /***** STROKE BORDERS *****/
- /***** *****/
- /***************************************************************************/
- /***************************************************************************/
-
- typedef enum
- {
- FT_STROKE_TAG_ON = 1, /* on-curve point */
- FT_STROKE_TAG_CUBIC = 2, /* cubic off-point */
- FT_STROKE_TAG_BEGIN = 4, /* sub-path start */
- FT_STROKE_TAG_END = 8 /* sub-path end */
-
- } FT_StrokeTags;
-
-
- typedef struct FT_StrokeBorderRec_
- {
- FT_UInt num_points;
- FT_UInt max_points;
- FT_Vector* points;
- FT_Byte* tags;
- FT_Bool movable;
- FT_Int start; /* index of current sub-path start point */
- FT_Memory memory;
-
- } FT_StrokeBorderRec, *FT_StrokeBorder;
-
-
- static FT_Error
- ft_stroke_border_grow( FT_StrokeBorder border,
- FT_UInt new_points )
- {
- FT_UInt old_max = border->max_points;
- FT_UInt new_max = border->num_points + new_points;
- FT_Error error = 0;
-
-
- if ( new_max > old_max )
- {
- FT_UInt cur_max = old_max;
- FT_Memory memory = border->memory;
-
-
- while ( cur_max < new_max )
- cur_max += ( cur_max >> 1 ) + 16;
-
- if ( FT_RENEW_ARRAY( border->points, old_max, cur_max ) ||
- FT_RENEW_ARRAY( border->tags, old_max, cur_max ) )
- goto Exit;
-
- border->max_points = cur_max;
- }
- Exit:
- return error;
- }
-
-
- static void
- ft_stroke_border_close( FT_StrokeBorder border )
- {
- FT_ASSERT( border->start >= 0 );
-
- /* don't record empty paths! */
- if ( border->num_points > (FT_UInt)border->start )
- {
- border->tags[border->start ] |= FT_STROKE_TAG_BEGIN;
- border->tags[border->num_points - 1] |= FT_STROKE_TAG_END;
- }
-
- border->start = -1;
- border->movable = 0;
- }
-
-
- static FT_Error
- ft_stroke_border_lineto( FT_StrokeBorder border,
- FT_Vector* to,
- FT_Bool movable )
- {
- FT_Error error = 0;
-
-
- FT_ASSERT( border->start >= 0 );
-
- if ( border->movable )
- {
- /* move last point */
- border->points[border->num_points - 1] = *to;
- }
- else
- {
- /* add one point */
- error = ft_stroke_border_grow( border, 1 );
- if ( !error )
- {
- FT_Vector* vec = border->points + border->num_points;
- FT_Byte* tag = border->tags + border->num_points;
-
-
- vec[0] = *to;
- tag[0] = FT_STROKE_TAG_ON;
-
- border->num_points += 1;
- }
- }
- border->movable = movable;
- return error;
- }
-
-
- static FT_Error
- ft_stroke_border_conicto( FT_StrokeBorder border,
- FT_Vector* control,
- FT_Vector* to )
- {
- FT_Error error;
-
-
- FT_ASSERT( border->start >= 0 );
-
- error = ft_stroke_border_grow( border, 2 );
- if ( !error )
- {
- FT_Vector* vec = border->points + border->num_points;
- FT_Byte* tag = border->tags + border->num_points;
-
- vec[0] = *control;
- vec[1] = *to;
-
- tag[0] = 0;
- tag[1] = FT_STROKE_TAG_ON;
-
- border->num_points += 2;
- }
- border->movable = 0;
- return error;
- }
-
-
- static FT_Error
- ft_stroke_border_cubicto( FT_StrokeBorder border,
- FT_Vector* control1,
- FT_Vector* control2,
- FT_Vector* to )
- {
- FT_Error error;
-
-
- FT_ASSERT( border->start >= 0 );
-
- error = ft_stroke_border_grow( border, 3 );
- if ( !error )
- {
- FT_Vector* vec = border->points + border->num_points;
- FT_Byte* tag = border->tags + border->num_points;
-
-
- vec[0] = *control1;
- vec[1] = *control2;
- vec[2] = *to;
-
- tag[0] = FT_STROKE_TAG_CUBIC;
- tag[1] = FT_STROKE_TAG_CUBIC;
- tag[2] = FT_STROKE_TAG_ON;
-
- border->num_points += 3;
- }
- border->movable = 0;
- return error;
- }
-
-
-#define FT_ARC_CUBIC_ANGLE ( FT_ANGLE_PI / 2 )
-
-
- static FT_Error
- ft_stroke_border_arcto( FT_StrokeBorder border,
- FT_Vector* center,
- FT_Fixed radius,
- FT_Angle angle_start,
- FT_Angle angle_diff )
- {
- FT_Angle total, angle, step, rotate, next, theta;
- FT_Vector a, b, a2, b2;
- FT_Fixed length;
- FT_Error error = 0;
-
-
- /* compute start point */
- FT_Vector_From_Polar( &a, radius, angle_start );
- a.x += center->x;
- a.y += center->y;
-
- total = angle_diff;
- angle = angle_start;
- rotate = ( angle_diff >= 0 ) ? FT_ANGLE_PI2 : -FT_ANGLE_PI2;
-
- while ( total != 0 )
- {
- step = total;
- if ( step > FT_ARC_CUBIC_ANGLE )
- step = FT_ARC_CUBIC_ANGLE;
-
- else if ( step < -FT_ARC_CUBIC_ANGLE )
- step = -FT_ARC_CUBIC_ANGLE;
-
- next = angle + step;
- theta = step;
- if ( theta < 0 )
- theta = -theta;
-
- theta >>= 1;
-
- /* compute end point */
- FT_Vector_From_Polar( &b, radius, next );
- b.x += center->x;
- b.y += center->y;
-
- /* compute first and second control points */
- length = FT_MulDiv( radius, FT_Sin( theta ) * 4,
- ( 0x10000L + FT_Cos( theta ) ) * 3 );
-
- FT_Vector_From_Polar( &a2, length, angle + rotate );
- a2.x += a.x;
- a2.y += a.y;
-
- FT_Vector_From_Polar( &b2, length, next - rotate );
- b2.x += b.x;
- b2.y += b.y;
-
- /* add cubic arc */
- error = ft_stroke_border_cubicto( border, &a2, &b2, &b );
- if ( error )
- break;
-
- /* process the rest of the arc ?? */
- a = b;
- total -= step;
- angle = next;
- }
-
- return error;
- }
-
-
- static FT_Error
- ft_stroke_border_moveto( FT_StrokeBorder border,
- FT_Vector* to )
- {
- /* close current open path if any ? */
- if ( border->start >= 0 )
- ft_stroke_border_close( border );
-
- border->start = border->num_points;
- border->movable = 0;
-
- return ft_stroke_border_lineto( border, to, 0 );
- }
-
-
- static void
- ft_stroke_border_init( FT_StrokeBorder border,
- FT_Memory memory )
- {
- border->memory = memory;
- border->points = NULL;
- border->tags = NULL;
-
- border->num_points = 0;
- border->max_points = 0;
- border->start = -1;
- }
-
-
- static void
- ft_stroke_border_reset( FT_StrokeBorder border )
- {
- border->num_points = 0;
- border->start = -1;
- }
-
-
- static void
- ft_stroke_border_done( FT_StrokeBorder border )
- {
- FT_Memory memory = border->memory;
-
-
- FT_FREE( border->points );
- FT_FREE( border->tags );
-
- border->num_points = 0;
- border->max_points = 0;
- border->start = -1;
- }
-
-
- static FT_Error
- ft_stroke_border_get_counts( FT_StrokeBorder border,
- FT_UInt *anum_points,
- FT_UInt *anum_contours )
- {
- FT_Error error = 0;
- FT_UInt num_points = 0;
- FT_UInt num_contours = 0;
-
- FT_UInt count = border->num_points;
- FT_Vector* point = border->points;
- FT_Byte* tags = border->tags;
- FT_Int in_contour = 0;
-
-
- for ( ; count > 0; count--, num_points++, point++, tags++ )
- {
- if ( tags[0] & FT_STROKE_TAG_BEGIN )
- {
- if ( in_contour != 0 )
- goto Fail;
-
- in_contour = 1;
- }
- else if ( in_contour == 0 )
- goto Fail;
-
- if ( tags[0] & FT_STROKE_TAG_END )
- {
- if ( in_contour == 0 )
- goto Fail;
-
- in_contour = 0;
- num_contours++;
- }
- }
-
- if ( in_contour != 0 )
- goto Fail;
-
- Exit:
- *anum_points = num_points;
- *anum_contours = num_contours;
- return error;
-
- Fail:
- num_points = 0;
- num_contours = 0;
- goto Exit;
- }
-
-
- static void
- ft_stroke_border_export( FT_StrokeBorder border,
- FT_Outline* outline )
- {
- /* copy point locations */
- FT_MEM_COPY( outline->points + outline->n_points,
- border->points,
- border->num_points * sizeof ( FT_Vector ) );
-
- /* copy tags */
- {
- FT_UInt count = border->num_points;
- FT_Byte* read = border->tags;
- FT_Byte* write = (FT_Byte*)outline->tags + outline->n_points;
-
-
- for ( ; count > 0; count--, read++, write++ )
- {
- if ( *read & FT_STROKE_TAG_ON )
- *write = FT_CURVE_TAG_ON;
- else if ( *read & FT_STROKE_TAG_CUBIC )
- *write = FT_CURVE_TAG_CUBIC;
- else
- *write = FT_CURVE_TAG_CONIC;
- }
- }
-
- /* copy contours */
- {
- FT_UInt count = border->num_points;
- FT_Byte* tags = border->tags;
- FT_Short* write = outline->contours + outline->n_contours;
- FT_Short idx = (FT_Short)outline->n_points;
-
-
- for ( ; count > 0; count--, tags++, idx++ )
- {
- if ( *tags & FT_STROKE_TAG_END )
- {
- *write++ = idx;
- outline->n_contours++;
- }
- }
- }
-
- outline->n_points = (short)( outline->n_points + border->num_points );
-
- FT_ASSERT( FT_Outline_Check( outline ) == 0 );
- }
-
-
- /***************************************************************************/
- /***************************************************************************/
- /***** *****/
- /***** STROKER *****/
- /***** *****/
- /***************************************************************************/
- /***************************************************************************/
-
-#define FT_SIDE_TO_ROTATE( s ) ( FT_ANGLE_PI2 - (s) * FT_ANGLE_PI )
-
- typedef struct FT_StrokerRec_
- {
- FT_Angle angle_in;
- FT_Angle angle_out;
- FT_Vector center;
- FT_Bool first_point;
- FT_Bool subpath_open;
- FT_Angle subpath_angle;
- FT_Vector subpath_start;
-
- FT_Stroker_LineCap line_cap;
- FT_Stroker_LineJoin line_join;
- FT_Fixed miter_limit;
- FT_Fixed radius;
-
- FT_Bool valid;
- FT_StrokeBorderRec borders[2];
- FT_Memory memory;
-
- } FT_StrokerRec;
-
-
- FT_EXPORT_DEF( FT_Error )
- FT_Stroker_New( FT_Memory memory,
- FT_Stroker *astroker )
- {
- FT_Error error;
- FT_Stroker stroker;
-
-
- if ( !FT_NEW( stroker ) )
- {
- stroker->memory = memory;
-
- ft_stroke_border_init( &stroker->borders[0], memory );
- ft_stroke_border_init( &stroker->borders[1], memory );
- }
- *astroker = stroker;
- return error;
- }
-
-
- FT_EXPORT_DEF( void )
- FT_Stroker_Set( FT_Stroker stroker,
- FT_Fixed radius,
- FT_Stroker_LineCap line_cap,
- FT_Stroker_LineJoin line_join,
- FT_Fixed miter_limit )
- {
- stroker->radius = radius;
- stroker->line_cap = line_cap;
- stroker->line_join = line_join;
- stroker->miter_limit = miter_limit;
-
- stroker->valid = 0;
-
- ft_stroke_border_reset( &stroker->borders[0] );
- ft_stroke_border_reset( &stroker->borders[1] );
- }
-
-
- FT_EXPORT_DEF( void )
- FT_Stroker_Done( FT_Stroker stroker )
- {
- if ( stroker )
- {
- FT_Memory memory = stroker->memory;
-
-
- ft_stroke_border_done( &stroker->borders[0] );
- ft_stroke_border_done( &stroker->borders[1] );
-
- stroker->memory = NULL;
- FT_FREE( stroker );
- }
- }
-
-
- /* creates a circular arc at a corner or cap */
- static FT_Error
- ft_stroker_arcto( FT_Stroker stroker,
- FT_Int side )
- {
- FT_Angle total, rotate;
- FT_Fixed radius = stroker->radius;
- FT_Error error = 0;
- FT_StrokeBorder border = stroker->borders + side;
-
-
- rotate = FT_SIDE_TO_ROTATE( side );
-
- total = FT_Angle_Diff( stroker->angle_in, stroker->angle_out );
- if ( total == FT_ANGLE_PI )
- total = -rotate * 2;
-
- error = ft_stroke_border_arcto( border,
- &stroker->center,
- radius,
- stroker->angle_in + rotate,
- total );
- border->movable = 0;
- return error;
- }
-
-
- /* adds a cap at the end of an opened path */
- static FT_Error
- ft_stroker_cap( FT_Stroker stroker,
- FT_Angle angle,
- FT_Int side )
- {
- FT_Error error = 0;
-
-
- if ( stroker->line_cap == FT_STROKER_LINECAP_ROUND )
- {
- /* add a round cap */
- stroker->angle_in = angle;
- stroker->angle_out = angle + FT_ANGLE_PI;
- error = ft_stroker_arcto( stroker, side );
- }
- else if ( stroker->line_cap == FT_STROKER_LINECAP_SQUARE )
- {
- /* add a square cap */
- FT_Vector delta, delta2;
- FT_Angle rotate = FT_SIDE_TO_ROTATE( side );
- FT_Fixed radius = stroker->radius;
- FT_StrokeBorder border = stroker->borders + side;
-
-
- FT_Vector_From_Polar( &delta2, radius, angle + rotate );
- FT_Vector_From_Polar( &delta, radius, angle );
-
- delta.x += stroker->center.x + delta2.x;
- delta.y += stroker->center.y + delta2.y;
-
- error = ft_stroke_border_lineto( border, &delta, 0 );
- if ( error )
- goto Exit;
-
- FT_Vector_From_Polar( &delta2, radius, angle - rotate );
- FT_Vector_From_Polar( &delta, radius, angle );
-
- delta.x += delta2.x + stroker->center.x;
- delta.y += delta2.y + stroker->center.y;
-
- error = ft_stroke_border_lineto( border, &delta, 0 );
- }
-
- Exit:
- return error;
- }
-
-
- /* process an inside corner, i.e. compute intersection */
- static FT_Error
- ft_stroker_inside( FT_Stroker stroker,
- FT_Int side)
- {
- FT_StrokeBorder border = stroker->borders + side;
- FT_Angle phi, theta, rotate;
- FT_Fixed length, thcos, sigma;
- FT_Vector delta;
- FT_Error error = 0;
-
-
- rotate = FT_SIDE_TO_ROTATE( side );
-
- /* compute median angle */
- theta = FT_Angle_Diff( stroker->angle_in, stroker->angle_out );
- if ( theta == FT_ANGLE_PI )
- theta = rotate;
- else
- theta = theta / 2;
-
- phi = stroker->angle_in + theta;
-
- thcos = FT_Cos( theta );
- sigma = FT_MulFix( stroker->miter_limit, thcos );
-
- if ( sigma < 0x10000L )
- {
- FT_Vector_From_Polar( &delta, stroker->radius,
- stroker->angle_out + rotate );
- delta.x += stroker->center.x;
- delta.y += stroker->center.y;
- border->movable = 0;
- }
- else
- {
- length = FT_DivFix( stroker->radius, thcos );
-
- FT_Vector_From_Polar( &delta, length, phi + rotate );
- delta.x += stroker->center.x;
- delta.y += stroker->center.y;
- }
-
- error = ft_stroke_border_lineto( border, &delta, 0 );
-
- return error;
- }
-
-
- /* process an outside corner, i.e. compute bevel/miter/round */
- static FT_Error
- ft_stroker_outside( FT_Stroker stroker,
- FT_Int side )
- {
- FT_StrokeBorder border = stroker->borders + side;
- FT_Error error;
- FT_Angle rotate;
-
-
- if ( stroker->line_join == FT_STROKER_LINEJOIN_ROUND )
- {
- error = ft_stroker_arcto( stroker, side );
- }
- else
- {
- /* this is a mitered or beveled corner */
- FT_Fixed sigma, radius = stroker->radius;
- FT_Angle theta, phi;
- FT_Fixed thcos;
- FT_Bool miter;
-
-
- rotate = FT_SIDE_TO_ROTATE( side );
- miter = FT_BOOL( stroker->line_join == FT_STROKER_LINEJOIN_MITER );
-
- theta = FT_Angle_Diff( stroker->angle_in, stroker->angle_out );
- if ( theta == FT_ANGLE_PI )
- {
- theta = rotate;
- phi = stroker->angle_in;
- }
- else
- {
- theta = theta / 2;
- phi = stroker->angle_in + theta + rotate;
- }
-
- thcos = FT_Cos( theta );
- sigma = FT_MulFix( stroker->miter_limit, thcos );
-
- if ( sigma >= 0x10000L )
- miter = 0;
-
- if ( miter ) /* this is a miter (broken angle) */
- {
- FT_Vector middle, delta;
- FT_Fixed length;
-
-
- /* compute middle point */
- FT_Vector_From_Polar( &middle,
- FT_MulFix( radius, stroker->miter_limit ),
- phi );
- middle.x += stroker->center.x;
- middle.y += stroker->center.y;
-
- /* compute first angle point */
- length = FT_MulFix( radius,
- FT_DivFix( 0x10000L - sigma,
- ft_pos_abs( FT_Sin( theta ) ) ) );
-
- FT_Vector_From_Polar( &delta, length, phi + rotate );
- delta.x += middle.x;
- delta.y += middle.y;
-
- error = ft_stroke_border_lineto( border, &delta, 0 );
- if ( error )
- goto Exit;
-
- /* compute second angle point */
- FT_Vector_From_Polar( &delta, length, phi - rotate );
- delta.x += middle.x;
- delta.y += middle.y;
-
- error = ft_stroke_border_lineto( border, &delta, 0 );
- if ( error )
- goto Exit;
-
- /* finally, add a movable end point */
- FT_Vector_From_Polar( &delta, radius, stroker->angle_out + rotate );
- delta.x += stroker->center.x;
- delta.y += stroker->center.y;
-
- error = ft_stroke_border_lineto( border, &delta, 1 );
- }
-
- else /* this is a bevel (intersection) */
- {
- FT_Fixed length;
- FT_Vector delta;
-
-
- length = FT_DivFix( stroker->radius, thcos );
-
- FT_Vector_From_Polar( &delta, length, phi );
- delta.x += stroker->center.x;
- delta.y += stroker->center.y;
-
- error = ft_stroke_border_lineto( border, &delta, 0 );
- if (error) goto Exit;
-
- /* now add end point */
- FT_Vector_From_Polar( &delta, stroker->radius,
- stroker->angle_out + rotate );
- delta.x += stroker->center.x;
- delta.y += stroker->center.y;
-
- error = ft_stroke_border_lineto( border, &delta, 1 );
- }
- }
-
- Exit:
- return error;
- }
-
-
- static FT_Error
- ft_stroker_process_corner( FT_Stroker stroker )
- {
- FT_Error error = 0;
- FT_Angle turn;
- FT_Int inside_side;
-
-
- turn = FT_Angle_Diff( stroker->angle_in, stroker->angle_out );
-
- /* no specific corner processing is required if the turn is 0 */
- if ( turn == 0 )
- goto Exit;
-
- /* when we turn to the right, the inside side is 0 */
- inside_side = 0;
-
- /* otherwise, the inside side is 1 */
- if ( turn < 0 )
- inside_side = 1;
-
- /* process the inside side */
- error = ft_stroker_inside( stroker, inside_side );
- if ( error )
- goto Exit;
-
- /* process the outside side */
- error = ft_stroker_outside( stroker, 1 - inside_side );
-
- Exit:
- return error;
- }
-
-
- /* add two points to the left and right borders corresponding to the */
- /* start of the subpath.. */
- static FT_Error
- ft_stroker_subpath_start( FT_Stroker stroker,
- FT_Angle start_angle )
- {
- FT_Vector delta;
- FT_Vector point;
- FT_Error error;
- FT_StrokeBorder border;
-
-
- FT_Vector_From_Polar( &delta, stroker->radius,
- start_angle + FT_ANGLE_PI2 );
-
- point.x = stroker->center.x + delta.x;
- point.y = stroker->center.y + delta.y;
-
- border = stroker->borders;
- error = ft_stroke_border_moveto( border, &point );
- if ( error )
- goto Exit;
-
- point.x = stroker->center.x - delta.x;
- point.y = stroker->center.y - delta.y;
-
- border++;
- error = ft_stroke_border_moveto( border, &point );
-
- /* save angle for last cap */
- stroker->subpath_angle = start_angle;
- stroker->first_point = 0;
-
- Exit:
- return error;
- }
-
-
- FT_EXPORT_DEF( FT_Error )
- FT_Stroker_LineTo( FT_Stroker stroker,
- FT_Vector* to )
- {
- FT_Error error = 0;
- FT_StrokeBorder border;
- FT_Vector delta;
- FT_Angle angle;
- FT_Int side;
-
- delta.x = to->x - stroker->center.x;
- delta.y = to->y - stroker->center.y;
-
- angle = FT_Atan2( delta.x, delta.y );
- FT_Vector_From_Polar( &delta, stroker->radius, angle + FT_ANGLE_PI2 );
-
- /* process corner if necessary */
- if ( stroker->first_point )
- {
- /* This is the first segment of a subpath. We need to */
- /* add a point to each border at their respective starting */
- /* point locations. */
- error = ft_stroker_subpath_start( stroker, angle );
- if ( error )
- goto Exit;
- }
- else
- {
- /* process the current corner */
- stroker->angle_out = angle;
- error = ft_stroker_process_corner( stroker );
- if ( error )
- goto Exit;
- }
-
- /* now add a line segment to both the "inside" and "outside" paths */
-
- for ( border = stroker->borders, side = 1; side >= 0; side--, border++ )
- {
- FT_Vector point;
-
-
- point.x = to->x + delta.x;
- point.y = to->y + delta.y;
-
- error = ft_stroke_border_lineto( border, &point, 1 );
- if ( error )
- goto Exit;
-
- delta.x = -delta.x;
- delta.y = -delta.y;
- }
-
- stroker->angle_in = angle;
- stroker->center = *to;
-
- Exit:
- return error;
- }
-
-
- FT_EXPORT_DEF( FT_Error )
- FT_Stroker_ConicTo( FT_Stroker stroker,
- FT_Vector* control,
- FT_Vector* to )
- {
- FT_Error error = 0;
- FT_Vector bez_stack[34];
- FT_Vector* arc;
- FT_Vector* limit = bez_stack + 30;
- FT_Angle start_angle;
- FT_Bool first_arc = 1;
-
-
- arc = bez_stack;
- arc[0] = *to;
- arc[1] = *control;
- arc[2] = stroker->center;
-
- while ( arc >= bez_stack )
- {
- FT_Angle angle_in, angle_out;
-
-
- angle_in = angle_out = 0; /* remove compiler warnings */
-
- if ( arc < limit &&
- !ft_conic_is_small_enough( arc, &angle_in, &angle_out ) )
- {
- ft_conic_split( arc );
- arc += 2;
- continue;
- }
-
- if ( first_arc )
- {
- first_arc = 0;
-
- start_angle = angle_in;
-
- /* process corner if necessary */
- if ( stroker->first_point )
- error = ft_stroker_subpath_start( stroker, start_angle );
- else
- {
- stroker->angle_out = start_angle;
- error = ft_stroker_process_corner( stroker );
- }
- }
-
- /* the arc's angle is small enough; we can add it directly to each */
- /* border */
- {
- FT_Vector ctrl, end;
- FT_Angle theta, phi, rotate;
- FT_Fixed length;
- FT_Int side;
-
-
- theta = FT_Angle_Diff( angle_in, angle_out ) / 2;
- phi = angle_in + theta;
- length = FT_DivFix( stroker->radius, FT_Cos( theta ) );
-
- for ( side = 0; side <= 1; side++ )
- {
- rotate = FT_SIDE_TO_ROTATE( side );
-
- /* compute control point */
- FT_Vector_From_Polar( &ctrl, length, phi + rotate );
- ctrl.x += arc[1].x;
- ctrl.y += arc[1].y;
-
- /* compute end point */
- FT_Vector_From_Polar( &end, stroker->radius, angle_out + rotate );
- end.x += arc[0].x;
- end.y += arc[0].y;
-
- error = ft_stroke_border_conicto( stroker->borders + side,
- &ctrl, &end );
- if ( error )
- goto Exit;
- }
- }
-
- arc -= 2;
-
- if ( arc < bez_stack )
- stroker->angle_in = angle_out;
- }
-
- stroker->center = *to;
-
- Exit:
- return error;
- }
-
-
- FT_EXPORT_DEF( FT_Error )
- FT_Stroker_CubicTo( FT_Stroker stroker,
- FT_Vector* control1,
- FT_Vector* control2,
- FT_Vector* to )
- {
- FT_Error error = 0;
- FT_Vector bez_stack[37];
- FT_Vector* arc;
- FT_Vector* limit = bez_stack + 32;
- FT_Angle start_angle;
- FT_Bool first_arc = 1;
-
-
- arc = bez_stack;
- arc[0] = *to;
- arc[1] = *control2;
- arc[2] = *control1;
- arc[3] = stroker->center;
-
- while ( arc >= bez_stack )
- {
- FT_Angle angle_in, angle_mid, angle_out;
-
-
- /* remove compiler warnings */
- angle_in = angle_out = angle_mid = 0;
-
- if ( arc < limit &&
- !ft_cubic_is_small_enough( arc, &angle_in,
- &angle_mid, &angle_out ) )
- {
- ft_cubic_split( arc );
- arc += 3;
- continue;
- }
-
- if ( first_arc )
- {
- first_arc = 0;
-
- /* process corner if necessary */
- start_angle = angle_in;
-
- if ( stroker->first_point )
- error = ft_stroker_subpath_start( stroker, start_angle );
- else
- {
- stroker->angle_out = start_angle;
- error = ft_stroker_process_corner( stroker );
- }
- if ( error )
- goto Exit;
- }
-
- /* the arc's angle is small enough; we can add it directly to each */
- /* border */
- {
- FT_Vector ctrl1, ctrl2, end;
- FT_Angle theta1, phi1, theta2, phi2, rotate;
- FT_Fixed length1, length2;
- FT_Int side;
-
-
- theta1 = ft_pos_abs( angle_mid - angle_in ) / 2;
- theta2 = ft_pos_abs( angle_out - angle_mid ) / 2;
- phi1 = (angle_mid + angle_in ) / 2;
- phi2 = (angle_mid + angle_out ) / 2;
- length1 = FT_DivFix( stroker->radius, FT_Cos( theta1 ) );
- length2 = FT_DivFix( stroker->radius, FT_Cos(theta2) );
-
- for ( side = 0; side <= 1; side++ )
- {
- rotate = FT_SIDE_TO_ROTATE( side );
-
- /* compute control points */
- FT_Vector_From_Polar( &ctrl1, length1, phi1 + rotate );
- ctrl1.x += arc[2].x;
- ctrl1.y += arc[2].y;
-
- FT_Vector_From_Polar( &ctrl2, length2, phi2 + rotate );
- ctrl2.x += arc[1].x;
- ctrl2.y += arc[1].y;
-
- /* compute end point */
- FT_Vector_From_Polar( &end, stroker->radius, angle_out + rotate );
- end.x += arc[0].x;
- end.y += arc[0].y;
-
- error = ft_stroke_border_cubicto( stroker->borders + side,
- &ctrl1, &ctrl2, &end );
- if ( error )
- goto Exit;
- }
- }
-
- arc -= 3;
- if ( arc < bez_stack )
- stroker->angle_in = angle_out;
- }
-
- stroker->center = *to;
-
- Exit:
- return error;
- }
-
-
- FT_EXPORT_DEF( FT_Error )
- FT_Stroker_BeginSubPath( FT_Stroker stroker,
- FT_Vector* to,
- FT_Bool open )
- {
- /* We cannot process the first point, because there is not enough */
- /* information regarding its corner/cap. The latter will be processed */
- /* in the "end_subpath" routine. */
- /* */
- stroker->first_point = 1;
- stroker->center = *to;
- stroker->subpath_open = open;
-
- /* record the subpath start point index for each border */
- stroker->subpath_start = *to;
- return 0;
- }
-
-
- static FT_Error
- ft_stroker_add_reverse_left( FT_Stroker stroker,
- FT_Bool open )
- {
- FT_StrokeBorder right = stroker->borders + 0;
- FT_StrokeBorder left = stroker->borders + 1;
- FT_Int new_points;
- FT_Error error = 0;
-
-
- FT_ASSERT( left->start >= 0 );
-
- new_points = left->num_points - left->start;
- if ( new_points > 0 )
- {
- error = ft_stroke_border_grow( right, (FT_UInt)new_points );
- if ( error )
- goto Exit;
-
- {
- FT_Vector* dst_point = right->points + right->num_points;
- FT_Byte* dst_tag = right->tags + right->num_points;
- FT_Vector* src_point = left->points + left->num_points - 1;
- FT_Byte* src_tag = left->tags + left->num_points - 1;
-
- while ( src_point >= left->points + left->start )
- {
- *dst_point = *src_point;
- *dst_tag = *src_tag;
-
- if ( open )
- dst_tag[0] &= ~( FT_STROKE_TAG_BEGIN | FT_STROKE_TAG_END );
- else
- {
- /* switch begin/end tags if necessary.. */
- if ( dst_tag[0] & ( FT_STROKE_TAG_BEGIN | FT_STROKE_TAG_END ) )
- dst_tag[0] ^= ( FT_STROKE_TAG_BEGIN | FT_STROKE_TAG_END );
- }
-
- src_point--;
- src_tag--;
- dst_point++;
- dst_tag++;
- }
- }
-
- left->num_points = left->start;
- right->num_points += new_points;
-
- right->movable = 0;
- left->movable = 0;
- }
-
- Exit:
- return error;
- }
-
-
- /* there's a lot of magic in this function! */
- FT_EXPORT_DEF( FT_Error )
- FT_Stroker_EndSubPath( FT_Stroker stroker )
- {
- FT_Error error = 0;
-
-
- if ( stroker->subpath_open )
- {
- FT_StrokeBorder right = stroker->borders;
-
- /* All right, this is an opened path, we need to add a cap between */
- /* right & left, add the reverse of left, then add a final cap */
- /* between left & right. */
- error = ft_stroker_cap( stroker, stroker->angle_in, 0 );
- if ( error )
- goto Exit;
-
- /* add reversed points from "left" to "right" */
- error = ft_stroker_add_reverse_left( stroker, 1 );
- if ( error )
- goto Exit;
-
- /* now add the final cap */
- stroker->center = stroker->subpath_start;
- error = ft_stroker_cap( stroker,
- stroker->subpath_angle + FT_ANGLE_PI, 0 );
- if ( error )
- goto Exit;
-
- /* Now end the right subpath accordingly. The left one is */
- /* rewind and doesn't need further processing. */
- ft_stroke_border_close( right );
- }
- else
- {
- FT_Angle turn;
- FT_Int inside_side;
-
-
- /* process the corner */
- stroker->angle_out = stroker->subpath_angle;
- turn = FT_Angle_Diff( stroker->angle_in,
- stroker->angle_out );
-
- /* no specific corner processing is required if the turn is 0 */
- if ( turn != 0 )
- {
- /* when we turn to the right, the inside side is 0 */
- inside_side = 0;
-
- /* otherwise, the inside side is 1 */
- if ( turn < 0 )
- inside_side = 1;
-
- /* IMPORTANT: WE DO NOT PROCESS THE INSIDE BORDER HERE! */
- /* process the inside side */
- /* error = ft_stroker_inside( stroker, inside_side ); */
- /* if ( error ) */
- /* goto Exit; */
-
- /* process the outside side */
- error = ft_stroker_outside( stroker, 1 - inside_side );
- if ( error )
- goto Exit;
- }
-
- /* we will first end our two subpaths */
- ft_stroke_border_close( stroker->borders + 0 );
- ft_stroke_border_close( stroker->borders + 1 );
-
- /* now, add the reversed left subpath to "right" */
- error = ft_stroker_add_reverse_left( stroker, 0 );
- if ( error )
- goto Exit;
- }
-
- Exit:
- return error;
- }
-
-
- FT_EXPORT_DEF( FT_Error )
- FT_Stroker_GetCounts( FT_Stroker stroker,
- FT_UInt *anum_points,
- FT_UInt *anum_contours )
- {
- FT_UInt count1, count2, num_points = 0;
- FT_UInt count3, count4, num_contours = 0;
- FT_Error error;
-
-
- error = ft_stroke_border_get_counts( stroker->borders + 0,
- &count1, &count2 );
- if ( error )
- goto Exit;
-
- error = ft_stroke_border_get_counts( stroker->borders + 1,
- &count3, &count4 );
- if ( error )
- goto Exit;
-
- num_points = count1 + count3;
- num_contours = count2 + count4;
-
- stroker->valid = 1;
-
- Exit:
- *anum_points = num_points;
- *anum_contours = num_contours;
- return error;
- }
-
-
- FT_EXPORT_DEF( void )
- FT_Stroker_Export( FT_Stroker stroker,
- FT_Outline* outline )
- {
- if ( stroker->valid )
- {
- ft_stroke_border_export( stroker->borders + 0, outline );
- ft_stroke_border_export( stroker->borders + 1, outline );
- }
- }
-
-
- /*
- * The following is very similar to FT_Outline_Decompose, except
- * that we do support opened paths, and do not scale the outline.
- */
- FT_EXPORT_DEF( FT_Error )
- FT_Stroker_ParseOutline( FT_Stroker stroker,
- FT_Outline* outline,
- FT_Bool opened )
- {
- FT_Vector v_last;
- FT_Vector v_control;
- FT_Vector v_start;
-
- FT_Vector* point;
- FT_Vector* limit;
- char* tags;
-
- FT_Error error;
-
- FT_Int n; /* index of contour in outline */
- FT_UInt first; /* index of first point in contour */
- FT_Int tag; /* current point's state */
-
-
- if ( !outline || !stroker )
- return FT_Err_Invalid_Argument;
-
- first = 0;
-
- for ( n = 0; n < outline->n_contours; n++ )
- {
- FT_Int last; /* index of last point in contour */
-
-
- last = outline->contours[n];
- limit = outline->points + last;
-
- v_start = outline->points[first];
- v_last = outline->points[last];
-
- v_control = v_start;
-
- point = outline->points + first;
- tags = outline->tags + first;
- tag = FT_CURVE_TAG( tags[0] );
-
- /* A contour cannot start with a cubic control point! */
- if ( tag == FT_CURVE_TAG_CUBIC )
- goto Invalid_Outline;
-
- /* check first point to determine origin */
- if ( tag == FT_CURVE_TAG_CONIC )
- {
- /* First point is conic control. Yes, this happens. */
- if ( FT_CURVE_TAG( outline->tags[last] ) == FT_CURVE_TAG_ON )
- {
- /* start at last point if it is on the curve */
- v_start = v_last;
- limit--;
- }
- else
- {
- /* if both first and last points are conic, */
- /* start at their middle and record its position */
- /* for closure */
- v_start.x = ( v_start.x + v_last.x ) / 2;
- v_start.y = ( v_start.y + v_last.y ) / 2;
-
- v_last = v_start;
- }
- point--;
- tags--;
- }
-
- error = FT_Stroker_BeginSubPath( stroker, &v_start, opened );
- if ( error )
- goto Exit;
-
- while ( point < limit )
- {
- point++;
- tags++;
-
- tag = FT_CURVE_TAG( tags[0] );
- switch ( tag )
- {
- case FT_CURVE_TAG_ON: /* emit a single line_to */
- {
- FT_Vector vec;
-
-
- vec.x = point->x;
- vec.y = point->y;
-
- error = FT_Stroker_LineTo( stroker, &vec );
- if ( error )
- goto Exit;
- continue;
- }
-
- case FT_CURVE_TAG_CONIC: /* consume conic arcs */
- v_control.x = point->x;
- v_control.y = point->y;
-
- Do_Conic:
- if ( point < limit )
- {
- FT_Vector vec;
- FT_Vector v_middle;
-
-
- point++;
- tags++;
- tag = FT_CURVE_TAG( tags[0] );
-
- vec = point[0];
-
- if ( tag == FT_CURVE_TAG_ON )
- {
- error = FT_Stroker_ConicTo( stroker, &v_control, &vec );
- if ( error )
- goto Exit;
- continue;
- }
-
- if ( tag != FT_CURVE_TAG_CONIC )
- goto Invalid_Outline;
-
- v_middle.x = ( v_control.x + vec.x ) / 2;
- v_middle.y = ( v_control.y + vec.y ) / 2;
-
- error = FT_Stroker_ConicTo( stroker, &v_control, &v_middle );
- if ( error )
- goto Exit;
-
- v_control = vec;
- goto Do_Conic;
- }
-
- error = FT_Stroker_ConicTo( stroker, &v_control, &v_start );
- goto Close;
-
- default: /* FT_CURVE_TAG_CUBIC */
- {
- FT_Vector vec1, vec2;
-
-
- if ( point + 1 > limit ||
- FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC )
- goto Invalid_Outline;
-
- point += 2;
- tags += 2;
-
- vec1 = point[-2];
- vec2 = point[-1];
-
- if ( point <= limit )
- {
- FT_Vector vec;
-
-
- vec = point[0];
-
- error = FT_Stroker_CubicTo( stroker, &vec1, &vec2, &vec );
- if ( error )
- goto Exit;
- continue;
- }
-
- error = FT_Stroker_CubicTo( stroker, &vec1, &vec2, &v_start );
- goto Close;
- }
- }
- }
-
- Close:
- if ( error )
- goto Exit;
-
- error = FT_Stroker_EndSubPath( stroker );
- if ( error )
- goto Exit;
-
- first = last + 1;
- }
-
- return 0;
-
- Exit:
- return error;
-
- Invalid_Outline:
- return FT_Err_Invalid_Outline;
- }
-
-
-/* END */
--- a/src/base/rules.mk
+++ b/src/base/rules.mk
@@ -49,14 +49,14 @@
# object. It will then be linked to the final executable only if one of its
# symbols is used by the application.
#
-BASE_EXT_SRC := $(BASE_)ftglyph.c \
- $(BASE_)ftmm.c \
- $(BASE_)ftbdf.c \
- $(BASE_)fttype1.c \
- $(BASE_)ftxf86.c \
- $(BASE_)ftpfr.c \
- $(BASE_)ftstroker.c \
- $(BASE_)ftwinfnt.c \
+BASE_EXT_SRC := $(BASE_)ftglyph.c \
+ $(BASE_)ftmm.c \
+ $(BASE_)ftbdf.c \
+ $(BASE_)fttype1.c \
+ $(BASE_)ftxf86.c \
+ $(BASE_)ftpfr.c \
+ $(BASE_)ftstroke.c \
+ $(BASE_)ftwinfnt.c \
$(BASE_)ftbbox.c
# Default extensions objects
--- a/src/pcf/Jamfile
+++ b/src/pcf/Jamfile
@@ -1,4 +1,4 @@
-# FreeType 2 src/pcf Jamfile (c) 2001 David Turner
+# FreeType 2 src/pcf Jamfile (c) 2001, 2003 David Turner
#
SubDir FT2_TOP $(FT2_SRC_DIR) pcf ;
@@ -8,7 +8,7 @@
if $(FT2_MULTI)
{
- _sources = pcfdriver pcfread pcfutil ;
+ _sources = pcfdrivr pcfread pcfutil ;
}
else
{
--- a/src/pcf/pcf.c
+++ b/src/pcf/pcf.c
@@ -2,7 +2,7 @@
FreeType font driver for pcf fonts
- Copyright 2000-2001 by
+ Copyright 2000-2001, 2003 by
Francesco Zappa Nardelli
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -31,6 +31,6 @@
#include <ft2build.h>
#include "pcfutil.c"
#include "pcfread.c"
-#include "pcfdriver.c"
+#include "pcfdrivr.c"
/* END */
--- a/src/pcf/pcfdriver.c
+++ /dev/null
@@ -1,559 +1,0 @@
-/* pcfdriver.c
-
- FreeType font driver for pcf files
-
- Copyright (C) 2000, 2001, 2002, 2003 by
- Francesco Zappa Nardelli
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-*/
-
-
-#include <ft2build.h>
-
-#include FT_INTERNAL_DEBUG_H
-#include FT_INTERNAL_STREAM_H
-#include FT_INTERNAL_OBJECTS_H
-#include FT_GZIP_H
-#include FT_ERRORS_H
-#include FT_BDF_H
-
-#include "pcf.h"
-#include "pcfdriver.h"
-#include "pcfutil.h"
-#include "pcfread.h"
-
-#include "pcferror.h"
-
-#undef FT_COMPONENT
-#define FT_COMPONENT trace_pcfread
-
-
- typedef struct PCF_CMapRec_
- {
- FT_CMapRec cmap;
- FT_UInt num_encodings;
- PCF_Encoding encodings;
-
- } PCF_CMapRec, *PCF_CMap;
-
-
- FT_CALLBACK_DEF( FT_Error )
- pcf_cmap_init( PCF_CMap cmap )
- {
- PCF_Face face = (PCF_Face)FT_CMAP_FACE( cmap );
-
-
- cmap->num_encodings = (FT_UInt)face->nencodings;
- cmap->encodings = face->encodings;
-
- return FT_Err_Ok;
- }
-
-
- FT_CALLBACK_DEF( void )
- pcf_cmap_done( PCF_CMap cmap )
- {
- cmap->encodings = NULL;
- cmap->num_encodings = 0;
- }
-
-
- FT_CALLBACK_DEF( FT_UInt )
- pcf_cmap_char_index( PCF_CMap cmap,
- FT_UInt32 charcode )
- {
- PCF_Encoding encodings = cmap->encodings;
- FT_UInt min, max, mid;
- FT_UInt result = 0;
-
-
- min = 0;
- max = cmap->num_encodings;
-
- while ( min < max )
- {
- FT_UInt32 code;
-
-
- mid = ( min + max ) >> 1;
- code = encodings[mid].enc;
-
- if ( charcode == code )
- {
- result = encodings[mid].glyph + 1;
- break;
- }
-
- if ( charcode < code )
- max = mid;
- else
- min = mid + 1;
- }
-
- return result;
- }
-
-
- FT_CALLBACK_DEF( FT_UInt )
- pcf_cmap_char_next( PCF_CMap cmap,
- FT_UInt32 *acharcode )
- {
- PCF_Encoding encodings = cmap->encodings;
- FT_UInt min, max, mid;
- FT_UInt32 charcode = *acharcode + 1;
- FT_UInt result = 0;
-
-
- min = 0;
- max = cmap->num_encodings;
-
- while ( min < max )
- {
- FT_UInt32 code;
-
-
- mid = ( min + max ) >> 1;
- code = encodings[mid].enc;
-
- if ( charcode == code )
- {
- result = encodings[mid].glyph + 1;
- goto Exit;
- }
-
- if ( charcode < code )
- max = mid;
- else
- min = mid + 1;
- }
-
- charcode = 0;
- if ( min < cmap->num_encodings )
- {
- charcode = encodings[min].enc;
- result = encodings[min].glyph + 1;
- }
-
- Exit:
- *acharcode = charcode;
- return result;
- }
-
-
- FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec pcf_cmap_class =
- {
- sizeof( PCF_CMapRec ),
- (FT_CMap_InitFunc) pcf_cmap_init,
- (FT_CMap_DoneFunc) pcf_cmap_done,
- (FT_CMap_CharIndexFunc)pcf_cmap_char_index,
- (FT_CMap_CharNextFunc) pcf_cmap_char_next
- };
-
-
- /*************************************************************************/
- /* */
- /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
- /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
- /* messages during execution. */
- /* */
-#undef FT_COMPONENT
-#define FT_COMPONENT trace_pcfdriver
-
-
- FT_CALLBACK_DEF( FT_Error )
- PCF_Face_Done( PCF_Face face )
- {
- FT_Memory memory = FT_FACE_MEMORY( face );
-
-
- FT_FREE( face->encodings );
- FT_FREE( face->metrics );
-
- /* free properties */
- {
- PCF_Property prop = face->properties;
- FT_Int i;
-
-
- for ( i = 0; i < face->nprops; i++ )
- {
- prop = &face->properties[i];
-
- FT_FREE( prop->name );
- if ( prop->isString )
- FT_FREE( prop->value );
- }
-
- FT_FREE( face->properties );
- }
-
- FT_FREE( face->toc.tables );
- FT_FREE( face->root.family_name );
- FT_FREE( face->root.available_sizes );
- FT_FREE( face->charset_encoding );
- FT_FREE( face->charset_registry );
-
- FT_TRACE4(( "PCF_Face_Done: done face\n" ));
-
- /* close gzip stream if any */
- if ( face->root.stream == &face->gzip_stream )
- {
- FT_Stream_Close( &face->gzip_stream );
- face->root.stream = face->gzip_source;
- }
-
- return PCF_Err_Ok;
- }
-
-
- FT_CALLBACK_DEF( FT_Error )
- PCF_Face_Init( FT_Stream stream,
- PCF_Face face,
- FT_Int face_index,
- FT_Int num_params,
- FT_Parameter* params )
- {
- FT_Error error = PCF_Err_Ok;
-
- FT_UNUSED( num_params );
- FT_UNUSED( params );
- FT_UNUSED( face_index );
-
-
- error = pcf_load_font( stream, face );
- if ( error )
- {
- FT_Error error2;
-
-
- /* this didn't work, try gzip support! */
- error2 = FT_Stream_OpenGzip( &face->gzip_stream, stream );
- if ( error2 == FT_Err_Unimplemented_Feature )
- goto Fail;
-
- error = error2;
- if ( error )
- goto Fail;
-
- face->gzip_source = stream;
- face->root.stream = &face->gzip_stream;
-
- stream = face->root.stream;
-
- error = pcf_load_font( stream, face );
- if ( error )
- goto Fail;
- }
-
- /* set-up charmap */
- {
- FT_String *charset_registry, *charset_encoding;
- FT_Bool unicode_charmap = 0;
-
-
- charset_registry = face->charset_registry;
- charset_encoding = face->charset_encoding;
-
- if ( ( charset_registry != NULL ) &&
- ( charset_encoding != NULL ) )
- {
- char* s = face->charset_registry;
-
-
- /* Uh, oh, compare first letters manually to avoid dependency
- on locales. */
- if ( ( s[0] == 'i' || s[0] == 'I' ) &&
- ( s[1] == 's' || s[1] == 'S' ) &&
- ( s[2] == 'o' || s[2] == 'O' ) )
- {
- s += 3;
- if ( !ft_strcmp( s, "10646" ) ||
- ( !ft_strcmp( s, "8859" ) &&
- !ft_strcmp( face->charset_encoding, "1" ) ) )
- unicode_charmap = 1;
- }
- }
-
- {
- FT_CharMapRec charmap;
-
-
- charmap.face = FT_FACE( face );
- charmap.encoding = FT_ENCODING_NONE;
- charmap.platform_id = 0;
- charmap.encoding_id = 0;
-
- if ( unicode_charmap )
- {
- charmap.encoding = FT_ENCODING_UNICODE;
- charmap.platform_id = 3;
- charmap.encoding_id = 1;
- }
-
- error = FT_CMap_New( &pcf_cmap_class, NULL, &charmap, NULL );
-
-#if 0
- /* Select default charmap */
- if (face->root.num_charmaps)
- face->root.charmap = face->root.charmaps[0];
-#endif
- }
- }
-
- Exit:
- return error;
-
- Fail:
- FT_TRACE2(( "[not a valid PCF file]\n" ));
- error = PCF_Err_Unknown_File_Format; /* error */
- goto Exit;
- }
-
-
- static FT_Error
- PCF_Set_Pixel_Size( FT_Size size )
- {
- PCF_Face face = (PCF_Face)FT_SIZE_FACE( size );
-
-
- FT_TRACE4(( "rec %d - pres %d\n", size->metrics.y_ppem,
- face->root.available_sizes->height ));
-
- if ( size->metrics.y_ppem == face->root.available_sizes->height )
- {
- size->metrics.ascender = face->accel.fontAscent << 6;
- size->metrics.descender = face->accel.fontDescent * (-64);
-#if 0
- size->metrics.height = face->accel.maxbounds.ascent << 6;
-#endif
- size->metrics.height = size->metrics.ascender -
- size->metrics.descender;
-
- size->metrics.max_advance = face->accel.maxbounds.characterWidth << 6;
-
- return PCF_Err_Ok;
- }
- else
- {
- FT_TRACE4(( "size WRONG\n" ));
- return PCF_Err_Invalid_Pixel_Size;
- }
- }
-
-
- static FT_Error
- PCF_Glyph_Load( FT_GlyphSlot slot,
- FT_Size size,
- FT_UInt glyph_index,
- FT_Int32 load_flags )
- {
- PCF_Face face = (PCF_Face)FT_SIZE_FACE( size );
- FT_Stream stream = face->root.stream;
- FT_Error error = PCF_Err_Ok;
- FT_Bitmap* bitmap = &slot->bitmap;
- PCF_Metric metric;
- int bytes;
-
- FT_UNUSED( load_flags );
-
-
- FT_TRACE4(( "load_glyph %d ---", glyph_index ));
-
- if ( !face )
- {
- error = PCF_Err_Invalid_Argument;
- goto Exit;
- }
-
- if ( glyph_index > 0 )
- glyph_index--;
-
- metric = face->metrics + glyph_index;
-
- bitmap->rows = metric->ascent + metric->descent;
- bitmap->width = metric->rightSideBearing - metric->leftSideBearing;
- bitmap->num_grays = 1;
- bitmap->pixel_mode = FT_PIXEL_MODE_MONO;
-
- FT_TRACE6(( "BIT_ORDER %d ; BYTE_ORDER %d ; GLYPH_PAD %d\n",
- PCF_BIT_ORDER( face->bitmapsFormat ),
- PCF_BYTE_ORDER( face->bitmapsFormat ),
- PCF_GLYPH_PAD( face->bitmapsFormat ) ));
-
- switch ( PCF_GLYPH_PAD( face->bitmapsFormat ) )
- {
- case 1:
- bitmap->pitch = ( bitmap->width + 7 ) >> 3;
- break;
-
- case 2:
- bitmap->pitch = ( ( bitmap->width + 15 ) >> 4 ) << 1;
- break;
-
- case 4:
- bitmap->pitch = ( ( bitmap->width + 31 ) >> 5 ) << 2;
- break;
-
- case 8:
- bitmap->pitch = ( ( bitmap->width + 63 ) >> 6 ) << 3;
- break;
-
- default:
- return PCF_Err_Invalid_File_Format;
- }
-
- /* XXX: to do: are there cases that need repadding the bitmap? */
- bytes = bitmap->pitch * bitmap->rows;
-
- error = ft_glyphslot_alloc_bitmap( slot, bytes );
- if ( error )
- goto Exit;
-
- if ( FT_STREAM_SEEK( metric->bits ) ||
- FT_STREAM_READ( bitmap->buffer, bytes ) )
- goto Exit;
-
- if ( PCF_BIT_ORDER( face->bitmapsFormat ) != MSBFirst )
- BitOrderInvert( bitmap->buffer, bytes );
-
- if ( ( PCF_BYTE_ORDER( face->bitmapsFormat ) !=
- PCF_BIT_ORDER( face->bitmapsFormat ) ) )
- {
- switch ( PCF_SCAN_UNIT( face->bitmapsFormat ) )
- {
- case 1:
- break;
-
- case 2:
- TwoByteSwap( bitmap->buffer, bytes );
- break;
-
- case 4:
- FourByteSwap( bitmap->buffer, bytes );
- break;
- }
- }
-
- slot->bitmap_left = metric->leftSideBearing;
- slot->bitmap_top = metric->ascent;
-
- slot->metrics.horiAdvance = metric->characterWidth << 6 ;
- slot->metrics.horiBearingX = metric->leftSideBearing << 6 ;
- slot->metrics.horiBearingY = metric->ascent << 6 ;
- slot->metrics.width = ( metric->rightSideBearing -
- metric->leftSideBearing ) << 6;
- slot->metrics.height = bitmap->rows << 6;
-
- slot->linearHoriAdvance = (FT_Fixed)bitmap->width << 16;
- slot->format = FT_GLYPH_FORMAT_BITMAP;
-
- FT_TRACE4(( " --- ok\n" ));
-
- Exit:
- return error;
- }
-
-
- static FT_Error
- pcf_get_bdf_property( PCF_Face face,
- const char* prop_name,
- BDF_PropertyRec *aproperty )
- {
- PCF_Property prop;
-
-
- prop = pcf_find_property( face, prop_name );
- if ( prop != NULL )
- {
- if ( prop->isString )
- {
- aproperty->type = BDF_PROPERTY_TYPE_ATOM;
- aproperty->u.atom = prop->value.atom;
- }
- else
- {
- /* Apparently, the PCF driver loads all properties as signed integers!
- * This really doesn't seem to be a problem, because this is
- * sufficient for any meaningful values.
- */
- aproperty->type = BDF_PROPERTY_TYPE_INTEGER;
- aproperty->u.integer = prop->value.integer;
- }
- return 0;
- }
-
- return FT_Err_Invalid_Argument;
- }
-
-
- static FT_Module_Interface
- pcf_driver_requester( FT_Module module,
- const char* name )
- {
- FT_UNUSED( module );
-
- if ( name && ft_strcmp( name, "get_bdf_property" ) == 0 )
- return (FT_Module_Interface) pcf_get_bdf_property;
-
- return NULL;
- }
-
-
- FT_CALLBACK_TABLE_DEF
- const FT_Driver_ClassRec pcf_driver_class =
- {
- {
- ft_module_font_driver,
- sizeof ( FT_DriverRec ),
-
- "pcf",
- 0x10000L,
- 0x20000L,
-
- 0,
-
- (FT_Module_Constructor)0,
- (FT_Module_Destructor) 0,
- (FT_Module_Requester) pcf_driver_requester
- },
-
- sizeof( PCF_FaceRec ),
- sizeof( FT_SizeRec ),
- sizeof( FT_GlyphSlotRec ),
-
- (FT_Face_InitFunc) PCF_Face_Init,
- (FT_Face_DoneFunc) PCF_Face_Done,
- (FT_Size_InitFunc) 0,
- (FT_Size_DoneFunc) 0,
- (FT_Slot_InitFunc) 0,
- (FT_Slot_DoneFunc) 0,
-
- (FT_Size_ResetPointsFunc) PCF_Set_Pixel_Size,
- (FT_Size_ResetPixelsFunc) PCF_Set_Pixel_Size,
-
- (FT_Slot_LoadFunc) PCF_Glyph_Load,
-
- (FT_Face_GetKerningFunc) 0,
- (FT_Face_AttachFunc) 0,
- (FT_Face_GetAdvancesFunc) 0
- };
-
-
-/* END */
--- a/src/pcf/pcfdriver.h
+++ /dev/null
@@ -1,44 +1,0 @@
-/* pcfdriver.h
-
- FreeType font driver for pcf fonts
-
- Copyright 2000-2001, 2002 by
- Francesco Zappa Nardelli
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-*/
-
-
-#ifndef __PCFDRIVER_H__
-#define __PCFDRIVER_H__
-
-#include <ft2build.h>
-#include FT_INTERNAL_DRIVER_H
-
-FT_BEGIN_HEADER
-
- FT_EXPORT_VAR( const FT_Driver_ClassRec ) pcf_driver_class;
-
-FT_END_HEADER
-
-
-#endif /* __PCFDRIVER_H__ */
-
-
-/* END */
--- /dev/null
+++ b/src/pcf/pcfdrivr.c
@@ -1,0 +1,559 @@
+/* pcfdrivr.c
+
+ FreeType font driver for pcf files
+
+ Copyright (C) 2000, 2001, 2002, 2003 by
+ Francesco Zappa Nardelli
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+
+#include <ft2build.h>
+
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_GZIP_H
+#include FT_ERRORS_H
+#include FT_BDF_H
+
+#include "pcf.h"
+#include "pcfdrivr.h"
+#include "pcfutil.h"
+#include "pcfread.h"
+
+#include "pcferror.h"
+
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_pcfread
+
+
+ typedef struct PCF_CMapRec_
+ {
+ FT_CMapRec cmap;
+ FT_UInt num_encodings;
+ PCF_Encoding encodings;
+
+ } PCF_CMapRec, *PCF_CMap;
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ pcf_cmap_init( PCF_CMap cmap )
+ {
+ PCF_Face face = (PCF_Face)FT_CMAP_FACE( cmap );
+
+
+ cmap->num_encodings = (FT_UInt)face->nencodings;
+ cmap->encodings = face->encodings;
+
+ return FT_Err_Ok;
+ }
+
+
+ FT_CALLBACK_DEF( void )
+ pcf_cmap_done( PCF_CMap cmap )
+ {
+ cmap->encodings = NULL;
+ cmap->num_encodings = 0;
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ pcf_cmap_char_index( PCF_CMap cmap,
+ FT_UInt32 charcode )
+ {
+ PCF_Encoding encodings = cmap->encodings;
+ FT_UInt min, max, mid;
+ FT_UInt result = 0;
+
+
+ min = 0;
+ max = cmap->num_encodings;
+
+ while ( min < max )
+ {
+ FT_UInt32 code;
+
+
+ mid = ( min + max ) >> 1;
+ code = encodings[mid].enc;
+
+ if ( charcode == code )
+ {
+ result = encodings[mid].glyph + 1;
+ break;
+ }
+
+ if ( charcode < code )
+ max = mid;
+ else
+ min = mid + 1;
+ }
+
+ return result;
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ pcf_cmap_char_next( PCF_CMap cmap,
+ FT_UInt32 *acharcode )
+ {
+ PCF_Encoding encodings = cmap->encodings;
+ FT_UInt min, max, mid;
+ FT_UInt32 charcode = *acharcode + 1;
+ FT_UInt result = 0;
+
+
+ min = 0;
+ max = cmap->num_encodings;
+
+ while ( min < max )
+ {
+ FT_UInt32 code;
+
+
+ mid = ( min + max ) >> 1;
+ code = encodings[mid].enc;
+
+ if ( charcode == code )
+ {
+ result = encodings[mid].glyph + 1;
+ goto Exit;
+ }
+
+ if ( charcode < code )
+ max = mid;
+ else
+ min = mid + 1;
+ }
+
+ charcode = 0;
+ if ( min < cmap->num_encodings )
+ {
+ charcode = encodings[min].enc;
+ result = encodings[min].glyph + 1;
+ }
+
+ Exit:
+ *acharcode = charcode;
+ return result;
+ }
+
+
+ FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec pcf_cmap_class =
+ {
+ sizeof( PCF_CMapRec ),
+ (FT_CMap_InitFunc) pcf_cmap_init,
+ (FT_CMap_DoneFunc) pcf_cmap_done,
+ (FT_CMap_CharIndexFunc)pcf_cmap_char_index,
+ (FT_CMap_CharNextFunc) pcf_cmap_char_next
+ };
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_pcfdriver
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ PCF_Face_Done( PCF_Face face )
+ {
+ FT_Memory memory = FT_FACE_MEMORY( face );
+
+
+ FT_FREE( face->encodings );
+ FT_FREE( face->metrics );
+
+ /* free properties */
+ {
+ PCF_Property prop = face->properties;
+ FT_Int i;
+
+
+ for ( i = 0; i < face->nprops; i++ )
+ {
+ prop = &face->properties[i];
+
+ FT_FREE( prop->name );
+ if ( prop->isString )
+ FT_FREE( prop->value );
+ }
+
+ FT_FREE( face->properties );
+ }
+
+ FT_FREE( face->toc.tables );
+ FT_FREE( face->root.family_name );
+ FT_FREE( face->root.available_sizes );
+ FT_FREE( face->charset_encoding );
+ FT_FREE( face->charset_registry );
+
+ FT_TRACE4(( "PCF_Face_Done: done face\n" ));
+
+ /* close gzip stream if any */
+ if ( face->root.stream == &face->gzip_stream )
+ {
+ FT_Stream_Close( &face->gzip_stream );
+ face->root.stream = face->gzip_source;
+ }
+
+ return PCF_Err_Ok;
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ PCF_Face_Init( FT_Stream stream,
+ PCF_Face face,
+ FT_Int face_index,
+ FT_Int num_params,
+ FT_Parameter* params )
+ {
+ FT_Error error = PCF_Err_Ok;
+
+ FT_UNUSED( num_params );
+ FT_UNUSED( params );
+ FT_UNUSED( face_index );
+
+
+ error = pcf_load_font( stream, face );
+ if ( error )
+ {
+ FT_Error error2;
+
+
+ /* this didn't work, try gzip support! */
+ error2 = FT_Stream_OpenGzip( &face->gzip_stream, stream );
+ if ( error2 == FT_Err_Unimplemented_Feature )
+ goto Fail;
+
+ error = error2;
+ if ( error )
+ goto Fail;
+
+ face->gzip_source = stream;
+ face->root.stream = &face->gzip_stream;
+
+ stream = face->root.stream;
+
+ error = pcf_load_font( stream, face );
+ if ( error )
+ goto Fail;
+ }
+
+ /* set-up charmap */
+ {
+ FT_String *charset_registry, *charset_encoding;
+ FT_Bool unicode_charmap = 0;
+
+
+ charset_registry = face->charset_registry;
+ charset_encoding = face->charset_encoding;
+
+ if ( ( charset_registry != NULL ) &&
+ ( charset_encoding != NULL ) )
+ {
+ char* s = face->charset_registry;
+
+
+ /* Uh, oh, compare first letters manually to avoid dependency
+ on locales. */
+ if ( ( s[0] == 'i' || s[0] == 'I' ) &&
+ ( s[1] == 's' || s[1] == 'S' ) &&
+ ( s[2] == 'o' || s[2] == 'O' ) )
+ {
+ s += 3;
+ if ( !ft_strcmp( s, "10646" ) ||
+ ( !ft_strcmp( s, "8859" ) &&
+ !ft_strcmp( face->charset_encoding, "1" ) ) )
+ unicode_charmap = 1;
+ }
+ }
+
+ {
+ FT_CharMapRec charmap;
+
+
+ charmap.face = FT_FACE( face );
+ charmap.encoding = FT_ENCODING_NONE;
+ charmap.platform_id = 0;
+ charmap.encoding_id = 0;
+
+ if ( unicode_charmap )
+ {
+ charmap.encoding = FT_ENCODING_UNICODE;
+ charmap.platform_id = 3;
+ charmap.encoding_id = 1;
+ }
+
+ error = FT_CMap_New( &pcf_cmap_class, NULL, &charmap, NULL );
+
+#if 0
+ /* Select default charmap */
+ if (face->root.num_charmaps)
+ face->root.charmap = face->root.charmaps[0];
+#endif
+ }
+ }
+
+ Exit:
+ return error;
+
+ Fail:
+ FT_TRACE2(( "[not a valid PCF file]\n" ));
+ error = PCF_Err_Unknown_File_Format; /* error */
+ goto Exit;
+ }
+
+
+ static FT_Error
+ PCF_Set_Pixel_Size( FT_Size size )
+ {
+ PCF_Face face = (PCF_Face)FT_SIZE_FACE( size );
+
+
+ FT_TRACE4(( "rec %d - pres %d\n", size->metrics.y_ppem,
+ face->root.available_sizes->height ));
+
+ if ( size->metrics.y_ppem == face->root.available_sizes->height )
+ {
+ size->metrics.ascender = face->accel.fontAscent << 6;
+ size->metrics.descender = face->accel.fontDescent * (-64);
+#if 0
+ size->metrics.height = face->accel.maxbounds.ascent << 6;
+#endif
+ size->metrics.height = size->metrics.ascender -
+ size->metrics.descender;
+
+ size->metrics.max_advance = face->accel.maxbounds.characterWidth << 6;
+
+ return PCF_Err_Ok;
+ }
+ else
+ {
+ FT_TRACE4(( "size WRONG\n" ));
+ return PCF_Err_Invalid_Pixel_Size;
+ }
+ }
+
+
+ static FT_Error
+ PCF_Glyph_Load( FT_GlyphSlot slot,
+ FT_Size size,
+ FT_UInt glyph_index,
+ FT_Int32 load_flags )
+ {
+ PCF_Face face = (PCF_Face)FT_SIZE_FACE( size );
+ FT_Stream stream = face->root.stream;
+ FT_Error error = PCF_Err_Ok;
+ FT_Bitmap* bitmap = &slot->bitmap;
+ PCF_Metric metric;
+ int bytes;
+
+ FT_UNUSED( load_flags );
+
+
+ FT_TRACE4(( "load_glyph %d ---", glyph_index ));
+
+ if ( !face )
+ {
+ error = PCF_Err_Invalid_Argument;
+ goto Exit;
+ }
+
+ if ( glyph_index > 0 )
+ glyph_index--;
+
+ metric = face->metrics + glyph_index;
+
+ bitmap->rows = metric->ascent + metric->descent;
+ bitmap->width = metric->rightSideBearing - metric->leftSideBearing;
+ bitmap->num_grays = 1;
+ bitmap->pixel_mode = FT_PIXEL_MODE_MONO;
+
+ FT_TRACE6(( "BIT_ORDER %d ; BYTE_ORDER %d ; GLYPH_PAD %d\n",
+ PCF_BIT_ORDER( face->bitmapsFormat ),
+ PCF_BYTE_ORDER( face->bitmapsFormat ),
+ PCF_GLYPH_PAD( face->bitmapsFormat ) ));
+
+ switch ( PCF_GLYPH_PAD( face->bitmapsFormat ) )
+ {
+ case 1:
+ bitmap->pitch = ( bitmap->width + 7 ) >> 3;
+ break;
+
+ case 2:
+ bitmap->pitch = ( ( bitmap->width + 15 ) >> 4 ) << 1;
+ break;
+
+ case 4:
+ bitmap->pitch = ( ( bitmap->width + 31 ) >> 5 ) << 2;
+ break;
+
+ case 8:
+ bitmap->pitch = ( ( bitmap->width + 63 ) >> 6 ) << 3;
+ break;
+
+ default:
+ return PCF_Err_Invalid_File_Format;
+ }
+
+ /* XXX: to do: are there cases that need repadding the bitmap? */
+ bytes = bitmap->pitch * bitmap->rows;
+
+ error = ft_glyphslot_alloc_bitmap( slot, bytes );
+ if ( error )
+ goto Exit;
+
+ if ( FT_STREAM_SEEK( metric->bits ) ||
+ FT_STREAM_READ( bitmap->buffer, bytes ) )
+ goto Exit;
+
+ if ( PCF_BIT_ORDER( face->bitmapsFormat ) != MSBFirst )
+ BitOrderInvert( bitmap->buffer, bytes );
+
+ if ( ( PCF_BYTE_ORDER( face->bitmapsFormat ) !=
+ PCF_BIT_ORDER( face->bitmapsFormat ) ) )
+ {
+ switch ( PCF_SCAN_UNIT( face->bitmapsFormat ) )
+ {
+ case 1:
+ break;
+
+ case 2:
+ TwoByteSwap( bitmap->buffer, bytes );
+ break;
+
+ case 4:
+ FourByteSwap( bitmap->buffer, bytes );
+ break;
+ }
+ }
+
+ slot->bitmap_left = metric->leftSideBearing;
+ slot->bitmap_top = metric->ascent;
+
+ slot->metrics.horiAdvance = metric->characterWidth << 6 ;
+ slot->metrics.horiBearingX = metric->leftSideBearing << 6 ;
+ slot->metrics.horiBearingY = metric->ascent << 6 ;
+ slot->metrics.width = ( metric->rightSideBearing -
+ metric->leftSideBearing ) << 6;
+ slot->metrics.height = bitmap->rows << 6;
+
+ slot->linearHoriAdvance = (FT_Fixed)bitmap->width << 16;
+ slot->format = FT_GLYPH_FORMAT_BITMAP;
+
+ FT_TRACE4(( " --- ok\n" ));
+
+ Exit:
+ return error;
+ }
+
+
+ static FT_Error
+ pcf_get_bdf_property( PCF_Face face,
+ const char* prop_name,
+ BDF_PropertyRec *aproperty )
+ {
+ PCF_Property prop;
+
+
+ prop = pcf_find_property( face, prop_name );
+ if ( prop != NULL )
+ {
+ if ( prop->isString )
+ {
+ aproperty->type = BDF_PROPERTY_TYPE_ATOM;
+ aproperty->u.atom = prop->value.atom;
+ }
+ else
+ {
+ /* Apparently, the PCF driver loads all properties as signed integers!
+ * This really doesn't seem to be a problem, because this is
+ * sufficient for any meaningful values.
+ */
+ aproperty->type = BDF_PROPERTY_TYPE_INTEGER;
+ aproperty->u.integer = prop->value.integer;
+ }
+ return 0;
+ }
+
+ return FT_Err_Invalid_Argument;
+ }
+
+
+ static FT_Module_Interface
+ pcf_driver_requester( FT_Module module,
+ const char* name )
+ {
+ FT_UNUSED( module );
+
+ if ( name && ft_strcmp( name, "get_bdf_property" ) == 0 )
+ return (FT_Module_Interface) pcf_get_bdf_property;
+
+ return NULL;
+ }
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FT_Driver_ClassRec pcf_driver_class =
+ {
+ {
+ ft_module_font_driver,
+ sizeof ( FT_DriverRec ),
+
+ "pcf",
+ 0x10000L,
+ 0x20000L,
+
+ 0,
+
+ (FT_Module_Constructor)0,
+ (FT_Module_Destructor) 0,
+ (FT_Module_Requester) pcf_driver_requester
+ },
+
+ sizeof( PCF_FaceRec ),
+ sizeof( FT_SizeRec ),
+ sizeof( FT_GlyphSlotRec ),
+
+ (FT_Face_InitFunc) PCF_Face_Init,
+ (FT_Face_DoneFunc) PCF_Face_Done,
+ (FT_Size_InitFunc) 0,
+ (FT_Size_DoneFunc) 0,
+ (FT_Slot_InitFunc) 0,
+ (FT_Slot_DoneFunc) 0,
+
+ (FT_Size_ResetPointsFunc) PCF_Set_Pixel_Size,
+ (FT_Size_ResetPixelsFunc) PCF_Set_Pixel_Size,
+
+ (FT_Slot_LoadFunc) PCF_Glyph_Load,
+
+ (FT_Face_GetKerningFunc) 0,
+ (FT_Face_AttachFunc) 0,
+ (FT_Face_GetAdvancesFunc) 0
+ };
+
+
+/* END */
--- /dev/null
+++ b/src/pcf/pcfdrivr.h
@@ -1,0 +1,44 @@
+/* pcfdrivr.h
+
+ FreeType font driver for pcf fonts
+
+ Copyright 2000-2001, 2002 by
+ Francesco Zappa Nardelli
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+
+#ifndef __PCFDRIVR_H__
+#define __PCFDRIVR_H__
+
+#include <ft2build.h>
+#include FT_INTERNAL_DRIVER_H
+
+FT_BEGIN_HEADER
+
+ FT_EXPORT_VAR( const FT_Driver_ClassRec ) pcf_driver_class;
+
+FT_END_HEADER
+
+
+#endif /* __PCFDRIVR_H__ */
+
+
+/* END */
--- a/src/pcf/pcfread.c
+++ b/src/pcf/pcfread.c
@@ -32,7 +32,7 @@
#include FT_INTERNAL_OBJECTS_H
#include "pcf.h"
-#include "pcfdriver.h"
+#include "pcfdrivr.h"
#include "pcfread.h"
#include "pcferror.h"
--- a/src/pcf/rules.mk
+++ b/src/pcf/rules.mk
@@ -3,7 +3,7 @@
#
-# Copyright (C) 2000, 2001 by
+# Copyright (C) 2000, 2001, 2003 by
# Francesco Zappa Nardelli
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -36,15 +36,15 @@
# pcf driver sources (i.e., C files)
#
-PCF_DRV_SRC := $(PCF_DIR_)pcfread.c \
- $(PCF_DIR_)pcfdriver.c \
+PCF_DRV_SRC := $(PCF_DIR_)pcfread.c \
+ $(PCF_DIR_)pcfdrivr.c \
$(PCF_DIR_)pcfutil.c
# pcf driver headers
#
-PCF_DRV_H := $(PCF_DIR_)pcf.h \
- $(PCF_DIR_)pcfdriver.h \
- $(PCF_DIR_)pcfutil.h \
+PCF_DRV_H := $(PCF_DIR_)pcf.h \
+ $(PCF_DIR_)pcfdrivr.h \
+ $(PCF_DIR_)pcfutil.h \
$(PCF_DIR_)pcferror.h
# pcf driver object(s)