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 ); }
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; /* 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; }
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 ); }
FT_Outline_Embolden( FT_Outline* outline, FT_Pos strength ) { 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; strength /= 2; if ( strength == 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; 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]; v_first = points[first]; v_prev = points[last]; v_cur = v_first; for ( n = first; n <= last; n++ ) { FT_Vector in, out; FT_Angle angle_diff; FT_Pos d; FT_Fixed scale; 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; out.x = v_next.x - v_cur.x; out.y = v_next.y - v_cur.y; 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 ); if ( scale < 0x4000L && scale > -0x4000L ) in.x = in.y = 0; else { d = FT_DivFix( strength, scale ); FT_Vector_From_Polar( &in, d, angle_in + angle_diff / 2 - rotate ); } outline->points[n].x = v_cur.x + strength + in.x; outline->points[n].y = v_cur.y + strength + in.y; v_prev = v_cur; v_cur = v_next; } first = last + 1; } return FT_Err_Ok; }
/* 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; }
static void GK_Outline_Embolden(FT_Outline* outline,FT_Pos strength,int* x_left,int* x_right,int* y_bottom,int* y_top) { 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 = 0; FT_Int orientation; FT_Int min_x = 35565, max_x = -35565, min_y = 35565, max_y = -35565; FT_Int new_min_x = 35565, new_max_x = -35565, new_min_y = 35565, new_max_y = -35565; if (!outline) return; strength /= 2; if ( strength == 0 ) return; orientation = FT_Outline_Get_Orientation(outline); if (orientation == FT_ORIENTATION_NONE) return; #ifdef GLYPH_LOG if (glyph_log) { fprintf(glyph_log," Emboldening the outline by %ld:\n",strength); } #endif if (orientation == FT_ORIENTATION_TRUETYPE) rotate = -FT_ANGLE_PI2; else rotate = FT_ANGLE_PI2; points = outline->points; for ( c = 0; c < outline->n_contours; c++ ) { int last = outline->contours[c]; v_first = points[first]; v_prev = points[last]; v_cur = v_first; for ( n = first; n <= last; n++ ) { FT_Vector in, out; FT_Angle angle_diff; FT_Pos d; FT_Fixed scale; 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; out.x = v_next.x - v_cur.x; out.y = v_next.y - v_cur.y; 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 ); if ( scale < 0x4000L && scale > -0x4000L ) in.x = in.y = 0; else { d = FT_DivFix( strength, scale ); FT_Vector_From_Polar( &in, d, angle_in + angle_diff / 2 - rotate ); } outline->points[n].x = v_cur.x + strength + in.x; outline->points[n].y = v_cur.y + strength + in.y; if (v_cur.x < min_x) min_x = v_cur.x; if (v_cur.x > max_x) max_x = v_cur.x; if (v_cur.y < min_y) min_y = v_cur.y; if (v_cur.y > max_y) max_y = v_cur.y; if (outline->points[n].x < new_min_x) new_min_x = outline->points[n].x; if (outline->points[n].x > new_max_x) new_max_x = outline->points[n].x; if (outline->points[n].y < new_min_y) new_min_y = outline->points[n].y; if (outline->points[n].y > new_max_y) new_max_y = outline->points[n].y; v_prev = v_cur; v_cur = v_next; } first = last + 1; } *x_left = min_x - new_min_x; *x_right = new_max_x - max_x; *y_top = new_max_y - max_y; *y_bottom = min_y - new_min_y; #ifdef GLYPH_LOG if (glyph_log) { fprintf(glyph_log," (%d..%d x %d..%d) -> (%d..%d x %d..%d)\n", min_x,max_x,min_y,max_y,new_min_x,new_max_x,new_min_y,new_max_y); } #endif }