📄 ftraster.c
字号:
/* cy1 :: The y-coordinate of the arc's first new control point. */ /* */ /* cx2 :: The x-coordinate of the arc's second new control point. */ /* */ /* cy2 :: The y-coordinate of the arc's second new control point. */ /* */ /* x :: The x-coordinate of the arc's end point (its start point is */ /* stored in `LastX'). */ /* */ /* y :: The y-coordinate of the arc's end point (its start point is */ /* stored in `LastY'). */ /* */ /* <Return> */ /* SUCCESS on success, FAILURE on render pool overflow or incorrect */ /* profile. */ /* */ static Bool Cubic_To( RAS_ARGS Long cx1, Long cy1, Long cx2, Long cy2, Long x, Long y ) { Long y1, y2, y3, y4, x4, ymin1, ymax1, ymin2, ymax2; TStates state_bez; ras.arc = ras.arcs; ras.arc[3].x = ras.lastX; ras.arc[3].y = ras.lastY; ras.arc[2].x = cx1; ras.arc[2].y = cy1; ras.arc[1].x = cx2; ras.arc[1].y = cy2; ras.arc[0].x = x; ras.arc[0].y = y; do { y1 = ras.arc[3].y; y2 = ras.arc[2].y; y3 = ras.arc[1].y; y4 = ras.arc[0].y; x4 = ras.arc[0].x; /* first, categorize the Bezier arc */ if ( y1 <= y4 ) { ymin1 = y1; ymax1 = y4; } else { ymin1 = y4; ymax1 = y1; } if ( y2 <= y3 ) { ymin2 = y2; ymax2 = y3; } else { ymin2 = y3; ymax2 = y2; } if ( ymin2 < ymin1 || ymax2 > ymax1 ) { /* this arc has no given direction, split it! */ Split_Cubic( ras.arc ); ras.arc += 3; } else if ( y1 == y4 ) { /* this arc is flat, ignore it and pop it from the Bezier stack */ ras.arc -= 3; } else { state_bez = ( y1 <= y4 ) ? Ascending : Descending; /* detect a change of direction */ if ( ras.state != state_bez ) { if ( ras.state != Unknown && End_Profile( RAS_VAR ) ) goto Fail; if ( New_Profile( RAS_VARS state_bez ) ) goto Fail; } /* compute intersections */ if ( state_bez == Ascending ) { if ( Bezier_Up( RAS_VARS 3, Split_Cubic, ras.minY, ras.maxY ) ) goto Fail; } else if ( Bezier_Down( RAS_VARS 3, Split_Cubic, ras.minY, ras.maxY ) ) goto Fail; } } while ( ras.arc >= ras.arcs ); ras.lastX = x4; ras.lastY = y4; return SUCCESS; Fail: return FAILURE; }#undef SWAP_#define SWAP_( x, y ) do \ { \ Long swap = x; \ \ \ x = y; \ y = swap; \ } while ( 0 ) /*************************************************************************/ /* */ /* <Function> */ /* Decompose_Curve */ /* */ /* <Description> */ /* Scans the outline arays in order to emit individual segments and */ /* Beziers by calling Line_To() and Bezier_To(). It handles all */ /* weird cases, like when the first point is off the curve, or when */ /* there are simply no `on' points in the contour! */ /* */ /* <Input> */ /* first :: The index of the first point in the contour. */ /* */ /* last :: The index of the last point in the contour. */ /* */ /* flipped :: If set, flip the direction of the curve. */ /* */ /* <Return> */ /* SUCCESS on success, FAILURE on error. */ /* */ static Bool Decompose_Curve( RAS_ARGS UShort first, UShort last, int flipped ) { FT_Vector v_last; FT_Vector v_control; FT_Vector v_start; FT_Vector* points; FT_Vector* point; FT_Vector* limit; char* tags; char tag; /* current point's state */ points = ras.outline.points; limit = points + last; v_start.x = SCALED( points[first].x ); v_start.y = SCALED( points[first].y ); v_last.x = SCALED( points[last].x ); v_last.y = SCALED( points[last].y ); if ( flipped ) { SWAP_( v_start.x, v_start.y ); SWAP_( v_last.x, v_last.y ); } v_control = v_start; point = points + first; tags = ras.outline.tags + first; tag = FT_CURVE_TAG( tags[0] ); /* A contour cannot start with a cubic control point! */ if ( tag == FT_Curve_Tag_Cubic ) goto Invalid_Outline; /* check first point to determine origin */ if ( tag == FT_Curve_Tag_Conic ) { /* first point is conic control. Yes, this happens. */ if ( FT_CURVE_TAG( ras.outline.tags[last] ) == FT_Curve_Tag_On ) { /* start at last point if it is on the curve */ v_start = v_last; limit--; } else { /* if both first and last points are conic, */ /* start at their middle and record its position */ /* for closure */ v_start.x = ( v_start.x + v_last.x ) / 2; v_start.y = ( v_start.y + v_last.y ) / 2; v_last = v_start; } point--; tags--; } ras.lastX = v_start.x; ras.lastY = v_start.y; while ( point < limit ) { point++; tags++; tag = FT_CURVE_TAG( tags[0] ); switch ( tag ) { case FT_Curve_Tag_On: /* emit a single line_to */ { Long x, y; x = SCALED( point->x ); y = SCALED( point->y ); if ( flipped ) SWAP_( x, y ); if ( Line_To( RAS_VARS x, y ) ) goto Fail; continue; } case FT_Curve_Tag_Conic: /* consume conic arcs */ v_control.x = SCALED( point[0].x ); v_control.y = SCALED( point[0].y ); if ( flipped ) SWAP_( v_control.x, v_control.y ); Do_Conic: if ( point < limit ) { FT_Vector v_middle; Long x, y; point++; tags++; tag = FT_CURVE_TAG( tags[0] ); x = SCALED( point[0].x ); y = SCALED( point[0].y ); if ( flipped ) SWAP_( x, y ); if ( tag == FT_Curve_Tag_On ) { if ( Conic_To( RAS_VARS v_control.x, v_control.y, x, y ) ) goto Fail; continue; } if ( tag != FT_Curve_Tag_Conic ) goto Invalid_Outline; v_middle.x = ( v_control.x + x ) / 2; v_middle.y = ( v_control.y + y ) / 2; if ( Conic_To( RAS_VARS v_control.x, v_control.y, v_middle.x, v_middle.y ) ) goto Fail; v_control.x = x; v_control.y = y; goto Do_Conic; } if ( Conic_To( RAS_VARS v_control.x, v_control.y, v_start.x, v_start.y ) ) goto Fail; goto Close; default: /* FT_Curve_Tag_Cubic */ { Long x1, y1, x2, y2, x3, y3; if ( point + 1 > limit || FT_CURVE_TAG( tags[1] ) != FT_Curve_Tag_Cubic ) goto Invalid_Outline; point += 2; tags += 2; x1 = SCALED( point[-2].x ); y1 = SCALED( point[-2].y ); x2 = SCALED( point[-1].x ); y2 = SCALED( point[-1].y ); x3 = SCALED( point[ 0].x ); y3 = SCALED( point[ 0].y ); if ( flipped ) { SWAP_( x1, y1 ); SWAP_( x2, y2 ); SWAP_( x3, y3 ); } if ( point <= limit ) { if ( Cubic_To( RAS_VARS x1, y1, x2, y2, x3, y3 ) ) goto Fail; continue; } if ( Cubic_To( RAS_VARS x1, y1, x2, y2, v_start.x, v_start.y ) ) goto Fail; goto Close; } } } /* close the contour with a line segment */ if ( Line_To( RAS_VARS v_start.x, v_start.y ) ) goto Fail; Close: return SUCCESS; Invalid_Outline: ras.error = Raster_Err_Invalid; Fail: return FAILURE; } /*************************************************************************/ /* */ /* <Function> */ /* Convert_Glyph */ /* */ /* <Description> */ /* Converts a glyph into a series of segments and arcs and makes a */ /* profiles list with them. */ /* */ /* <Input>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -