Index: src/base/ftoutln.c |
diff --git a/src/base/ftoutln.c b/src/base/ftoutln.c |
index 9ae276d082a4fc6e4cfebe744ef84ac402690818..54ca5cdcf6ed206ae58024d3633159602330ce6d 100644 |
--- a/src/base/ftoutln.c |
+++ b/src/base/ftoutln.c |
@@ -4,7 +4,7 @@ |
/* */ |
/* FreeType outline management (body). */ |
/* */ |
-/* Copyright 1996-2008, 2010, 2012 by */ |
+/* Copyright 1996-2008, 2010, 2012-2013 by */ |
/* David Turner, Robert Wilhelm, and Werner Lemberg. */ |
/* */ |
/* This file is part of the FreeType project, and may only be used, */ |
@@ -26,6 +26,7 @@ |
#include <ft2build.h> |
#include FT_OUTLINE_H |
#include FT_INTERNAL_OBJECTS_H |
+#include FT_INTERNAL_CALC_H |
#include FT_INTERNAL_DEBUG_H |
#include FT_TRIGONOMETRY_H |
@@ -73,7 +74,7 @@ |
if ( !outline || !func_interface ) |
- return FT_Err_Invalid_Argument; |
+ return FT_THROW( Invalid_Argument ); |
shift = func_interface->shift; |
delta = func_interface->delta; |
@@ -286,7 +287,7 @@ |
return error; |
Invalid_Outline: |
- return FT_Err_Invalid_Outline; |
+ return FT_THROW( Invalid_Outline ); |
} |
@@ -300,10 +301,17 @@ |
if ( !anoutline || !memory ) |
- return FT_Err_Invalid_Argument; |
+ return FT_THROW( Invalid_Argument ); |
*anoutline = null_outline; |
+ if ( numContours < 0 || |
+ (FT_UInt)numContours > numPoints ) |
+ return FT_THROW( Invalid_Argument ); |
+ |
+ if ( numPoints > FT_OUTLINE_POINTS_MAX ) |
+ return FT_THROW( Array_Too_Large ); |
+ |
if ( FT_NEW_ARRAY( anoutline->points, numPoints ) || |
FT_NEW_ARRAY( anoutline->tags, numPoints ) || |
FT_NEW_ARRAY( anoutline->contours, numContours ) ) |
@@ -332,7 +340,7 @@ |
FT_Outline *anoutline ) |
{ |
if ( !library ) |
- return FT_Err_Invalid_Library_Handle; |
+ return FT_THROW( Invalid_Library_Handle ); |
return FT_Outline_New_Internal( library->memory, numPoints, |
numContours, anoutline ); |
@@ -380,7 +388,7 @@ |
} |
Bad: |
- return FT_Err_Invalid_Argument; |
+ return FT_THROW( Invalid_Argument ); |
} |
@@ -396,7 +404,7 @@ |
if ( !source || !target || |
source->n_points != target->n_points || |
source->n_contours != target->n_contours ) |
- return FT_Err_Invalid_Argument; |
+ return FT_THROW( Invalid_Argument ); |
if ( source == target ) |
return FT_Err_Ok; |
@@ -435,7 +443,7 @@ |
return FT_Err_Ok; |
} |
else |
- return FT_Err_Invalid_Argument; |
+ return FT_THROW( Invalid_Argument ); |
} |
@@ -448,7 +456,7 @@ |
/* check for valid `outline' in FT_Outline_Done_Internal() */ |
if ( !library ) |
- return FT_Err_Invalid_Library_Handle; |
+ return FT_THROW( Invalid_Library_Handle ); |
return FT_Outline_Done_Internal( library->memory, outline ); |
} |
@@ -602,21 +610,21 @@ |
if ( !library ) |
- return FT_Err_Invalid_Library_Handle; |
+ return FT_THROW( Invalid_Library_Handle ); |
if ( !outline || !params ) |
- return FT_Err_Invalid_Argument; |
+ return FT_THROW( Invalid_Argument ); |
renderer = library->cur_renderer; |
node = library->renderers.head; |
params->source = (void*)outline; |
- error = FT_Err_Cannot_Render_Glyph; |
+ error = FT_ERR( Cannot_Render_Glyph ); |
while ( renderer ) |
{ |
error = renderer->raster_render( renderer->raster, params ); |
- if ( !error || FT_ERROR_BASE( error ) != FT_Err_Cannot_Render_Glyph ) |
+ if ( !error || FT_ERR_NEQ( error, Cannot_Render_Glyph ) ) |
break; |
/* FT_Err_Cannot_Render_Glyph is returned if the render mode */ |
@@ -650,7 +658,7 @@ |
if ( !abitmap ) |
- return FT_Err_Invalid_Argument; |
+ return FT_THROW( Invalid_Argument ); |
/* other checks are delayed to FT_Outline_Render() */ |
@@ -882,85 +890,126 @@ |
FT_Outline_Embolden( FT_Outline* outline, |
FT_Pos strength ) |
{ |
+ return FT_Outline_EmboldenXY( outline, strength, strength ); |
+ } |
+ |
+ |
+ /* documentation is in ftoutln.h */ |
+ |
+ FT_EXPORT_DEF( FT_Error ) |
+ FT_Outline_EmboldenXY( FT_Outline* outline, |
+ FT_Pos xstrength, |
+ FT_Pos ystrength ) |
+ { |
FT_Vector* points; |
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 ) |
- return FT_Err_Invalid_Argument; |
+ return FT_THROW( Invalid_Argument ); |
- strength /= 2; |
- if ( strength == 0 ) |
+ xstrength /= 2; |
+ ystrength /= 2; |
+ if ( xstrength == 0 && ystrength == 0 ) |
return FT_Err_Ok; |
orientation = FT_Outline_Get_Orientation( outline ); |
if ( orientation == FT_ORIENTATION_NONE ) |
{ |
if ( outline->n_contours ) |
- return FT_Err_Invalid_Argument; |
+ return FT_THROW( Invalid_Argument ); |
else |
return FT_Err_Ok; |
} |
- if ( orientation == FT_ORIENTATION_TRUETYPE ) |
- rotate = -FT_ANGLE_PI2; |
- else |
- rotate = FT_ANGLE_PI2; |
- |
points = outline->points; |
first = 0; |
for ( c = 0; c < outline->n_contours; c++ ) |
{ |
- int last = outline->contours[c]; |
+ FT_Vector in, out, shift; |
+ FT_Fixed l_in, l_out, l, q, d; |
+ int last = outline->contours[c]; |
v_first = points[first]; |
v_prev = points[last]; |
v_cur = v_first; |
- for ( n = first; n <= last; n++ ) |
+ /* compute incoming normalized vector */ |
+ in.x = v_cur.x - v_prev.x; |
+ in.y = v_cur.y - v_prev.y; |
+ l_in = FT_Vector_Length( &in ); |
+ if ( l_in ) |
{ |
- FT_Vector in, out; |
- FT_Angle angle_diff; |
- FT_Pos d; |
- FT_Fixed scale; |
- |
+ in.x = FT_DivFix( in.x, l_in ); |
+ in.y = FT_DivFix( in.y, l_in ); |
+ } |
+ for ( n = first; n <= last; n++ ) |
+ { |
if ( n < last ) |
v_next = points[n + 1]; |
else |
v_next = v_first; |
- /* compute the in and out vectors */ |
- in.x = v_cur.x - v_prev.x; |
- in.y = v_cur.y - v_prev.y; |
- |
+ /* compute outgoing normalized vector */ |
out.x = v_next.x - v_cur.x; |
out.y = v_next.y - v_cur.y; |
+ l_out = FT_Vector_Length( &out ); |
+ if ( l_out ) |
+ { |
+ out.x = FT_DivFix( out.x, l_out ); |
+ out.y = FT_DivFix( out.y, l_out ); |
+ } |
- angle_in = FT_Atan2( in.x, in.y ); |
- angle_out = FT_Atan2( out.x, out.y ); |
- angle_diff = FT_Angle_Diff( angle_in, angle_out ); |
- scale = FT_Cos( angle_diff / 2 ); |
+ d = FT_MulFix( in.x, out.x ) + FT_MulFix( in.y, out.y ); |
- if ( scale < 0x4000L && scale > -0x4000L ) |
- in.x = in.y = 0; |
- else |
+ /* shift only if turn is less than ~160 degrees */ |
+ if ( d > -0xF000L ) |
{ |
- d = FT_DivFix( strength, scale ); |
+ d = d + 0x10000L; |
- FT_Vector_From_Polar( &in, d, angle_in + angle_diff / 2 - rotate ); |
+ /* shift components are aligned along lateral bisector */ |
+ /* and directed according to the outline orientation. */ |
+ shift.x = in.y + out.y; |
+ shift.y = in.x + out.x; |
+ |
+ if ( orientation == FT_ORIENTATION_TRUETYPE ) |
+ shift.x = -shift.x; |
+ else |
+ shift.y = -shift.y; |
+ |
+ /* restrict shift magnitude to better handle collapsing segments */ |
+ q = FT_MulFix( out.x, in.y ) - FT_MulFix( out.y, in.x ); |
+ if ( orientation == FT_ORIENTATION_TRUETYPE ) |
+ q = -q; |
+ |
+ l = FT_MIN( l_in, l_out ); |
+ |
+ /* non-strict inequalities avoid divide-by-zero when q == l == 0 */ |
+ if ( FT_MulFix( xstrength, q ) <= FT_MulFix( d, l ) ) |
+ shift.x = FT_MulDiv( shift.x, xstrength, d ); |
+ else |
+ shift.x = FT_MulDiv( shift.x, l, q ); |
+ |
+ |
+ if ( FT_MulFix( ystrength, q ) <= FT_MulFix( d, l ) ) |
+ shift.y = FT_MulDiv( shift.y, ystrength, d ); |
+ else |
+ shift.y = FT_MulDiv( shift.y, l, q ); |
} |
+ else |
+ shift.x = shift.y = 0; |
- outline->points[n].x = v_cur.x + strength + in.x; |
- outline->points[n].y = v_cur.y + strength + in.y; |
+ outline->points[n].x = v_cur.x + xstrength + shift.x; |
+ outline->points[n].y = v_cur.y + ystrength + shift.y; |
- v_prev = v_cur; |
- v_cur = v_next; |
+ in = out; |
+ l_in = l_out; |
+ v_cur = v_next; |
} |
first = last + 1; |
@@ -975,23 +1024,12 @@ |
FT_EXPORT_DEF( FT_Orientation ) |
FT_Outline_Get_Orientation( FT_Outline* outline ) |
{ |
- FT_Pos xmin = 32768L; |
- FT_Pos xmin_ymin = 32768L; |
- FT_Pos xmin_ymax = -32768L; |
- FT_Vector* xmin_first = NULL; |
- FT_Vector* xmin_last = NULL; |
- |
- short* contour; |
- |
- FT_Vector* first; |
- FT_Vector* last; |
- FT_Vector* prev; |
- FT_Vector* point; |
- |
- int i; |
- FT_Pos ray_y[3]; |
- FT_Orientation result[3] = |
- { FT_ORIENTATION_NONE, FT_ORIENTATION_NONE, FT_ORIENTATION_NONE }; |
+ FT_BBox cbox; |
+ FT_Int xshift, yshift; |
+ FT_Vector* points; |
+ FT_Vector v_prev, v_cur; |
+ FT_Int c, n, first; |
+ FT_Pos area = 0; |
if ( !outline || outline->n_points <= 0 ) |
@@ -1002,127 +1040,41 @@ |
/* cubic or quadratic curves, this test deals with the polygon */ |
/* only which is spanned up by the control points. */ |
- first = outline->points; |
- for ( contour = outline->contours; |
- contour < outline->contours + outline->n_contours; |
- contour++, first = last + 1 ) |
- { |
- FT_Pos contour_xmin = 32768L; |
- FT_Pos contour_xmax = -32768L; |
- FT_Pos contour_ymin = 32768L; |
- FT_Pos contour_ymax = -32768L; |
- |
- |
- last = outline->points + *contour; |
+ FT_Outline_Get_CBox( outline, &cbox ); |
- /* skip degenerate contours */ |
- if ( last < first + 2 ) |
- continue; |
- |
- for ( point = first; point <= last; ++point ) |
- { |
- if ( point->x < contour_xmin ) |
- contour_xmin = point->x; |
- |
- if ( point->x > contour_xmax ) |
- contour_xmax = point->x; |
- |
- if ( point->y < contour_ymin ) |
- contour_ymin = point->y; |
- |
- if ( point->y > contour_ymax ) |
- contour_ymax = point->y; |
- } |
- |
- if ( contour_xmin < xmin && |
- contour_xmin != contour_xmax && |
- contour_ymin != contour_ymax ) |
- { |
- xmin = contour_xmin; |
- xmin_ymin = contour_ymin; |
- xmin_ymax = contour_ymax; |
- xmin_first = first; |
- xmin_last = last; |
- } |
- } |
+ xshift = FT_MSB( FT_ABS( cbox.xMax ) | FT_ABS( cbox.xMin ) ) - 14; |
+ xshift = FT_MAX( xshift, 0 ); |
- if ( xmin == 32768L ) |
- return FT_ORIENTATION_TRUETYPE; |
+ yshift = FT_MSB( cbox.yMax - cbox.yMin ) - 14; |
+ yshift = FT_MAX( yshift, 0 ); |
- ray_y[0] = ( xmin_ymin * 3 + xmin_ymax ) >> 2; |
- ray_y[1] = ( xmin_ymin + xmin_ymax ) >> 1; |
- ray_y[2] = ( xmin_ymin + xmin_ymax * 3 ) >> 2; |
+ points = outline->points; |
- for ( i = 0; i < 3; i++ ) |
+ first = 0; |
+ for ( c = 0; c < outline->n_contours; c++ ) |
{ |
- FT_Pos left_x; |
- FT_Pos right_x; |
- FT_Vector* left1; |
- FT_Vector* left2; |
- FT_Vector* right1; |
- FT_Vector* right2; |
- |
+ FT_Int last = outline->contours[c]; |
- RedoRay: |
- left_x = 32768L; |
- right_x = -32768L; |
- left1 = left2 = right1 = right2 = NULL; |
+ v_prev = points[last]; |
- prev = xmin_last; |
- for ( point = xmin_first; point <= xmin_last; prev = point, ++point ) |
+ for ( n = first; n <= last; n++ ) |
{ |
- FT_Pos tmp_x; |
- |
- |
- if ( point->y == ray_y[i] || prev->y == ray_y[i] ) |
- { |
- ray_y[i]++; |
- goto RedoRay; |
- } |
- |
- if ( ( point->y < ray_y[i] && prev->y < ray_y[i] ) || |
- ( point->y > ray_y[i] && prev->y > ray_y[i] ) ) |
- continue; |
- |
- tmp_x = FT_MulDiv( point->x - prev->x, |
- ray_y[i] - prev->y, |
- point->y - prev->y ) + prev->x; |
- |
- if ( tmp_x < left_x ) |
- { |
- left_x = tmp_x; |
- left1 = prev; |
- left2 = point; |
- } |
- |
- if ( tmp_x > right_x ) |
- { |
- right_x = tmp_x; |
- right1 = prev; |
- right2 = point; |
- } |
+ v_cur = points[n]; |
+ area += ( ( v_cur.y - v_prev.y ) >> yshift ) * |
+ ( ( v_cur.x + v_prev.x ) >> xshift ); |
+ v_prev = v_cur; |
} |
- if ( left1 && right1 ) |
- { |
- if ( left1->y < left2->y && right1->y > right2->y ) |
- result[i] = FT_ORIENTATION_TRUETYPE; |
- else if ( left1->y > left2->y && right1->y < right2->y ) |
- result[i] = FT_ORIENTATION_POSTSCRIPT; |
- else |
- result[i] = FT_ORIENTATION_NONE; |
- } |
+ first = last + 1; |
} |
- if ( result[0] != FT_ORIENTATION_NONE && |
- ( result[0] == result[1] || result[0] == result[2] ) ) |
- return result[0]; |
- |
- if ( result[1] != FT_ORIENTATION_NONE && result[1] == result[2] ) |
- return result[1]; |
- |
- return FT_ORIENTATION_TRUETYPE; |
+ if ( area > 0 ) |
+ return FT_ORIENTATION_POSTSCRIPT; |
+ else if ( area < 0 ) |
+ return FT_ORIENTATION_TRUETYPE; |
+ else |
+ return FT_ORIENTATION_NONE; |
} |