📄 ftgrays.c
字号:
/* the state during the decomposition. */ /* */ /* <Return> */ /* Error code. 0 means sucess. */ /* */ static int FT_Outline_Decompose( FT_Outline* outline, const FT_Outline_Funcs* interface, void* user ) {#undef SCALED#define SCALED( x ) ( ( (x) << shift ) - delta ) FT_Vector v_last; FT_Vector v_control; FT_Vector v_start; FT_Vector* point; FT_Vector* limit; char* tags; int n; /* index of contour in outline */ int first; /* index of first point in contour */ int error; char tag; /* current point's state */ int shift = interface->shift; FT_Pos delta = interface->delta; first = 0; for ( n = 0; n < outline->n_contours; n++ ) { int last; /* index of last point in contour */ last = outline->contours[n]; limit = outline->points + last; v_start = outline->points[first]; v_last = outline->points[last]; v_start.x = SCALED( v_start.x ); v_start.y = SCALED( v_start.y ); v_last.x = SCALED( v_last.x ); v_last.y = SCALED( v_last.y ); v_control = v_start; point = outline->points + first; tags = 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( 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--; } error = interface->move_to( &v_start, user ); if ( error ) goto Exit; while ( point < limit ) { point++; tags++; tag = FT_CURVE_TAG( tags[0] ); switch ( tag ) { case FT_Curve_Tag_On: /* emit a single line_to */ { FT_Vector vec; vec.x = SCALED( point->x ); vec.y = SCALED( point->y ); error = interface->line_to( &vec, user ); if ( error ) goto Exit; continue; } case FT_Curve_Tag_Conic: /* consume conic arcs */ { v_control.x = SCALED( point->x ); v_control.y = SCALED( point->y ); Do_Conic: if ( point < limit ) { FT_Vector vec; FT_Vector v_middle; point++; tags++; tag = FT_CURVE_TAG( tags[0] ); vec.x = SCALED( point->x ); vec.y = SCALED( point->y ); if ( tag == FT_Curve_Tag_On ) { error = interface->conic_to( &v_control, &vec, user ); if ( error ) goto Exit; continue; } if ( tag != FT_Curve_Tag_Conic ) goto Invalid_Outline; v_middle.x = ( v_control.x + vec.x ) / 2; v_middle.y = ( v_control.y + vec.y ) / 2; error = interface->conic_to( &v_control, &v_middle, user ); if ( error ) goto Exit; v_control = vec; goto Do_Conic; } error = interface->conic_to( &v_control, &v_start, user ); goto Close; } default: /* FT_Curve_Tag_Cubic */ { FT_Vector vec1, vec2; if ( point + 1 > limit || FT_CURVE_TAG( tags[1] ) != FT_Curve_Tag_Cubic ) goto Invalid_Outline; point += 2; tags += 2; vec1.x = SCALED( point[-2].x ); vec1.y = SCALED( point[-2].y ); vec2.x = SCALED( point[-1].x ); vec2.y = SCALED( point[-1].y ); if ( point <= limit ) { FT_Vector vec; vec.x = SCALED( point->x ); vec.y = SCALED( point->y ); error = interface->cubic_to( &vec1, &vec2, &vec, user ); if ( error ) goto Exit; continue; } error = interface->cubic_to( &vec1, &vec2, &v_start, user ); goto Close; } } } /* close the contour with a line segment */ error = interface->line_to( &v_start, user ); Close: if ( error ) goto Exit; first = last + 1; } return 0; Exit: return error; Invalid_Outline: return ErrRaster_Invalid_Outline; }#endif /* _STANDALONE_ */ typedef struct TBand_ { FT_Pos min, max; } TBand; static int grays_convert_glyph( RAS_ARG_ FT_Outline* outline ) { static const FT_Outline_Funcs interface = { (FT_Outline_MoveTo_Func) Move_To, (FT_Outline_LineTo_Func) Line_To, (FT_Outline_ConicTo_Func)Conic_To, (FT_Outline_CubicTo_Func)Cubic_To, 0, 0 }; TBand bands[40], *band; int n, num_bands; TPos min, max, max_y; /* Set up state in the raster object */ compute_cbox( RAS_VAR_ outline ); /* clip to target bitmap, exit if nothing to do */ if ( ras.max_ex <= 0 || ras.min_ex >= ras.target.width || ras.max_ey <= 0 || ras.min_ey >= ras.target.rows ) return 0; if ( ras.min_ex < 0 ) ras.min_ex = 0; if ( ras.min_ey < 0 ) ras.min_ey = 0; if ( ras.max_ex > ras.target.width ) ras.max_ex = ras.target.width; if ( ras.max_ey > ras.target.rows ) ras.max_ey = ras.target.rows; /* simple heuristic used to speed-up the bezier decomposition -- see */ /* the code in render_conic() and render_cubic() for more details */ ras.conic_level = 32; ras.cubic_level = 16; { int level = 0; if ( ras.max_ex > 24 || ras.max_ey > 24 ) level++; if ( ras.max_ex > 120 || ras.max_ey > 120 ) level++; ras.conic_level <<= level; ras.cubic_level <<= level; } /* setup vertical bands */ num_bands = ( ras.max_ey - ras.min_ey ) / ras.band_size; if ( num_bands == 0 ) num_bands = 1; if ( num_bands >= 39 ) num_bands = 39; ras.band_shoot = 0; min = ras.min_ey; max_y = ras.max_ey; for ( n = 0; n < num_bands; n++, min = max ) { max = min + ras.band_size; if ( n == num_bands - 1 || max > max_y ) max = max_y; bands[0].min = min; bands[0].max = max; band = bands; while ( band >= bands ) { FT_Pos bottom, top, middle; int error; ras.num_cells = 0; ras.invalid = 1; ras.min_ey = band->min; ras.max_ey = band->max; error = FT_Outline_Decompose( outline, &interface, &ras ) || record_cell( RAS_VAR ); if ( !error ) {#ifdef SHELL_SORT shell_sort( ras.cells, ras.num_cells );#else quick_sort( ras.cells, ras.num_cells );#endif#ifdef DEBUG_GRAYS check_sort( ras.cells, ras.num_cells ); dump_cells( RAS_VAR );#endif grays_sweep( RAS_VAR_ &ras.target ); band--; continue; } /* render pool overflow, we will reduce the render band by half */ bottom = band->min; top = band->max; middle = bottom + ( ( top - bottom ) >> 1 ); /* waoow! This is too complex for a single scanline, something */ /* must be really rotten here! */ if ( middle == bottom ) {#ifdef DEBUG_GRAYS fprintf( stderr, "Rotten glyph!\n" );#endif return 1; } if ( bottom-top >= ras.band_size ) ras.band_shoot++; band[1].min = bottom; band[1].max = middle; band[0].min = middle; band[0].max = top; band++; } } if ( ras.band_shoot > 8 && ras.band_size > 16 ) ras.band_size = ras.band_size / 2; return 0; } extern int grays_raster_render( PRaster raster, FT_Raster_Params* params ) { FT_Outline* outline = (FT_Outline*)params->source; FT_Bitmap* target_map = params->target; if ( !raster || !raster->cells || !raster->max_cells ) return -1; /* return immediately if the outline is empty */ if ( outline->n_points == 0 || outline->n_contours <= 0 ) return 0; if ( !outline || !outline->contours || !outline->points ) return ErrRaster_Invalid_Outline; if ( outline->n_points != outline->contours[outline->n_contours - 1] + 1 ) return ErrRaster_Invalid_Outline; /* if direct mode is not set, we must have a target bitmap */ if ( ( params->flags & ft_raster_flag_direct ) == 0 && ( !target_map || !target_map->buffer ) ) return -1; /* this version does not support monochrome rendering */ if ( !( params->flags & ft_raster_flag_aa ) ) return ErrRaster_Invalid_Mode; ras.outline = *outline; ras.num_cells = 0; ras.invalid = 1; if ( target_map ) ras.target = *target_map; ras.render_span = (FT_Raster_Span_Func)grays_render_span; ras.render_span_data = &ras; if ( params->flags & ft_raster_flag_direct ) { ras.render_span = (FT_Raster_Span_Func)params->gray_spans; ras.render_span_data = params->user; } return grays_convert_glyph( (PRaster)raster, outline ); } /**** RASTER OBJECT CREATION: In standalone mode, we simply use *****/ /**** a static object. *****/#ifdef _STANDALONE_ static int grays_raster_new( void* memory, FT_Raster* araster ) { static TRaster the_raster; FT_UNUSED( memory ); *araster = (FT_Raster)&the_raster; memset( &the_raster, 0, sizeof ( the_raster ) ); return 0; } static void grays_raster_done( FT_Raster raster ) { /* nothing */ FT_UNUSED( raster ); }#else /* _STANDALONE_ */ static int grays_raster_new( FT_Memory memory, FT_Raster* araster ) { FT_Error error; PRaster raster; *araster = 0; if ( !ALLOC( raster, sizeof ( TRaster ) ) ) { raster->memory = memory; *araster = (FT_Raster)raster; } return error; } static void grays_raster_done( FT_Raster raster ) { FT_Memory memory = (FT_Memory)((PRaster)raster)->memory; FREE( raster ); }#endif /* _STANDALONE_ */ static void grays_raster_reset( FT_Raster raster, const char* pool_base, long pool_size ) { PRaster rast = (PRaster)raster; if ( raster && pool_base && pool_size >= 4096 ) init_cells( rast, (char*)pool_base, pool_size ); rast->band_size = ( pool_size / sizeof ( TCell ) ) / 8; } const FT_Raster_Funcs ft_grays_raster = { ft_glyph_format_outline, (FT_Raster_New_Func) grays_raster_new, (FT_Raster_Reset_Func) grays_raster_reset, (FT_Raster_Set_Mode_Func)0, (FT_Raster_Render_Func) grays_raster_render, (FT_Raster_Done_Func) grays_raster_done };/* END */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -