[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Devel] FT_Outline_Get_Orientation is very broken
From: |
Anders Kaseorg |
Subject: |
Re: [Devel] FT_Outline_Get_Orientation is very broken |
Date: |
Tue, 23 Nov 2004 23:12:32 -0500 |
User-agent: |
Mozilla Thunderbird 0.9+ (X11/20041123) |
Werner LEMBERG wrote:
The functions are coded very differently. I don't know whether it is
worth the effort to unify them, but you are invited to contribute code
if it actually makes sense :-)
Okay. This patch replaces all of these functions with one that's much
simpler, faster, and more likely to be correct. I tested that
FT_Outline_Get_Orientation now works correctly on PostScript and
Truetype fonts, including some with incorrect reversed glyphs, and that
it does what was expected by the code that had used ah_get_orientation
(and presumably ft_get_orientation, since that was almost identical).
Anders
Index: include/freetype/config/ftoption.h
===================================================================
RCS file: /cvs/freetype/freetype2/include/freetype/config/ftoption.h,v
retrieving revision 1.88
diff -u -r1.88 ftoption.h
--- ftoption.h 2004/11/17 08:19:26 1.88
+++ ftoption.h 2004/11/24 04:09:16
@@ -436,7 +436,7 @@
/* Do not #undef this macro here, since the build system might */
/* define it for certain configurations only. */
/* */
-#define TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+/* #define TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
/*************************************************************************/
Index: src/autohint/ahglyph.c
===================================================================
RCS file: /cvs/freetype/freetype2/src/autohint/ahglyph.c,v
retrieving revision 1.59
diff -u -r1.59 ahglyph.c
--- ahglyph.c 2004/03/27 08:43:17 1.59
+++ ahglyph.c 2004/11/24 04:09:16
@@ -21,6 +21,7 @@
#include <ft2build.h>
+#include FT_OUTLINE_H
#include "ahglyph.h"
#include "ahangles.h"
#include "ahglobal.h"
@@ -164,144 +165,6 @@
}
- /* this function is used by ah_get_orientation (see below) to test */
- /* the fill direction of given bbox extremum */
- static FT_Int
- ah_test_extremum( FT_Outline* outline,
- FT_Int n )
- {
- FT_Vector *prev, *cur, *next;
- FT_Pos product;
- FT_Int first, last, c;
- FT_Int retval;
-
-
- /* we need to compute the `previous' and `next' point */
- /* for this extremum; we check whether the extremum */
- /* is start or end of a contour and providing */
- /* appropriate values if so */
- cur = outline->points + n;
- prev = cur - 1;
- next = cur + 1;
-
- first = 0;
- for ( c = 0; c < outline->n_contours; c++ )
- {
- last = outline->contours[c];
-
- if ( n == first )
- prev = outline->points + last;
-
- if ( n == last )
- next = outline->points + first;
-
- first = last + 1;
- }
-
- /* compute the vectorial product -- since we know that the angle */
- /* is <= 180 degrees (otherwise it wouldn't be an extremum) we */
- /* can determine the filling orientation if the product is */
- /* either positive or negative */
- product = FT_MulDiv( cur->x - prev->x, /* in.x */
- next->y - cur->y, /* out.y */
- 0x40 )
- -
- FT_MulDiv( cur->y - prev->y, /* in.y */
- next->x - cur->x, /* out.x */
- 0x40 );
-
- retval = 0;
- if ( product )
- retval = product > 0 ? 2 : 1;
-
- return retval;
- }
-
-
- /* Compute the orientation of path filling. It differs between TrueType */
- /* and Type1 formats. We could use the `FT_OUTLINE_REVERSE_FILL' flag, */
- /* but it is better to re-compute it directly (it seems that this flag */
- /* isn't correctly set for some weird composite glyphs currently). */
- /* */
- /* We do this by computing bounding box points, and computing their */
- /* curvature. */
- /* */
- /* The function returns either 1 or 2. */
- /* */
- static FT_Int
- ah_get_orientation( FT_Outline* outline )
- {
- FT_BBox box;
- FT_Int indices_xMin, indices_yMin, indices_xMax, indices_yMax;
- FT_Int n, last;
-
-
- indices_xMin = -1;
- indices_yMin = -1;
- indices_xMax = -1;
- indices_yMax = -1;
-
- box.xMin = box.yMin = 32767L;
- box.xMax = box.yMax = -32768L;
-
- /* is it empty? */
- if ( outline->n_contours < 1 )
- return 1;
-
- last = outline->contours[outline->n_contours - 1];
-
- for ( n = 0; n <= last; n++ )
- {
- FT_Pos x, y;
-
-
- x = outline->points[n].x;
- if ( x < box.xMin )
- {
- box.xMin = x;
- indices_xMin = n;
- }
- if ( x > box.xMax )
- {
- box.xMax = x;
- indices_xMax = n;
- }
-
- y = outline->points[n].y;
- if ( y < box.yMin )
- {
- box.yMin = y;
- indices_yMin = n;
- }
- if ( y > box.yMax )
- {
- box.yMax = y;
- indices_yMax = n;
- }
- }
-
- /* test orientation of the extrema */
- n = ah_test_extremum( outline, indices_xMin );
- if ( n )
- goto Exit;
-
- n = ah_test_extremum( outline, indices_yMin );
- if ( n )
- goto Exit;
-
- n = ah_test_extremum( outline, indices_xMax );
- if ( n )
- goto Exit;
-
- n = ah_test_extremum( outline, indices_yMax );
- if ( !n )
- n = 1;
-
- Exit:
- return n;
- }
-
-
/*************************************************************************/
/* */
/* <Function> */
@@ -465,7 +328,7 @@
outline->vert_major_dir = AH_DIR_UP;
outline->horz_major_dir = AH_DIR_LEFT;
- if ( ah_get_orientation( source ) > 1 )
+ if ( FT_Outline_Get_Orientation( source ) == FT_ORIENTATION_POSTSCRIPT )
{
outline->vert_major_dir = AH_DIR_DOWN;
outline->horz_major_dir = AH_DIR_RIGHT;
Index: src/base/ftoutln.c
===================================================================
RCS file: /cvs/freetype/freetype2/src/base/ftoutln.c,v
retrieving revision 1.57
diff -u -r1.57 ftoutln.c
--- ftoutln.c 2004/01/22 09:07:10 1.57
+++ ftoutln.c 2004/11/24 04:09:16
@@ -653,142 +653,60 @@
}
- typedef struct FT_OrientationExtremumRec_
- {
- FT_Int index;
- FT_Long pos;
- FT_Int first;
- FT_Int last;
-
- } FT_OrientationExtremumRec;
-
-
- static FT_Orientation
- ft_orientation_extremum_compute( FT_OrientationExtremumRec* extremum,
- FT_Outline* outline )
- {
- FT_Vector *point, *first, *last, *prev, *next;
- FT_Vector* points = outline->points;
- FT_Angle angle_in, angle_out;
-
+ /* documentation is in ftoutln.h */
- /* compute the previous and next points in the same contour */
- point = points + extremum->index;
- first = points + extremum->first;
- last = points + extremum->last;
-
- prev = point;
- next = point;
-
- do
- {
- prev = ( prev == first ) ? last : prev - 1;
- if ( prev == point )
- return FT_ORIENTATION_TRUETYPE; /* degenerate case */
-
- } while ( prev->x != point->x || prev->y != point->y );
-
- do
- {
- next = ( next == last ) ? first : next + 1;
- if ( next == point )
- return FT_ORIENTATION_TRUETYPE; /* shouldn't happen */
-
- } while ( next->x != point->x || next->y != point->y );
-
- /* now compute the orientation of the `out' vector relative */
- /* to the `in' vector. */
- angle_in = FT_Atan2( point->x - prev->x, point->y - prev->y );
- angle_out = FT_Atan2( next->x - point->x, next->y - point->y );
-
- return ( FT_Angle_Diff( angle_in, angle_out ) >= 0 )
- ? FT_ORIENTATION_TRUETYPE
- : FT_ORIENTATION_POSTSCRIPT;
- }
-
-
FT_EXPORT_DEF( FT_Orientation )
FT_Outline_Get_Orientation( FT_Outline* outline )
{
- FT_Orientation result = FT_ORIENTATION_TRUETYPE;
-
-
- if ( outline && outline->n_points > 0 )
+ FT_Pos xmin = +32768L;
+ FT_Vector* xmin_point = NULL;
+ FT_Vector* xmin_first = NULL;
+ FT_Vector* xmin_last = NULL;
+ short* contour;
+ FT_Vector* first;
+ FT_Vector* last;
+ FT_Vector* prev;
+ FT_Vector* next;
+
+ if ( !outline || outline->n_points <= 0 )
+ return FT_ORIENTATION_TRUETYPE;
+
+ first = outline->points;
+ for ( contour = outline->contours;
+ contour < outline->contours + outline->n_contours;
+ contour++, first = last + 1 )
{
- FT_OrientationExtremumRec xmin, ymin, xmax, ymax;
- FT_Int n;
- FT_Int first, last;
- FT_Vector* points = outline->points;
-
+ FT_Vector* point;
- xmin.pos = ymin.pos = +32768L;
- xmax.pos = ymax.pos = -32768L;
+ last = outline->points + *contour;
- xmin.index = ymin.index = xmax.index = ymax.index = -1;
+ /* skip degenerate contours */
+ if ( last < first + 2 )
+ continue;
- first = 0;
- for ( n = 0; n < outline->n_contours; n++, first = last + 1 )
+ for ( point = first; point <= last; point++ )
{
- last = outline->contours[n];
-
- /* skip single-point contours; these are degenerated cases */
- if ( last > first + 1 )
- {
- FT_Int i;
-
-
- for ( i = first; i < last; i++ )
- {
- FT_Pos x = points[i].x;
- FT_Pos y = points[i].y;
-
-
- if ( x < xmin.pos )
- {
- xmin.pos = x;
- xmin.index = i;
- xmin.first = first;
- xmin.last = last;
- }
- if ( x > xmax.pos )
- {
- xmax.pos = x;
- xmax.index = i;
- xmax.first = first;
- xmax.last = last;
- }
- if ( y < ymin.pos )
- {
- ymin.pos = y;
- ymin.index = i;
- ymin.first = first;
- ymin.last = last;
- }
- if ( y > ymax.pos )
- {
- ymax.pos = y;
- ymax.index = i;
- ymax.first = first;
- ymax.last = last;
- }
- }
- }
-
- if ( xmin.index >= 0 )
- result = ft_orientation_extremum_compute( &xmin, outline );
-
- else if ( xmax.index >= 0 )
- result = ft_orientation_extremum_compute( &xmax, outline );
-
- else if ( ymin.index >= 0 )
- result = ft_orientation_extremum_compute( &ymin, outline );
-
- else if ( ymax.index >= 0 )
- result = ft_orientation_extremum_compute( &ymax, outline );
+ if ( point->x < xmin )
+ {
+ xmin = point->x;
+ xmin_point = point;
+ xmin_first = first;
+ xmin_last = last;
+ }
}
}
+
+ if ( !xmin_point )
+ return FT_ORIENTATION_TRUETYPE;
+
+ prev = ( xmin_point == xmin_first ) ? xmin_last : xmin_point - 1;
+ next = ( xmin_point == xmin_last ) ? xmin_first : xmin_point + 1;
- return result;
+ if ( FT_Atan2( prev->x - xmin_point->x, prev->y - xmin_point->y ) >
+ FT_Atan2( next->x - xmin_point->x, next->y - xmin_point->y ) )
+ return FT_ORIENTATION_POSTSCRIPT;
+ else
+ return FT_ORIENTATION_TRUETYPE;
}
Index: src/base/ftsynth.c
===================================================================
RCS file: /cvs/freetype/freetype2/src/base/ftsynth.c,v
retrieving revision 1.20
diff -u -r1.20 ftsynth.c
--- ftsynth.c 2003/12/24 13:37:58 1.20
+++ ftsynth.c 2004/11/24 04:09:16
@@ -71,134 +71,6 @@
- static int
- ft_test_extrema( FT_Outline* outline,
- int n )
- {
- FT_Vector *prev, *cur, *next;
- FT_Pos product;
- FT_Int c, first, last;
-
-
- /* we need to compute the `previous' and `next' point */
- /* for these extrema. */
- cur = outline->points + n;
- prev = cur - 1;
- next = cur + 1;
-
- first = 0;
- for ( c = 0; c < outline->n_contours; c++ )
- {
- last = outline->contours[c];
-
- if ( n == first )
- prev = outline->points + last;
-
- if ( n == last )
- next = outline->points + first;
-
- first = last + 1;
- }
-
- product = FT_MulDiv( cur->x - prev->x, /* in.x */
- next->y - cur->y, /* out.y */
- 0x40 )
- -
- FT_MulDiv( cur->y - prev->y, /* in.y */
- next->x - cur->x, /* out.x */
- 0x40 );
-
- if ( product )
- product = product > 0 ? 1 : -1;
-
- return product;
- }
-
-
- /* Compute the orientation of path filling. It differs between TrueType */
- /* and Type1 formats. We could use the `FT_OUTLINE_REVERSE_FILL' flag, */
- /* but it is better to re-compute it directly (it seems that this flag */
- /* isn't correctly set for some weird composite glyphs currently). */
- /* */
- /* We do this by computing bounding box points, and computing their */
- /* curvature. */
- /* */
- /* The function returns either 1 or -1. */
- /* */
- static int
- ft_get_orientation( FT_Outline* outline )
- {
- FT_BBox box;
- FT_BBox indices;
- int n, last;
-
-
- indices.xMin = -1;
- indices.yMin = -1;
- indices.xMax = -1;
- indices.yMax = -1;
-
- box.xMin = box.yMin = 32767;
- box.xMax = box.yMax = -32768;
-
- /* is it empty ? */
- if ( outline->n_contours < 1 )
- return 1;
-
- last = outline->contours[outline->n_contours - 1];
-
- for ( n = 0; n <= last; n++ )
- {
- FT_Pos x, y;
-
-
- x = outline->points[n].x;
- if ( x < box.xMin )
- {
- box.xMin = x;
- indices.xMin = n;
- }
- if ( x > box.xMax )
- {
- box.xMax = x;
- indices.xMax = n;
- }
-
- y = outline->points[n].y;
- if ( y < box.yMin )
- {
- box.yMin = y;
- indices.yMin = n;
- }
- if ( y > box.yMax )
- {
- box.yMax = y;
- indices.yMax = n;
- }
- }
-
- /* test orientation of the xmin */
- n = ft_test_extrema( outline, indices.xMin );
- if ( n )
- goto Exit;
-
- n = ft_test_extrema( outline, indices.yMin );
- if ( n )
- goto Exit;
-
- n = ft_test_extrema( outline, indices.xMax );
- if ( n )
- goto Exit;
-
- n = ft_test_extrema( outline, indices.yMax );
- if ( !n )
- n = 1;
-
- Exit:
- return n;
- }
-
-
FT_EXPORT_DEF( void )
FT_GlyphSlot_Embolden( FT_GlyphSlot slot )
{
@@ -208,7 +80,7 @@
FT_Outline* outline = &slot->outline;
FT_Face face = FT_SLOT_FACE( slot );
FT_Angle rotate, angle_in, angle_out;
- FT_Int c, n, first, orientation;
+ FT_Int c, n, first;
/* only embolden outline glyph images */
@@ -219,8 +91,10 @@
distance = FT_MulFix( face->units_per_EM / 60,
face->size->metrics.y_scale );
- orientation = ft_get_orientation( outline );
- rotate = FT_ANGLE_PI2*orientation;
+ if (FT_Outline_Get_Orientation( outline ) == FT_ORIENTATION_TRUETYPE)
+ rotate = -FT_ANGLE_PI2;
+ else
+ rotate = FT_ANGLE_PI2;
points = outline->points;