diff --git a/ChangeLog b/ChangeLog index 749ef1469..5031e66f1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2006-02-23 Chia-I Wu + + * include/freetype/ftoutln.h (enum FT_Orientation): New value + `FT_ORIENTATION_NONE'. + + * src/base/ftoutln.c (FT_OUTLINE_GET_CONTOUR, ft_contour_has, + ft_contour_enclosed, ft_outline_get_orientation): Another version of + `FT_Outline_Get_Orientation'. This version differs from the public + one in that each part (contour not enclosed in another contour) of the + outline is checked for orientation. + (FT_Outline_Embolden): Use `ft_outline_get_orientation'. + + * src/base/ftsynth.c (FT_GlyphSlot_Embolden): Render the outline and + use bitmap's embolden routine when the outline one failed. + 2006-02-22 Chia-I Wu * modules.cfg: Compile in ftotval.c and ftxf86.c by default for ABI diff --git a/include/freetype/ftoutln.h b/include/freetype/ftoutln.h index 946af7378..8939030d2 100644 --- a/include/freetype/ftoutln.h +++ b/include/freetype/ftoutln.h @@ -465,13 +465,19 @@ FT_BEGIN_HEADER * This is identical to @FT_ORIENTATION_POSTSCRIPT, but is used to * remember that in Postscript, everything that is to the left of * the drawing direction of a contour must be filled. + * + * FT_ORIENTATION_NONE :: + * The orientation cannot be determined. That is, different part of the + * glyph has different orientation. + * */ typedef enum { FT_ORIENTATION_TRUETYPE = 0, FT_ORIENTATION_POSTSCRIPT = 1, FT_ORIENTATION_FILL_RIGHT = FT_ORIENTATION_TRUETYPE, - FT_ORIENTATION_FILL_LEFT = FT_ORIENTATION_POSTSCRIPT + FT_ORIENTATION_FILL_LEFT = FT_ORIENTATION_POSTSCRIPT, + FT_ORIENTATION_NONE } FT_Orientation; diff --git a/src/base/ftoutln.c b/src/base/ftoutln.c index a252b2209..b9f845944 100644 --- a/src/base/ftoutln.c +++ b/src/base/ftoutln.c @@ -668,6 +668,168 @@ } +#define FT_OUTLINE_GET_CONTOUR( outline, c, first, last ) \ + do { \ + ( first ) = ( c > 0 ) ? ( outline )->points + \ + ( outline )->contours[c - 1] + 1 \ + : ( outline )->points; \ + ( last ) = ( outline )->points + ( outline )->contours[c]; \ + } while ( 0 ) + + + /* Is a point in some contour? */ + /* */ + /* We treat every point of the contour as if it */ + /* it is ON. That is, we allow false positive, */ + /* but disallow false negative. (XXX really?) */ + static FT_Bool + ft_contour_has( FT_Outline* outline, + FT_Short c, + FT_Vector* point ) + { + FT_Vector* first; + FT_Vector* last; + FT_Vector* a; + FT_Vector* b; + FT_UInt n = 0; + + + FT_OUTLINE_GET_CONTOUR( outline, c, first, last ); + + for ( a = first; a <= last; a++ ) + { + FT_Pos x; + FT_Int intersect; + + + b = ( a == last ) ? first : a + 1; + + intersect = ( a->y - point->y ) ^ ( b->y - point->y ); + + /* a and b are on the same side */ + if ( intersect >= 0 ) + { + if ( intersect == 0 && a->y == point->y ) + { + if ( ( a->x <= point->x && b->x >= point->x ) || + ( a->x >= point->x && b->x <= point->x ) ) + return 1; + } + + continue; + } + + x = a->x + ( b->x - a->x ) * (point->y - a->y ) / ( b->y - a->y ); + + if ( x < point->x ) + n++; + else if ( x == point->x ) + return 1; + } + + return ( n % 2 ); + } + + + static FT_Bool + ft_contour_enclosed( FT_Outline* outline, + FT_UShort c ) + { + FT_Vector* first; + FT_Vector* last; + FT_Short i; + + + FT_OUTLINE_GET_CONTOUR( outline, c, first, last ); + + for ( i = 0; i < outline->n_contours; i++ ) + { + if ( i != c && ft_contour_has( outline, i, first ) ) + { + FT_Vector* pt; + + + for ( pt = first + 1; pt <= last; pt++ ) + if ( !ft_contour_has( outline, i, pt ) ) + return 0; + + return 1; + } + } + + return 0; + } + + + /* This version differs from the public one in that each */ + /* part (contour not enclosed in another contour) of the */ + /* outline is checked for orientation. This is */ + /* necessary for some buggy CJK fonts. */ + static FT_Orientation + ft_outline_get_orientation( FT_Outline* outline ) + { + FT_Short i; + FT_Vector* first; + FT_Vector* last; + FT_Orientation orient = FT_ORIENTATION_NONE; + + + first = outline->points; + for ( i = 0; i < outline->n_contours; i++, first = last + 1 ) + { + FT_Vector* point; + FT_Vector* xmin_point; + FT_Pos xmin; + + + last = outline->points + outline->contours[i]; + + /* skip degenerate contours */ + if ( last < first + 2 ) + continue; + + if ( ft_contour_enclosed( outline, i ) ) + continue; + + xmin = first->x; + xmin_point = first; + + for ( point = first + 1; point <= last; point++ ) + { + if ( point->x < xmin ) + { + xmin = point->x; + xmin_point = point; + } + } + + /* check the orientation of the contour */ + { + FT_Vector* prev; + FT_Vector* next; + FT_Orientation o; + + + prev = ( xmin_point == first ) ? last : xmin_point - 1; + next = ( xmin_point == last ) ? first : xmin_point + 1; + + 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 ) ) + o = FT_ORIENTATION_POSTSCRIPT; + else + o = FT_ORIENTATION_TRUETYPE; + + if ( orient == FT_ORIENTATION_NONE ) + orient = o; + else if ( orient != o ) + return FT_ORIENTATION_NONE; + } + } + + return orient; + } + + /* documentation is in ftoutln.h */ FT_EXPORT_DEF( FT_Error ) @@ -678,6 +840,7 @@ FT_Vector v_prev, v_first, v_next, v_cur; FT_Angle rotate, angle_in, angle_out; FT_Int c, n, first; + FT_Int orientation; if ( !outline ) @@ -687,7 +850,16 @@ if ( strength == 0 ) return FT_Err_Ok; - if ( FT_Outline_Get_Orientation( outline ) == FT_ORIENTATION_TRUETYPE ) + orientation = ft_outline_get_orientation( outline ); + if ( orientation == FT_ORIENTATION_NONE ) + { + if ( outline->n_contours ) + return FT_Err_Invalid_Argument; + else + return FT_Err_Ok; + } + + if ( orientation == FT_ORIENTATION_TRUETYPE ) rotate = -FT_ANGLE_PI2; else rotate = FT_ANGLE_PI2; diff --git a/src/base/ftsynth.c b/src/base/ftsynth.c index 07a171609..ebb86a838 100644 --- a/src/base/ftsynth.c +++ b/src/base/ftsynth.c @@ -75,10 +75,14 @@ { FT_Library library = slot->library; FT_Face face = FT_SLOT_FACE( slot ); - FT_Error error = FT_Err_Ok; + FT_Error error; FT_Pos xstr, ystr; + if ( slot->format != FT_GLYPH_FORMAT_OUTLINE && + slot->format != FT_GLYPH_FORMAT_BITMAP ) + return; + /* some reasonable strength */ xstr = FT_MulFix( face->units_per_EM, face->size->metrics.y_scale ) / 24; @@ -87,13 +91,22 @@ if ( slot->format == FT_GLYPH_FORMAT_OUTLINE ) { error = FT_Outline_Embolden( &slot->outline, xstr ); - - /* this is more than enough for most glyphs; */ - /* if you need accurate values, you have to call FT_Outline_Get_CBox */ - xstr = xstr * 2; - ystr = xstr; + if ( error ) + { + error = FT_Render_Glyph( slot, FT_RENDER_MODE_NORMAL ); + if ( error ) + return; + } + else + { + /* this is more than enough for most glyphs; */ + /* if you need accurate values, you have to call FT_Outline_Get_CBox */ + xstr = xstr * 2; + ystr = xstr; + } } - else if ( slot->format == FT_GLYPH_FORMAT_BITMAP ) + + if ( slot->format == FT_GLYPH_FORMAT_BITMAP ) { xstr = FT_PIX_FLOOR( xstr ); if ( xstr == 0 ) @@ -108,37 +121,31 @@ FT_Bitmap_New( &bitmap ); error = FT_Bitmap_Copy( library, &slot->bitmap, &bitmap ); + if ( error ) + return; - if ( !error ) - { - slot->bitmap = bitmap; - slot->internal->flags |= FT_GLYPH_OWN_BITMAP; - } + slot->bitmap = bitmap; + slot->internal->flags |= FT_GLYPH_OWN_BITMAP; } - if ( !error ) - error = FT_Bitmap_Embolden( library, &slot->bitmap, xstr, ystr ); + error = FT_Bitmap_Embolden( library, &slot->bitmap, xstr, ystr ); + if ( error ) + return; } - else - error = FT_Err_Invalid_Argument; - /* modify the metrics accordingly */ - if ( !error ) - { - /* assume the layout is horizontal */ - slot->advance.x += xstr; + /* assume the layout is horizontal */ + slot->advance.x += xstr; - slot->metrics.width += xstr; - slot->metrics.height += ystr; - slot->metrics.horiBearingY += ystr; - slot->metrics.horiAdvance += xstr; - slot->metrics.vertBearingX -= xstr / 2; - slot->metrics.vertBearingY += ystr; - slot->metrics.vertAdvance += ystr; + slot->metrics.width += xstr; + slot->metrics.height += ystr; + slot->metrics.horiBearingY += ystr; + slot->metrics.horiAdvance += xstr; + slot->metrics.vertBearingX -= xstr / 2; + slot->metrics.vertBearingY += ystr; + slot->metrics.vertAdvance += ystr; - if ( slot->format == FT_GLYPH_FORMAT_BITMAP ) - slot->bitmap_top += ystr >> 6; - } + if ( slot->format == FT_GLYPH_FORMAT_BITMAP ) + slot->bitmap_top += ystr >> 6; }