📄 qgrayraster.c
字号:
int first; /* index of first point in contour */ int error; char tag; /* current point's state */#if 0 int shift = func_interface->shift; TPos delta = func_interface->delta;#endif 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 = QT_FT_CURVE_TAG( tags[0] ); /* A contour cannot start with a cubic control point! */ if ( tag == QT_FT_CURVE_TAG_CUBIC ) goto Invalid_Outline; /* check first point to determine origin */ if ( tag == QT_FT_CURVE_TAG_CONIC ) { /* first point is conic control. Yes, this happens. */ if ( QT_FT_CURVE_TAG( outline->tags[last] ) == QT_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 = func_interface->move_to( &v_start, user ); if ( error ) goto Exit; while ( point < limit ) { point++; tags++; tag = QT_FT_CURVE_TAG( tags[0] ); switch ( tag ) { case QT_FT_CURVE_TAG_ON: /* emit a single line_to */ { QT_FT_Vector vec; vec.x = SCALED( point->x ); vec.y = SCALED( point->y ); error = func_interface->line_to( &vec, user ); if ( error ) goto Exit; continue; } case QT_FT_CURVE_TAG_CONIC: /* consume conic arcs */ { v_control.x = SCALED( point->x ); v_control.y = SCALED( point->y ); Do_Conic: if ( point < limit ) { QT_FT_Vector vec; QT_FT_Vector v_middle; point++; tags++; tag = QT_FT_CURVE_TAG( tags[0] ); vec.x = SCALED( point->x ); vec.y = SCALED( point->y ); if ( tag == QT_FT_CURVE_TAG_ON ) { error = func_interface->conic_to( &v_control, &vec, user ); if ( error ) goto Exit; continue; } if ( tag != QT_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 = func_interface->conic_to( &v_control, &v_middle, user ); if ( error ) goto Exit; v_control = vec; goto Do_Conic; } error = func_interface->conic_to( &v_control, &v_start, user ); goto Close; } default: /* QT_FT_CURVE_TAG_CUBIC */ { QT_FT_Vector vec1, vec2; if ( point + 1 > limit || QT_FT_CURVE_TAG( tags[1] ) != QT_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 ) { QT_FT_Vector vec; vec.x = SCALED( point->x ); vec.y = SCALED( point->y ); error = func_interface->cubic_to( &vec1, &vec2, &vec, user ); if ( error ) goto Exit; continue; } error = func_interface->cubic_to( &vec1, &vec2, &v_start, user ); goto Close; } } } /* close the contour with a line segment */ error = func_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; } typedef struct TBand_ { TPos min, max; } TBand; static int gray_convert_glyph_inner( RAS_ARG ) { static const QT_FT_Outline_Funcs func_interface = { (QT_FT_Outline_MoveTo_Func) gray_move_to, (QT_FT_Outline_LineTo_Func) gray_line_to, (QT_FT_Outline_ConicTo_Func)gray_conic_to, (QT_FT_Outline_CubicTo_Func)gray_cubic_to, 0, 0 }; volatile int error = 0; if ( qt_ft_setjmp( ras.jump_buffer ) == 0 ) { error = QT_FT_Outline_Decompose( &ras.outline, &func_interface, &ras ); gray_record_cell( RAS_VAR ); } else { error = ErrRaster_MemoryOverflow; } return error; } static int gray_convert_glyph( RAS_ARG ) { TBand bands[40]; TBand* volatile band; int volatile n, num_bands; TPos volatile min, max, max_y; QT_FT_BBox* clip; ras.num_gray_spans = 0; /* Set up state in the raster object */ gray_compute_cbox( RAS_VAR ); /* clip to target bitmap, exit if nothing to do */ clip = &ras.clip_box; if ( ras.max_ex <= clip->xMin || ras.min_ex >= clip->xMax || ras.max_ey <= clip->yMin || ras.min_ey >= clip->yMax ) return 0; if ( ras.min_ex < clip->xMin ) ras.min_ex = clip->xMin; if ( ras.min_ey < clip->yMin ) ras.min_ey = clip->yMin; if ( ras.max_ex > clip->xMax ) ras.max_ex = clip->xMax; if ( ras.max_ey > clip->yMax ) ras.max_ey = clip->yMax; /* simple heuristic used to speed-up the bezier decomposition -- see */ /* the code in gray_render_conic() and gray_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 = (int)( ( 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 ) { TPos bottom, top, middle; int error; ras.num_cells = 0; ras.invalid = 1; ras.min_ey = band->min; ras.max_ey = band->max;#if 1 error = gray_convert_glyph_inner( RAS_VAR );#else error = QT_FT_Outline_Decompose( outline, &func_interface, &ras ) || gray_record_cell( RAS_VAR );#endif if ( !error ) {#ifdef SHELL_SORT gray_shell_sort( ras.cells, ras.num_cells );#else gray_quick_sort( ras.cells, ras.num_cells );#endif#ifdef DEBUG_GRAYS gray_check_sort( ras.cells, ras.num_cells ); gray_dump_cells( RAS_VAR );#endif gray_sweep( RAS_VAR_ &ras.target ); band--; continue; } else if ( error != ErrRaster_MemoryOverflow ) return 1; /* 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 /* == Raster_Err_OutOfMemory in qblackraster.c */ return -6; } 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.render_span && ras.num_gray_spans > 0 ) ras.render_span( ras.num_gray_spans, ras.gray_spans, ras.render_span_data ); if ( ras.band_shoot > 8 && ras.band_size > 16 ) ras.band_size = ras.band_size / 2; return 0; } static int gray_raster_render( PRaster raster, QT_FT_Raster_Params* params ) { QT_FT_Outline* outline = (QT_FT_Outline*)params->source; QT_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 & QT_FT_RASTER_FLAG_DIRECT ) == 0 && ( !target_map || !target_map->buffer ) ) return -1; /* this version does not support monochrome rendering */ if ( !( params->flags & QT_FT_RASTER_FLAG_AA ) ) return ErrRaster_Invalid_Mode; /* compute clipping box */ if ( ( params->flags & QT_FT_RASTER_FLAG_DIRECT ) == 0 ) { /* compute clip box from target pixmap */ ras.clip_box.xMin = 0; ras.clip_box.yMin = 0; ras.clip_box.xMax = target_map->width; ras.clip_box.yMax = target_map->rows; } else if ( params->flags & QT_FT_RASTER_FLAG_CLIP ) { ras.clip_box = params->clip_box; } else { ras.clip_box.xMin = -32768L; ras.clip_box.yMin = -32768L; ras.clip_box.xMax = 32767L; ras.clip_box.yMax = 32767L; } ras.outline = *outline; ras.num_cells = 0; ras.invalid = 1; if ( target_map ) ras.target = *target_map; ras.render_span = (QT_FT_Raster_Span_Func)gray_render_span; ras.render_span_data = &ras; if ( params->flags & QT_FT_RASTER_FLAG_DIRECT ) { ras.render_span = (QT_FT_Raster_Span_Func)params->gray_spans; ras.render_span_data = params->user; } return gray_convert_glyph( (PRaster)raster ); } /**** RASTER OBJECT CREATION: In standalone mode, we simply use *****/ /**** a static object. *****/#ifdef GRAYS_USE_GAMMA /* initialize the "gamma" table. Yes, this is really a crummy function */ /* but the results look pretty good for something that simple. */ /* */#define M_MAX 255#define M_X 128#define M_Y 192 static void grays_init_gamma( PRaster raster ) { unsigned int x, a; for ( x = 0; x < 256; x++ ) { if ( x <= M_X ) a = ( x * M_Y + M_X / 2) / M_X; else a = M_Y + ( ( x - M_X ) * ( M_MAX - M_Y ) + ( M_MAX - M_X ) / 2 ) / ( M_MAX - M_X ); raster->gamma[x] = (unsigned char)a; } }#endif /* GRAYS_USE_GAMMA */ static int gray_raster_new( void* memory, QT_FT_Raster* araster ) { if (memory) fprintf(stderr, "gray_raster_new(), memory ignored"); memory = malloc(sizeof(TRaster)); QT_FT_MEM_ZERO(memory, sizeof(TRaster)); *araster = (QT_FT_Raster) memory;#ifdef GRAYS_USE_GAMMA grays_init_gamma( (PRaster)*araster );#endif return 0; } static void gray_raster_done( QT_FT_Raster raster ) { free(raster); } static void gray_raster_reset( QT_FT_Raster raster, const char* pool_base, long pool_size ) { PRaster rast = (PRaster)raster; if ( raster && pool_base && pool_size >= 4096 ) gray_init_cells( rast, (char*)pool_base, pool_size ); rast->band_size = (int)( ( pool_size / sizeof ( TCell ) ) / 8 ); } const QT_FT_Raster_Funcs qt_ft_grays_raster = { QT_FT_GLYPH_FORMAT_OUTLINE, (QT_FT_Raster_New_Func) gray_raster_new, (QT_FT_Raster_Reset_Func) gray_raster_reset, (QT_FT_Raster_Set_Mode_Func)0, (QT_FT_Raster_Render_Func) gray_raster_render, (QT_FT_Raster_Done_Func) gray_raster_done };/* END */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -