summaryrefslogtreecommitdiffstats
path: root/src/base
diff options
context:
space:
mode:
authorDavid 'Digit' Turner <digit@google.com>2011-08-17 18:21:28 +0200
committerDavid 'Digit' Turner <digit@google.com>2011-08-17 18:25:40 +0200
commitaeb407daf3711a10a27f3bc2223c5eb05158076e (patch)
tree570010914e8c91992ea388f2319611655c7d4b0c /src/base
parent3053d1b9db55099918843889e4809ce97483ca9f (diff)
downloadandroid_external_freetype-aeb407daf3711a10a27f3bc2223c5eb05158076e.tar.gz
android_external_freetype-aeb407daf3711a10a27f3bc2223c5eb05158076e.tar.bz2
android_external_freetype-aeb407daf3711a10a27f3bc2223c5eb05158076e.zip
Update to FreeType 2.4.6+
This patch updates our copy of the FreeType sources to 2.4.6+. More precisely, it contains source code corresponding to the state of the upstream repository at the following hash submitted on August 16 2001: c3fb981e2ac79acad09d5673352646696472f55e This corresponds to 2.4.6 with 7 more patches applied on top of it to fix bugs in the TrueType interpreter and the CFF parser. Change-Id: I9f3ac736d616020c8d10fd1d4e4be466f35fb6e7
Diffstat (limited to 'src/base')
-rw-r--r--src/base/ftbitmap.c2
-rw-r--r--src/base/ftobjs.c41
-rw-r--r--src/base/ftpatent.c2
-rw-r--r--src/base/ftrfork.c8
-rw-r--r--src/base/ftstream.c72
-rw-r--r--src/base/ftstroke.c824
-rw-r--r--src/base/ftsystem.c4
7 files changed, 674 insertions, 279 deletions
diff --git a/src/base/ftbitmap.c b/src/base/ftbitmap.c
index 46fcce6..22ec337 100644
--- a/src/base/ftbitmap.c
+++ b/src/base/ftbitmap.c
@@ -105,7 +105,7 @@
int new_pitch;
FT_UInt bpp;
FT_Int i, width, height;
- unsigned char* buffer;
+ unsigned char* buffer = NULL;
width = bitmap->width;
diff --git a/src/base/ftobjs.c b/src/base/ftobjs.c
index cb44b8c..5069afb 100644
--- a/src/base/ftobjs.c
+++ b/src/base/ftobjs.c
@@ -4,8 +4,7 @@
/* */
/* The FreeType private base classes (body). */
/* */
-/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, */
-/* 2010 by */
+/* Copyright 1996-2011 by */
/* David Turner, Robert Wilhelm, and Werner Lemberg. */
/* */
/* This file is part of the FreeType project, and may only be used, */
@@ -131,7 +130,7 @@
{
FT_Error error;
FT_Memory memory;
- FT_Stream stream;
+ FT_Stream stream = NULL;
*astream = 0;
@@ -156,6 +155,9 @@
(const FT_Byte*)args->memory_base,
args->memory_size );
}
+
+#ifndef FT_CONFIG_OPTION_DISABLE_STREAM_SUPPORT
+
else if ( args->flags & FT_OPEN_PATHNAME )
{
/* create a normal system stream */
@@ -171,6 +173,9 @@
FT_FREE( stream );
stream = args->stream;
}
+
+#endif
+
else
error = FT_Err_Invalid_Argument;
@@ -375,7 +380,7 @@
FT_Driver driver;
FT_Driver_Class clazz;
FT_Memory memory;
- FT_GlyphSlot slot;
+ FT_GlyphSlot slot = NULL;
if ( !face || !face->driver )
@@ -561,6 +566,7 @@
FT_Library library;
FT_Bool autohint = FALSE;
FT_Module hinter;
+ TT_Face ttface = (TT_Face)face;
if ( !face || !face->size || !face->glyph )
@@ -601,7 +607,8 @@
* - Then, auto-hint if FT_LOAD_FORCE_AUTOHINT is set or if we don't
* have a native font hinter.
*
- * - Otherwise, auto-hint for LIGHT hinting mode.
+ * - Otherwise, auto-hint for LIGHT hinting mode or if there isn't
+ * any hinting bytecode in the TrueType/OpenType font.
*
* - Exception: The font is `tricky' and requires the native hinter to
* load properly.
@@ -626,8 +633,13 @@
FT_Render_Mode mode = FT_LOAD_TARGET_MODE( load_flags );
- if ( mode == FT_RENDER_MODE_LIGHT ||
- face->internal->ignore_unpatented_hinter )
+ /* the check for `num_locations' assures that we actually */
+ /* test for instructions in a TTF and not in a CFF-based OTF */
+ if ( mode == FT_RENDER_MODE_LIGHT ||
+ face->internal->ignore_unpatented_hinter ||
+ ( FT_IS_SFNT( face ) &&
+ ttface->num_locations &&
+ ttface->max_profile.maxSizeOfInstructions == 0 ) )
autohint = TRUE;
}
}
@@ -1283,7 +1295,7 @@
{
FT_Error error;
FT_Memory memory;
- FT_Stream stream;
+ FT_Stream stream = NULL;
if ( !library )
@@ -1458,7 +1470,7 @@
FT_ULong offset, length;
FT_Long pos;
FT_Bool is_sfnt_cid;
- FT_Byte* sfnt_ps;
+ FT_Byte* sfnt_ps = NULL;
FT_UNUSED( num_params );
FT_UNUSED( params );
@@ -1525,7 +1537,7 @@
{
FT_Error error = FT_Err_Cannot_Open_Resource;
FT_Memory memory = library->memory;
- FT_Byte* pfb_data;
+ FT_Byte* pfb_data = NULL;
int i, type, flags;
FT_Long len;
FT_Long pfb_len, pfb_pos, pfb_lenpos;
@@ -1667,7 +1679,7 @@
FT_Face *aface )
{
FT_Memory memory = library->memory;
- FT_Byte* sfnt_data;
+ FT_Byte* sfnt_data = NULL;
FT_Error error;
FT_Long flag_offset;
FT_Long rlen;
@@ -1869,7 +1881,7 @@
" is already checked and"
" no font is found\n", i ));
continue;
- }
+ }
if ( errors[i] )
{
@@ -3148,7 +3160,7 @@
FT_Error error = FT_Err_Ok;
FT_Face face;
FT_Memory memory;
- FT_CMap cmap;
+ FT_CMap cmap = NULL;
if ( clazz == NULL || charmap == NULL || charmap->face == NULL )
@@ -3887,6 +3899,7 @@
error = set_mode( renderer, parameters->tag, parameters->data );
if ( error )
break;
+ parameters++;
}
}
@@ -4150,7 +4163,7 @@
FT_Renderer renderer = FT_RENDERER( module );
- if ( renderer->clazz->glyph_format == FT_GLYPH_FORMAT_OUTLINE &&
+ if ( renderer->clazz->glyph_format == FT_GLYPH_FORMAT_OUTLINE &&
renderer->raster )
renderer->clazz->raster_class->raster_done( renderer->raster );
}
diff --git a/src/base/ftpatent.c b/src/base/ftpatent.c
index 501cab5..82b42f0 100644
--- a/src/base/ftpatent.c
+++ b/src/base/ftpatent.c
@@ -269,7 +269,7 @@
#if defined( TT_CONFIG_OPTION_UNPATENTED_HINTING ) && \
- !defined( TT_CONFIG_OPTION_BYTECODE_INTEPRETER )
+ !defined( TT_CONFIG_OPTION_BYTECODE_INTERPRETER )
if ( face && FT_IS_SFNT( face ) )
{
result = !face->internal->ignore_unpatented_hinter;
diff --git a/src/base/ftrfork.c b/src/base/ftrfork.c
index 6df2def..4e7d510 100644
--- a/src/base/ftrfork.c
+++ b/src/base/ftrfork.c
@@ -159,8 +159,8 @@
FT_Long tag_internal, rpos;
FT_Memory memory = library->memory;
FT_Long temp;
- FT_Long *offsets_internal;
- FT_RFork_Ref *ref;
+ FT_Long *offsets_internal = NULL;
+ FT_RFork_Ref *ref = NULL;
error = FT_Stream_Seek( stream, map_offset );
@@ -527,7 +527,7 @@
Only meaningful on systems with hfs+ drivers (or Macs).
*/
FT_Error error;
- char* newpath;
+ char* newpath = NULL;
FT_Memory memory;
FT_Long base_file_len = ft_strlen( base_file_name );
@@ -563,7 +563,7 @@
Only meaningful on systems with Mac OS X (> 10.1).
*/
FT_Error error;
- char* newpath;
+ char* newpath = NULL;
FT_Memory memory;
FT_Long base_file_len = ft_strlen( base_file_name );
diff --git a/src/base/ftstream.c b/src/base/ftstream.c
index 210aaa4..fc2868e 100644
--- a/src/base/ftstream.c
+++ b/src/base/ftstream.c
@@ -4,7 +4,7 @@
/* */
/* I/O stream support (body). */
/* */
-/* Copyright 2000-2001, 2002, 2004, 2005, 2006, 2008, 2009, 2010 by */
+/* Copyright 2000-2002, 2004-2006, 2008-2011 by */
/* David Turner, Robert Wilhelm, and Werner Lemberg. */
/* */
/* This file is part of the FreeType project, and may only be used, */
@@ -354,8 +354,8 @@
}
- FT_BASE_DEF( FT_Short )
- FT_Stream_GetShort( FT_Stream stream )
+ FT_BASE_DEF( FT_UShort )
+ FT_Stream_GetUShort( FT_Stream stream )
{
FT_Byte* p;
FT_Short result;
@@ -366,15 +366,15 @@
result = 0;
p = stream->cursor;
if ( p + 1 < stream->limit )
- result = FT_NEXT_SHORT( p );
+ result = FT_NEXT_USHORT( p );
stream->cursor = p;
return result;
}
- FT_BASE_DEF( FT_Short )
- FT_Stream_GetShortLE( FT_Stream stream )
+ FT_BASE_DEF( FT_UShort )
+ FT_Stream_GetUShortLE( FT_Stream stream )
{
FT_Byte* p;
FT_Short result;
@@ -385,15 +385,15 @@
result = 0;
p = stream->cursor;
if ( p + 1 < stream->limit )
- result = FT_NEXT_SHORT_LE( p );
+ result = FT_NEXT_USHORT_LE( p );
stream->cursor = p;
return result;
}
- FT_BASE_DEF( FT_Long )
- FT_Stream_GetOffset( FT_Stream stream )
+ FT_BASE_DEF( FT_ULong )
+ FT_Stream_GetUOffset( FT_Stream stream )
{
FT_Byte* p;
FT_Long result;
@@ -404,14 +404,14 @@
result = 0;
p = stream->cursor;
if ( p + 2 < stream->limit )
- result = FT_NEXT_OFF3( p );
+ result = FT_NEXT_UOFF3( p );
stream->cursor = p;
return result;
}
- FT_BASE_DEF( FT_Long )
- FT_Stream_GetLong( FT_Stream stream )
+ FT_BASE_DEF( FT_ULong )
+ FT_Stream_GetULong( FT_Stream stream )
{
FT_Byte* p;
FT_Long result;
@@ -422,14 +422,14 @@
result = 0;
p = stream->cursor;
if ( p + 3 < stream->limit )
- result = FT_NEXT_LONG( p );
+ result = FT_NEXT_ULONG( p );
stream->cursor = p;
return result;
}
- FT_BASE_DEF( FT_Long )
- FT_Stream_GetLongLE( FT_Stream stream )
+ FT_BASE_DEF( FT_ULong )
+ FT_Stream_GetULongLE( FT_Stream stream )
{
FT_Byte* p;
FT_Long result;
@@ -440,7 +440,7 @@
result = 0;
p = stream->cursor;
if ( p + 3 < stream->limit )
- result = FT_NEXT_LONG_LE( p );
+ result = FT_NEXT_ULONG_LE( p );
stream->cursor = p;
return result;
}
@@ -483,8 +483,8 @@
}
- FT_BASE_DEF( FT_Short )
- FT_Stream_ReadShort( FT_Stream stream,
+ FT_BASE_DEF( FT_UShort )
+ FT_Stream_ReadUShort( FT_Stream stream,
FT_Error* error )
{
FT_Byte reads[2];
@@ -511,7 +511,7 @@
}
if ( p )
- result = FT_NEXT_SHORT( p );
+ result = FT_NEXT_USHORT( p );
}
else
goto Fail;
@@ -522,7 +522,7 @@
Fail:
*error = FT_Err_Invalid_Stream_Operation;
- FT_ERROR(( "FT_Stream_ReadShort:"
+ FT_ERROR(( "FT_Stream_ReadUShort:"
" invalid i/o; pos = 0x%lx, size = 0x%lx\n",
stream->pos, stream->size ));
@@ -530,8 +530,8 @@
}
- FT_BASE_DEF( FT_Short )
- FT_Stream_ReadShortLE( FT_Stream stream,
+ FT_BASE_DEF( FT_UShort )
+ FT_Stream_ReadUShortLE( FT_Stream stream,
FT_Error* error )
{
FT_Byte reads[2];
@@ -558,7 +558,7 @@
}
if ( p )
- result = FT_NEXT_SHORT_LE( p );
+ result = FT_NEXT_USHORT_LE( p );
}
else
goto Fail;
@@ -569,7 +569,7 @@
Fail:
*error = FT_Err_Invalid_Stream_Operation;
- FT_ERROR(( "FT_Stream_ReadShortLE:"
+ FT_ERROR(( "FT_Stream_ReadUShortLE:"
" invalid i/o; pos = 0x%lx, size = 0x%lx\n",
stream->pos, stream->size ));
@@ -577,8 +577,8 @@
}
- FT_BASE_DEF( FT_Long )
- FT_Stream_ReadOffset( FT_Stream stream,
+ FT_BASE_DEF( FT_ULong )
+ FT_Stream_ReadUOffset( FT_Stream stream,
FT_Error* error )
{
FT_Byte reads[3];
@@ -605,7 +605,7 @@
}
if ( p )
- result = FT_NEXT_OFF3( p );
+ result = FT_NEXT_UOFF3( p );
}
else
goto Fail;
@@ -616,7 +616,7 @@
Fail:
*error = FT_Err_Invalid_Stream_Operation;
- FT_ERROR(( "FT_Stream_ReadOffset:"
+ FT_ERROR(( "FT_Stream_ReadUOffset:"
" invalid i/o; pos = 0x%lx, size = 0x%lx\n",
stream->pos, stream->size ));
@@ -624,8 +624,8 @@
}
- FT_BASE_DEF( FT_Long )
- FT_Stream_ReadLong( FT_Stream stream,
+ FT_BASE_DEF( FT_ULong )
+ FT_Stream_ReadULong( FT_Stream stream,
FT_Error* error )
{
FT_Byte reads[4];
@@ -652,7 +652,7 @@
}
if ( p )
- result = FT_NEXT_LONG( p );
+ result = FT_NEXT_ULONG( p );
}
else
goto Fail;
@@ -663,7 +663,7 @@
Fail:
*error = FT_Err_Invalid_Stream_Operation;
- FT_ERROR(( "FT_Stream_ReadLong:"
+ FT_ERROR(( "FT_Stream_ReadULong:"
" invalid i/o; pos = 0x%lx, size = 0x%lx\n",
stream->pos, stream->size ));
@@ -671,8 +671,8 @@
}
- FT_BASE_DEF( FT_Long )
- FT_Stream_ReadLongLE( FT_Stream stream,
+ FT_BASE_DEF( FT_ULong )
+ FT_Stream_ReadULongLE( FT_Stream stream,
FT_Error* error )
{
FT_Byte reads[4];
@@ -699,7 +699,7 @@
}
if ( p )
- result = FT_NEXT_LONG_LE( p );
+ result = FT_NEXT_ULONG_LE( p );
}
else
goto Fail;
@@ -710,7 +710,7 @@
Fail:
*error = FT_Err_Invalid_Stream_Operation;
- FT_ERROR(( "FT_Stream_ReadLongLE:"
+ FT_ERROR(( "FT_Stream_ReadULongLE:"
" invalid i/o; pos = 0x%lx, size = 0x%lx\n",
stream->pos, stream->size ));
diff --git a/src/base/ftstroke.c b/src/base/ftstroke.c
index 75bcbde..5399efe 100644
--- a/src/base/ftstroke.c
+++ b/src/base/ftstroke.c
@@ -4,7 +4,7 @@
/* */
/* FreeType path stroker (body). */
/* */
-/* Copyright 2002, 2003, 2004, 2005, 2006, 2008, 2009, 2010 by */
+/* Copyright 2002-2006, 2008-2011 by */
/* David Turner, Robert Wilhelm, and Werner Lemberg. */
/* */
/* This file is part of the FreeType project, and may only be used, */
@@ -34,7 +34,7 @@
return o == FT_ORIENTATION_TRUETYPE ? FT_STROKER_BORDER_RIGHT
- : FT_STROKER_BORDER_LEFT ;
+ : FT_STROKER_BORDER_LEFT;
}
@@ -47,20 +47,21 @@
return o == FT_ORIENTATION_TRUETYPE ? FT_STROKER_BORDER_LEFT
- : FT_STROKER_BORDER_RIGHT ;
+ : FT_STROKER_BORDER_RIGHT;
}
- /***************************************************************************/
- /***************************************************************************/
- /***** *****/
- /***** BEZIER COMPUTATIONS *****/
- /***** *****/
- /***************************************************************************/
- /***************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** BEZIER COMPUTATIONS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
#define FT_SMALL_CONIC_THRESHOLD ( FT_ANGLE_PI / 6 )
-#define FT_SMALL_CUBIC_THRESHOLD ( FT_ANGLE_PI / 6 )
+#define FT_SMALL_CUBIC_THRESHOLD ( FT_ANGLE_PI / 8 )
+
#define FT_EPSILON 2
#define FT_IS_SMALL( x ) ( (x) > -FT_EPSILON && (x) < FT_EPSILON )
@@ -69,7 +70,7 @@
static FT_Pos
ft_pos_abs( FT_Pos x )
{
- return x >= 0 ? x : -x ;
+ return x >= 0 ? x : -x;
}
@@ -114,18 +115,28 @@
if ( close1 )
{
if ( close2 )
- *angle_in = *angle_out = 0;
+ {
+ /* basically a point; */
+ /* do nothing to retain original direction */
+ }
else
- *angle_in = *angle_out = FT_Atan2( d2.x, d2.y );
- }
- else if ( close2 )
- {
- *angle_in = *angle_out = FT_Atan2( d1.x, d1.y );
+ {
+ *angle_in =
+ *angle_out = FT_Atan2( d2.x, d2.y );
+ }
}
- else
+ else /* !close1 */
{
- *angle_in = FT_Atan2( d1.x, d1.y );
- *angle_out = FT_Atan2( d2.x, d2.y );
+ 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 ) );
@@ -162,6 +173,17 @@
}
+ /* Return the average of `angle1' and `angle2'. */
+ /* This gives correct result even if `angle1' and `angle2' */
+ /* have opposite signs. */
+ static FT_Angle
+ ft_angle_mean( FT_Angle angle1,
+ FT_Angle angle2 )
+ {
+ return angle1 + FT_Angle_Diff( angle1, angle2 ) / 2;
+ }
+
+
static FT_Bool
ft_cubic_is_small_enough( FT_Vector* base,
FT_Angle *angle_in,
@@ -184,34 +206,70 @@
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 ( close1 )
{
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 );
+ if ( close3 )
+ {
+ /* basically a point; */
+ /* do nothing to retain original direction */
+ }
+ else /* !close3 */
+ {
+ *angle_in =
+ *angle_mid =
+ *angle_out = FT_Atan2( d3.x, d3.y );
+ }
}
- else /* close2 */
+ else /* !close2 */
{
- *angle_in = FT_Atan2( d1.x, d1.y );
- *angle_mid = *angle_out = FT_Atan2( d2.x, d2.y );
+ if ( close3 )
+ {
+ *angle_in =
+ *angle_mid =
+ *angle_out = FT_Atan2( d2.x, d2.y );
+ }
+ else /* !close3 */
+ {
+ *angle_in =
+ *angle_mid = FT_Atan2( d2.x, d2.y );
+ *angle_out = FT_Atan2( d3.x, d3.y );
+ }
}
}
- else if ( close2 )
+ else /* !close1 */
{
- *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 );
+ if ( close2 )
+ {
+ if ( close3 )
+ {
+ *angle_in =
+ *angle_mid =
+ *angle_out = FT_Atan2( d1.x, d1.y );
+ }
+ else /* !close3 */
+ {
+ *angle_in = FT_Atan2( d1.x, d1.y );
+ *angle_out = FT_Atan2( d3.x, d3.y );
+ *angle_mid = ft_angle_mean( *angle_in, *angle_out );
+ }
+ }
+ else /* !close2 */
+ {
+ if ( close3 )
+ {
+ *angle_in = FT_Atan2( d1.x, d1.y );
+ *angle_mid =
+ *angle_out = FT_Atan2( d2.x, d2.y );
+ }
+ else /* !close3 */
+ {
+ *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 ) );
@@ -222,13 +280,13 @@
}
- /***************************************************************************/
- /***************************************************************************/
- /***** *****/
- /***** STROKE BORDERS *****/
- /***** *****/
- /***************************************************************************/
- /***************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** STROKE BORDERS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
typedef enum FT_StrokeTags_
{
@@ -239,7 +297,7 @@
} FT_StrokeTags;
-#define FT_STROKE_TAG_BEGIN_END (FT_STROKE_TAG_BEGIN|FT_STROKE_TAG_END)
+#define FT_STROKE_TAG_BEGIN_END ( FT_STROKE_TAG_BEGIN | FT_STROKE_TAG_END )
typedef struct FT_StrokeBorderRec_
{
@@ -247,7 +305,7 @@
FT_UInt max_points;
FT_Vector* points;
FT_Byte* tags;
- FT_Bool movable;
+ FT_Bool movable; /* TRUE for ends of lineto borders */
FT_Int start; /* index of current sub-path start point */
FT_Memory memory;
FT_Bool valid;
@@ -368,6 +426,12 @@
}
else
{
+ /* don't add zero-length lineto */
+ if ( border->num_points > 0 &&
+ FT_IS_SMALL( border->points[border->num_points - 1].x - to->x ) &&
+ FT_IS_SMALL( border->points[border->num_points - 1].y - to->y ) )
+ return error;
+
/* add one point */
error = ft_stroke_border_grow( border, 1 );
if ( !error )
@@ -403,6 +467,7 @@
FT_Vector* vec = border->points + border->num_points;
FT_Byte* tag = border->tags + border->num_points;
+
vec[0] = *control;
vec[1] = *to;
@@ -411,7 +476,9 @@
border->num_points += 2;
}
+
border->movable = FALSE;
+
return error;
}
@@ -444,7 +511,9 @@
border->num_points += 3;
}
+
border->movable = FALSE;
+
return error;
}
@@ -530,7 +599,7 @@
if ( border->start >= 0 )
ft_stroke_border_close( border, FALSE );
- border->start = border->num_points;
+ border->start = border->num_points;
border->movable = FALSE;
return ft_stroke_border_lineto( border, to, FALSE );
@@ -673,38 +742,41 @@
}
}
- outline->n_points = (short)( outline->n_points + border->num_points );
+ outline->n_points = (short)( outline->n_points + border->num_points );
FT_ASSERT( FT_Outline_Check( outline ) == 0 );
}
- /***************************************************************************/
- /***************************************************************************/
- /***** *****/
- /***** STROKER *****/
- /***** *****/
- /***************************************************************************/
- /***************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** 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_Angle angle_in; /* direction into curr join */
+ FT_Angle angle_out; /* direction out of join */
+ FT_Vector center; /* current position */
+ FT_Fixed line_length; /* length of last lineto */
+ FT_Bool first_point; /* is this the start? */
+ FT_Bool subpath_open; /* is the subpath open? */
+ FT_Angle subpath_angle; /* subpath start direction */
+ FT_Vector subpath_start; /* subpath start position */
+ FT_Fixed subpath_line_length; /* subpath start lineto len */
+ FT_Bool handle_wide_strokes; /* use wide strokes logic? */
FT_Stroker_LineCap line_cap;
FT_Stroker_LineJoin line_join;
+ FT_Stroker_LineJoin line_join_saved;
FT_Fixed miter_limit;
FT_Fixed radius;
- FT_Bool valid;
FT_StrokeBorderRec borders[2];
FT_Library library;
@@ -719,7 +791,7 @@
{
FT_Error error;
FT_Memory memory;
- FT_Stroker stroker;
+ FT_Stroker stroker = NULL;
if ( !library )
@@ -734,7 +806,9 @@
ft_stroke_border_init( &stroker->borders[0], memory );
ft_stroke_border_init( &stroker->borders[1], memory );
}
+
*astroker = stroker;
+
return error;
}
@@ -753,6 +827,14 @@
stroker->line_join = line_join;
stroker->miter_limit = miter_limit;
+ /* ensure miter limit has sensible value */
+ if ( stroker->miter_limit < 0x10000 )
+ stroker->miter_limit = 0x10000;
+
+ /* save line join style: */
+ /* line join style can be temporarily changed when stroking curves */
+ stroker->line_join_saved = line_join;
+
FT_Stroker_Rewind( stroker );
}
@@ -789,7 +871,7 @@
}
- /* creates a circular arc at a corner or cap */
+ /* create a circular arc at a corner or cap */
static FT_Error
ft_stroker_arcto( FT_Stroker stroker,
FT_Int side )
@@ -816,7 +898,7 @@
}
- /* adds a cap at the end of an opened path */
+ /* add a cap at the end of an opened path */
static FT_Error
ft_stroker_cap( FT_Stroker stroker,
FT_Angle angle,
@@ -830,6 +912,7 @@
/* 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 )
@@ -882,7 +965,7 @@
delta.x += stroker->center.x;
delta.y += stroker->center.y;
- error = ft_stroke_border_lineto( border, &delta, FALSE );
+ error = ft_stroke_border_lineto( border, &delta, FALSE );
}
Exit:
@@ -893,40 +976,52 @@
/* process an inside corner, i.e. compute intersection */
static FT_Error
ft_stroker_inside( FT_Stroker stroker,
- FT_Int side)
+ FT_Int side,
+ FT_Fixed line_length )
{
FT_StrokeBorder border = stroker->borders + side;
FT_Angle phi, theta, rotate;
- FT_Fixed length, thcos, sigma;
+ FT_Fixed length, thcos;
FT_Vector delta;
FT_Error error = FT_Err_Ok;
+ FT_Bool intersect; /* use intersection of lines? */
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;
+ theta = FT_Angle_Diff( stroker->angle_in, stroker->angle_out ) / 2;
+
+ /* Only intersect borders if between two lineto's and both */
+ /* lines are long enough (line_length is zero for curves). */
+ if ( !border->movable || line_length == 0 )
+ intersect = FALSE;
else
- theta = theta / 2;
+ {
+ /* compute minimum required length of lines */
+ FT_Fixed min_length = ft_pos_abs( FT_MulFix( stroker->radius,
+ FT_Tan( theta ) ) );
- phi = stroker->angle_in + theta;
- thcos = FT_Cos( theta );
- sigma = FT_MulFix( stroker->miter_limit, thcos );
+ intersect = FT_BOOL( stroker->line_length >= min_length &&
+ line_length >= min_length );
+ }
- /* TODO: find better criterion to switch off the optimization */
- if ( sigma < 0x10000L )
+ if ( !intersect )
{
FT_Vector_From_Polar( &delta, stroker->radius,
stroker->angle_out + rotate );
delta.x += stroker->center.x;
delta.y += stroker->center.y;
+
border->movable = FALSE;
}
else
{
+ /* compute median angle */
+ phi = stroker->angle_in + theta;
+
+ thcos = FT_Cos( theta );
+
length = FT_DivFix( stroker->radius, thcos );
FT_Vector_From_Polar( &delta, length, phi + rotate );
@@ -943,7 +1038,8 @@
/* process an outside corner, i.e. compute bevel/miter/round */
static FT_Error
ft_stroker_outside( FT_Stroker stroker,
- FT_Int side )
+ FT_Int side,
+ FT_Fixed line_length )
{
FT_StrokeBorder border = stroker->borders + side;
FT_Error error;
@@ -954,79 +1050,119 @@
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;
+ /* this is a mitered (pointed) or beveled (truncated) corner */
+ FT_Fixed sigma = 0, radius = stroker->radius;
+ FT_Angle theta = 0, phi = 0;
+ FT_Fixed thcos = 0;
+ FT_Bool bevel, fixed_bevel;
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 )
+ bevel =
+ FT_BOOL( stroker->line_join == FT_STROKER_LINEJOIN_BEVEL );
+
+ fixed_bevel =
+ FT_BOOL( stroker->line_join != FT_STROKER_LINEJOIN_MITER_VARIABLE );
+
+ if ( !bevel )
{
- theta = rotate;
- phi = stroker->angle_in;
+ theta = FT_Angle_Diff( stroker->angle_in, stroker->angle_out );
+
+ if ( theta == FT_ANGLE_PI )
+ {
+ theta = rotate;
+ phi = stroker->angle_in;
+ }
+ else
+ {
+ theta /= 2;
+ phi = stroker->angle_in + theta + rotate;
+ }
+
+ thcos = FT_Cos( theta );
+ sigma = FT_MulFix( stroker->miter_limit, thcos );
+
+ /* is miter limit exceeded? */
+ if ( sigma < 0x10000L )
+ {
+ /* don't create variable bevels for very small deviations; */
+ /* FT_Sin(x) = 0 for x <= 57 */
+ if ( fixed_bevel || ft_pos_abs( theta ) > 57 )
+ bevel = TRUE;
+ }
}
- else
+
+ if ( bevel ) /* this is a bevel (broken angle) */
{
- theta = theta / 2;
- phi = stroker->angle_in + theta + rotate;
- }
+ if ( fixed_bevel )
+ {
+ /* the outer corners are simply joined together */
+ FT_Vector delta;
- thcos = FT_Cos( theta );
- sigma = FT_MulFix( stroker->miter_limit, thcos );
- /* FT_Sin(x) = 0 for x <= 57 */
- if ( sigma >= 0x10000L || ft_pos_abs( theta ) <= 57 )
- miter = FALSE;
+ /* add bevel */
+ FT_Vector_From_Polar( &delta,
+ radius,
+ stroker->angle_out + rotate );
+ delta.x += stroker->center.x;
+ delta.y += stroker->center.y;
- if ( miter ) /* this is a miter (broken angle) */
- {
- FT_Vector middle, delta;
- FT_Fixed length;
+ border->movable = FALSE;
+ error = ft_stroke_border_lineto( border, &delta, FALSE );
+ }
+ else /* variable bevel */
+ {
+ /* the miter is truncated */
+ 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 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 ) ) ) );
+ /* 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;
+ FT_Vector_From_Polar( &delta, length, phi + rotate );
+ delta.x += middle.x;
+ delta.y += middle.y;
- error = ft_stroke_border_lineto( border, &delta, FALSE );
- if ( error )
- goto Exit;
+ error = ft_stroke_border_lineto( border, &delta, FALSE );
+ if ( error )
+ goto Exit;
- /* compute second angle point */
- FT_Vector_From_Polar( &delta, length, phi - rotate );
- delta.x += middle.x;
- delta.y += middle.y;
+ /* 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, FALSE );
- if ( error )
- goto Exit;
+ error = ft_stroke_border_lineto( border, &delta, FALSE );
+ 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;
+ /* finally, add an end point; only needed if not lineto */
+ /* (line_length is zero for curves) */
+ if ( line_length == 0 )
+ {
+ FT_Vector_From_Polar( &delta,
+ radius,
+ stroker->angle_out + rotate );
- error = ft_stroke_border_lineto( border, &delta, TRUE );
- }
+ delta.x += stroker->center.x;
+ delta.y += stroker->center.y;
- else /* this is a bevel (intersection) */
+ error = ft_stroke_border_lineto( border, &delta, FALSE );
+ }
+ }
+ }
+ else /* this is a miter (intersection) */
{
FT_Fixed length;
FT_Vector delta;
@@ -1042,13 +1178,18 @@
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;
+ /* now add an end point; only needed if not lineto */
+ /* (line_length is zero for curves) */
+ if ( line_length == 0 )
+ {
+ 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, TRUE );
+ error = ft_stroke_border_lineto( border, &delta, FALSE );
+ }
}
}
@@ -1058,7 +1199,8 @@
static FT_Error
- ft_stroker_process_corner( FT_Stroker stroker )
+ ft_stroker_process_corner( FT_Stroker stroker,
+ FT_Fixed line_length )
{
FT_Error error = FT_Err_Ok;
FT_Angle turn;
@@ -1079,12 +1221,12 @@
inside_side = 1;
/* process the inside side */
- error = ft_stroker_inside( stroker, inside_side );
+ error = ft_stroker_inside( stroker, inside_side, line_length );
if ( error )
goto Exit;
/* process the outside side */
- error = ft_stroker_outside( stroker, 1 - inside_side );
+ error = ft_stroker_outside( stroker, 1 - inside_side, line_length );
Exit:
return error;
@@ -1095,7 +1237,8 @@
/* start of the subpath */
static FT_Error
ft_stroker_subpath_start( FT_Stroker stroker,
- FT_Angle start_angle )
+ FT_Angle start_angle,
+ FT_Fixed line_length )
{
FT_Vector delta;
FT_Vector point;
@@ -1120,9 +1263,11 @@
border++;
error = ft_stroke_border_moveto( border, &point );
- /* save angle for last cap */
- stroker->subpath_angle = start_angle;
- stroker->first_point = FALSE;
+ /* save angle, position, and line length for last join */
+ /* (line_length is zero for curves) */
+ stroker->subpath_angle = start_angle;
+ stroker->first_point = FALSE;
+ stroker->subpath_line_length = line_length;
Exit:
return error;
@@ -1140,10 +1285,19 @@
FT_Vector delta;
FT_Angle angle;
FT_Int side;
+ FT_Fixed line_length;
+
delta.x = to->x - stroker->center.x;
delta.y = to->y - stroker->center.y;
+ /* a zero-length lineto is a no-op; avoid creating a spurious corner */
+ if ( delta.x == 0 && delta.y == 0 )
+ goto Exit;
+
+ /* compute length of line */
+ line_length = FT_Vector_Length( &delta );
+
angle = FT_Atan2( delta.x, delta.y );
FT_Vector_From_Polar( &delta, stroker->radius, angle + FT_ANGLE_PI2 );
@@ -1153,7 +1307,7 @@
/* 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 );
+ error = ft_stroker_subpath_start( stroker, angle, line_length );
if ( error )
goto Exit;
}
@@ -1161,13 +1315,12 @@
{
/* process the current corner */
stroker->angle_out = angle;
- error = ft_stroker_process_corner( stroker );
+ error = ft_stroker_process_corner( stroker, line_length );
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;
@@ -1176,6 +1329,7 @@
point.x = to->x + delta.x;
point.y = to->y + delta.y;
+ /* the ends of lineto borders are movable */
error = ft_stroke_border_lineto( border, &point, TRUE );
if ( error )
goto Exit;
@@ -1184,8 +1338,9 @@
delta.y = -delta.y;
}
- stroker->angle_in = angle;
- stroker->center = *to;
+ stroker->angle_in = angle;
+ stroker->center = *to;
+ stroker->line_length = line_length;
Exit:
return error;
@@ -1203,10 +1358,20 @@
FT_Vector bez_stack[34];
FT_Vector* arc;
FT_Vector* limit = bez_stack + 30;
- FT_Angle start_angle;
FT_Bool first_arc = TRUE;
+ /* if all control points are coincident, this is a no-op; */
+ /* avoid creating a spurious corner */
+ if ( FT_IS_SMALL( stroker->center.x - control->x ) &&
+ FT_IS_SMALL( stroker->center.y - control->y ) &&
+ FT_IS_SMALL( control->x - to->x ) &&
+ FT_IS_SMALL( control->y - to->y ) )
+ {
+ stroker->center = *to;
+ goto Exit;
+ }
+
arc = bez_stack;
arc[0] = *to;
arc[1] = *control;
@@ -1217,11 +1382,15 @@
FT_Angle angle_in, angle_out;
- angle_in = angle_out = 0; /* remove compiler warnings */
+ /* initialize with current direction */
+ angle_in = angle_out = stroker->angle_in;
if ( arc < limit &&
!ft_conic_is_small_enough( arc, &angle_in, &angle_out ) )
{
+ if ( stroker->first_point )
+ stroker->angle_in = angle_in;
+
ft_conic_split( arc );
arc += 2;
continue;
@@ -1231,32 +1400,54 @@
{
first_arc = FALSE;
- start_angle = angle_in;
-
/* process corner if necessary */
if ( stroker->first_point )
- error = ft_stroker_subpath_start( stroker, start_angle );
+ error = ft_stroker_subpath_start( stroker, angle_in, 0 );
else
{
- stroker->angle_out = start_angle;
- error = ft_stroker_process_corner( stroker );
+ stroker->angle_out = angle_in;
+ error = ft_stroker_process_corner( stroker, 0 );
}
}
+ else if ( ft_pos_abs( FT_Angle_Diff( stroker->angle_in, angle_in ) ) >
+ FT_SMALL_CONIC_THRESHOLD / 4 )
+ {
+ /* if the deviation from one arc to the next is too great, */
+ /* add a round corner */
+ stroker->center = arc[2];
+ stroker->angle_out = angle_in;
+ stroker->line_join = FT_STROKER_LINEJOIN_ROUND;
+
+ error = ft_stroker_process_corner( stroker, 0 );
+
+ /* reinstate line join style */
+ stroker->line_join = stroker->line_join_saved;
+ }
+
+ if ( error )
+ goto Exit;
/* 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;
+ FT_Vector ctrl, end;
+ FT_Angle theta, phi, rotate, alpha0 = 0;
+ FT_Fixed length;
+ FT_StrokeBorder border;
+ 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++ )
+ /* compute direction of original arc */
+ if ( stroker->handle_wide_strokes )
+ alpha0 = FT_Atan2( arc[0].x - arc[2].x, arc[0].y - arc[2].y );
+
+ for ( border = stroker->borders, side = 0;
+ side <= 1;
+ side++, border++ )
{
rotate = FT_SIDE_TO_ROTATE( side );
@@ -1270,8 +1461,70 @@
end.x += arc[0].x;
end.y += arc[0].y;
- error = ft_stroke_border_conicto( stroker->borders + side,
- &ctrl, &end );
+ if ( stroker->handle_wide_strokes )
+ {
+ FT_Vector start;
+ FT_Angle alpha1;
+
+
+ /* determine whether the border radius is greater than the */
+ /* radius of curvature of the original arc */
+ start = border->points[border->num_points - 1];
+
+ alpha1 = FT_Atan2( end.x - start.x, end.y - start.y );
+
+ /* is the direction of the border arc opposite to */
+ /* that of the original arc? */
+ if ( ft_pos_abs( FT_Angle_Diff( alpha0, alpha1 ) ) >
+ FT_ANGLE_PI / 2 )
+ {
+ FT_Angle beta, gamma;
+ FT_Vector bvec, delta;
+ FT_Fixed blen, sinA, sinB, alen;
+
+
+ /* use the sine rule to find the intersection point */
+ beta = FT_Atan2( arc[2].x - start.x, arc[2].y - start.y );
+ gamma = FT_Atan2( arc[0].x - end.x, arc[0].y - end.y );
+
+ bvec.x = end.x - start.x;
+ bvec.y = end.y - start.y;
+
+ blen = FT_Vector_Length( &bvec );
+
+ sinA = ft_pos_abs( FT_Sin( alpha1 - gamma ) );
+ sinB = ft_pos_abs( FT_Sin( beta - gamma ) );
+
+ alen = FT_DivFix( FT_MulFix( blen, sinA ), sinB );
+
+ FT_Vector_From_Polar( &delta, alen, beta );
+ delta.x += start.x;
+ delta.y += start.y;
+
+ /* circumnavigate the negative sector backwards */
+ border->movable = FALSE;
+ error = ft_stroke_border_lineto( border, &delta, FALSE );
+ if ( error )
+ goto Exit;
+ error = ft_stroke_border_lineto( border, &end, FALSE );
+ if ( error )
+ goto Exit;
+ error = ft_stroke_border_conicto( border, &ctrl, &start );
+ if ( error )
+ goto Exit;
+ /* and then move to the endpoint */
+ error = ft_stroke_border_lineto( border, &end, FALSE );
+ if ( error )
+ goto Exit;
+
+ continue;
+ }
+
+ /* else fall through */
+ }
+
+ /* simply add an arc */
+ error = ft_stroke_border_conicto( border, &ctrl, &end );
if ( error )
goto Exit;
}
@@ -1279,8 +1532,7 @@
arc -= 2;
- if ( arc < bez_stack )
- stroker->angle_in = angle_out;
+ stroker->angle_in = angle_out;
}
stroker->center = *to;
@@ -1302,10 +1554,22 @@
FT_Vector bez_stack[37];
FT_Vector* arc;
FT_Vector* limit = bez_stack + 32;
- FT_Angle start_angle;
FT_Bool first_arc = TRUE;
+ /* if all control points are coincident, this is a no-op; */
+ /* avoid creating a spurious corner */
+ if ( FT_IS_SMALL( stroker->center.x - control1->x ) &&
+ FT_IS_SMALL( stroker->center.y - control1->y ) &&
+ FT_IS_SMALL( control1->x - control2->x ) &&
+ FT_IS_SMALL( control1->y - control2->y ) &&
+ FT_IS_SMALL( control2->x - to->x ) &&
+ FT_IS_SMALL( control2->y - to->y ) )
+ {
+ stroker->center = *to;
+ goto Exit;
+ }
+
arc = bez_stack;
arc[0] = *to;
arc[1] = *control2;
@@ -1317,13 +1581,16 @@
FT_Angle angle_in, angle_mid, angle_out;
- /* remove compiler warnings */
- angle_in = angle_out = angle_mid = 0;
+ /* initialize with current direction */
+ angle_in = angle_out = angle_mid = stroker->angle_in;
if ( arc < limit &&
!ft_cubic_is_small_enough( arc, &angle_in,
&angle_mid, &angle_out ) )
{
+ if ( stroker->first_point )
+ stroker->angle_in = angle_in;
+
ft_cubic_split( arc );
arc += 3;
continue;
@@ -1334,36 +1601,56 @@
first_arc = FALSE;
/* process corner if necessary */
- start_angle = angle_in;
-
if ( stroker->first_point )
- error = ft_stroker_subpath_start( stroker, start_angle );
+ error = ft_stroker_subpath_start( stroker, angle_in, 0 );
else
{
- stroker->angle_out = start_angle;
- error = ft_stroker_process_corner( stroker );
+ stroker->angle_out = angle_in;
+ error = ft_stroker_process_corner( stroker, 0 );
}
- if ( error )
- goto Exit;
}
+ else if ( ft_pos_abs( FT_Angle_Diff( stroker->angle_in, angle_in ) ) >
+ FT_SMALL_CUBIC_THRESHOLD / 4 )
+ {
+ /* if the deviation from one arc to the next is too great, */
+ /* add a round corner */
+ stroker->center = arc[3];
+ stroker->angle_out = angle_in;
+ stroker->line_join = FT_STROKER_LINEJOIN_ROUND;
+
+ error = ft_stroker_process_corner( stroker, 0 );
+
+ /* reinstate line join style */
+ stroker->line_join = stroker->line_join_saved;
+ }
+
+ 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;
+ FT_Vector ctrl1, ctrl2, end;
+ FT_Angle theta1, phi1, theta2, phi2, rotate, alpha0 = 0;
+ FT_Fixed length1, length2;
+ FT_StrokeBorder border;
+ 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;
+ theta1 = FT_Angle_Diff( angle_in, angle_mid ) / 2;
+ theta2 = FT_Angle_Diff( angle_mid, angle_out ) / 2;
+ phi1 = ft_angle_mean( angle_in, angle_mid );
+ phi2 = ft_angle_mean( angle_mid, angle_out );
length1 = FT_DivFix( stroker->radius, FT_Cos( theta1 ) );
length2 = FT_DivFix( stroker->radius, FT_Cos( theta2 ) );
- for ( side = 0; side <= 1; side++ )
+ /* compute direction of original arc */
+ if ( stroker->handle_wide_strokes )
+ alpha0 = FT_Atan2( arc[0].x - arc[3].x, arc[0].y - arc[3].y );
+
+ for ( border = stroker->borders, side = 0;
+ side <= 1;
+ side++, border++ )
{
rotate = FT_SIDE_TO_ROTATE( side );
@@ -1381,16 +1668,81 @@
end.x += arc[0].x;
end.y += arc[0].y;
- error = ft_stroke_border_cubicto( stroker->borders + side,
- &ctrl1, &ctrl2, &end );
+ if ( stroker->handle_wide_strokes )
+ {
+ FT_Vector start;
+ FT_Angle alpha1;
+
+
+ /* determine whether the border radius is greater than the */
+ /* radius of curvature of the original arc */
+ start = border->points[border->num_points - 1];
+
+ alpha1 = FT_Atan2( end.x - start.x, end.y - start.y );
+
+ /* is the direction of the border arc opposite to */
+ /* that of the original arc? */
+ if ( ft_pos_abs( FT_Angle_Diff( alpha0, alpha1 ) ) >
+ FT_ANGLE_PI / 2 )
+ {
+ FT_Angle beta, gamma;
+ FT_Vector bvec, delta;
+ FT_Fixed blen, sinA, sinB, alen;
+
+
+ /* use the sine rule to find the intersection point */
+ beta = FT_Atan2( arc[3].x - start.x, arc[3].y - start.y );
+ gamma = FT_Atan2( arc[0].x - end.x, arc[0].y - end.y );
+
+ bvec.x = end.x - start.x;
+ bvec.y = end.y - start.y;
+
+ blen = FT_Vector_Length( &bvec );
+
+ sinA = ft_pos_abs( FT_Sin( alpha1 - gamma ) );
+ sinB = ft_pos_abs( FT_Sin( beta - gamma ) );
+
+ alen = FT_DivFix( FT_MulFix( blen, sinA ), sinB );
+
+ FT_Vector_From_Polar( &delta, alen, beta );
+ delta.x += start.x;
+ delta.y += start.y;
+
+ /* circumnavigate the negative sector backwards */
+ border->movable = FALSE;
+ error = ft_stroke_border_lineto( border, &delta, FALSE );
+ if ( error )
+ goto Exit;
+ error = ft_stroke_border_lineto( border, &end, FALSE );
+ if ( error )
+ goto Exit;
+ error = ft_stroke_border_cubicto( border,
+ &ctrl2,
+ &ctrl1,
+ &start );
+ if ( error )
+ goto Exit;
+ /* and then move to the endpoint */
+ error = ft_stroke_border_lineto( border, &end, FALSE );
+ if ( error )
+ goto Exit;
+
+ continue;
+ }
+
+ /* else fall through */
+ }
+
+ /* simply add an arc */
+ error = ft_stroke_border_cubicto( border, &ctrl1, &ctrl2, &end );
if ( error )
goto Exit;
}
}
arc -= 3;
- if ( arc < bez_stack )
- stroker->angle_in = angle_out;
+
+ stroker->angle_in = angle_out;
}
stroker->center = *to;
@@ -1415,9 +1767,21 @@
stroker->center = *to;
stroker->subpath_open = open;
+ /* Determine if we need to check whether the border radius is greater */
+ /* than the radius of curvature of a curve, to handle this case */
+ /* specially. This is only required if bevel joins or butt caps may */
+ /* be created, because round & miter joins and round & square caps */
+ /* cover the negative sector created with wide strokes. */
+ stroker->handle_wide_strokes =
+ FT_BOOL( stroker->line_join != FT_STROKER_LINEJOIN_ROUND ||
+ ( stroker->subpath_open &&
+ stroker->line_cap == FT_STROKER_LINECAP_BUTT ) );
+
/* record the subpath start point for each border */
stroker->subpath_start = *to;
+ stroker->angle_in = 0;
+
return FT_Err_Ok;
}
@@ -1447,6 +1811,7 @@
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;
@@ -1456,14 +1821,14 @@
dst_tag[0] &= ~FT_STROKE_TAG_BEGIN_END;
else
{
- FT_Byte ttag = (FT_Byte)( dst_tag[0] & FT_STROKE_TAG_BEGIN_END );
+ FT_Byte ttag =
+ (FT_Byte)( dst_tag[0] & FT_STROKE_TAG_BEGIN_END );
/* switch begin/end tags if necessary */
if ( ttag == FT_STROKE_TAG_BEGIN ||
ttag == FT_STROKE_TAG_END )
dst_tag[0] ^= FT_STROKE_TAG_BEGIN_END;
-
}
src_point--;
@@ -1498,6 +1863,7 @@
{
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. */
@@ -1526,13 +1892,14 @@
FT_Angle turn;
FT_Int inside_side;
+
/* close the path if needed */
if ( stroker->center.x != stroker->subpath_start.x ||
stroker->center.y != stroker->subpath_start.y )
{
- error = FT_Stroker_LineTo( stroker, &stroker->subpath_start );
- if ( error )
- goto Exit;
+ error = FT_Stroker_LineTo( stroker, &stroker->subpath_start );
+ if ( error )
+ goto Exit;
}
/* process the corner */
@@ -1550,19 +1917,23 @@
if ( turn < 0 )
inside_side = 1;
- error = ft_stroker_inside( stroker, inside_side );
+ error = ft_stroker_inside( stroker,
+ inside_side,
+ stroker->subpath_line_length );
if ( error )
goto Exit;
/* process the outside side */
- error = ft_stroker_outside( stroker, 1 - inside_side );
+ error = ft_stroker_outside( stroker,
+ 1 - inside_side,
+ stroker->subpath_line_length );
if ( error )
goto Exit;
}
/* then end our two subpaths */
- ft_stroke_border_close( stroker->borders + 0, TRUE );
- ft_stroke_border_close( stroker->borders + 1, FALSE );
+ ft_stroke_border_close( stroker->borders + 0, FALSE );
+ ft_stroke_border_close( stroker->borders + 1, TRUE );
}
Exit:
@@ -1684,9 +2055,9 @@
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 */
+ 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 )
@@ -1851,9 +2222,13 @@
if ( error )
goto Exit;
- error = FT_Stroker_EndSubPath( stroker );
- if ( error )
- goto Exit;
+ /* don't try to end the path if no segments have been generated */
+ if ( !stroker->first_point )
+ {
+ error = FT_Stroker_EndSubPath( stroker );
+ if ( error )
+ goto Exit;
+ }
first = last + 1;
}
@@ -1867,9 +2242,10 @@
return FT_Err_Invalid_Outline;
}
-/* declare an extern to access ft_outline_glyph_class global allocated
- in ftglyph.c, and use the FT_OUTLINE_GLYPH_CLASS_GET macro to access
- it when FT_CONFIG_OPTION_PIC is defined */
+
+ /* declare an extern to access `ft_outline_glyph_class' globally */
+ /* allocated in `ftglyph.c', and use the FT_OUTLINE_GLYPH_CLASS_GET */
+ /* macro to access it when FT_CONFIG_OPTION_PIC is defined */
#ifndef FT_CONFIG_OPTION_PIC
extern const FT_Glyph_Class ft_outline_glyph_class;
#endif
@@ -1883,10 +2259,12 @@
FT_Stroker stroker,
FT_Bool destroy )
{
- FT_Error error = FT_Err_Invalid_Argument;
- FT_Glyph glyph = NULL;
- FT_Library library = stroker->library;
- FT_UNUSED(library);
+ FT_Error error = FT_Err_Invalid_Argument;
+ FT_Glyph glyph = NULL;
+ FT_Library library = stroker->library;
+
+ FT_UNUSED( library );
+
if ( pglyph == NULL )
goto Exit;
@@ -1907,7 +2285,7 @@
}
{
- FT_OutlineGlyph oglyph = (FT_OutlineGlyph) glyph;
+ FT_OutlineGlyph oglyph = (FT_OutlineGlyph)glyph;
FT_Outline* outline = &oglyph->outline;
FT_UInt num_points, num_contours;
@@ -1957,10 +2335,12 @@
FT_Bool inside,
FT_Bool destroy )
{
- FT_Error error = FT_Err_Invalid_Argument;
- FT_Glyph glyph = NULL;
- FT_Library library = stroker->library;
- FT_UNUSED(library);
+ FT_Error error = FT_Err_Invalid_Argument;
+ FT_Glyph glyph = NULL;
+ FT_Library library = stroker->library;
+
+ FT_UNUSED( library );
+
if ( pglyph == NULL )
goto Exit;
@@ -1981,7 +2361,7 @@
}
{
- FT_OutlineGlyph oglyph = (FT_OutlineGlyph) glyph;
+ FT_OutlineGlyph oglyph = (FT_OutlineGlyph)glyph;
FT_StrokerBorder border;
FT_Outline* outline = &oglyph->outline;
FT_UInt num_points, num_contours;
diff --git a/src/base/ftsystem.c b/src/base/ftsystem.c
index 66c5d76..7e203be 100644
--- a/src/base/ftsystem.c
+++ b/src/base/ftsystem.c
@@ -4,7 +4,7 @@
/* */
/* ANSI-specific FreeType low-level system interface (body). */
/* */
-/* Copyright 1996-2001, 2002, 2006, 2008, 2009, 2010 by */
+/* Copyright 1996-2002, 2006, 2008-2011 by */
/* David Turner, Robert Wilhelm, and Werner Lemberg. */
/* */
/* This file is part of the FreeType project, and may only be used, */
@@ -137,6 +137,7 @@
/* */
/*************************************************************************/
+#ifndef FT_CONFIG_OPTION_DISABLE_STREAM_SUPPORT
/*************************************************************************/
/* */
@@ -267,6 +268,7 @@
return FT_Err_Ok;
}
+#endif /* !FT_CONFIG_OPTION_DISABLE_STREAM_SUPPORT */
#ifdef FT_DEBUG_MEMORY