diff --git a/ChangeLog b/ChangeLog index f5045de5a..a28694a69 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2020-07-03 Alexei Podtelezhnikov + + [smooth] Introduce direct oversampling for overlaps. + + This implements oversampling to metigate artifacts in pixels partially + covered by overlapping contours. It turns out that the 4x4 + oversampling is sufficient but, at least, quadruples the rendering + time. The outline has to set FT_OUTLINE_OVERLAP to use this method. + + * include/freetype/ftimage.h (FT_OUTLINE_OVERLAP): New flag. + * src/smooth/ftsmooth.c (ft_smooth_render): Check it to... + (ft_smooth_raster_overlap): ... inflate outline and set up direct + rendering for oversampling with... + (ft_smooth_overlap_spans): ... new span function that integrates them. + 2020-07-03 Alexei Podtelezhnikov [smooth] Use direct rendering mode in Harmony. diff --git a/include/freetype/ftimage.h b/include/freetype/ftimage.h index 9fecd1fbc..29b907a75 100644 --- a/include/freetype/ftimage.h +++ b/include/freetype/ftimage.h @@ -400,6 +400,13 @@ FT_BEGIN_HEADER * if @FT_OUTLINE_IGNORE_DROPOUTS is set. See below for more * information. * + * FT_OUTLINE_OVERLAP :: + * This flag indicates that this outline contains overlapping contrours + * and the anti-aliased renderer should perform oversampling to + * metigate possible artifacts. This flag should _not_ be set for + * well designed glyphs without overlaps because it quadruples the + * rendering time. + * * FT_OUTLINE_HIGH_PRECISION :: * This flag indicates that the scan-line converter should try to * convert this outline to bitmaps with the highest possible quality. @@ -432,6 +439,7 @@ FT_BEGIN_HEADER #define FT_OUTLINE_SMART_DROPOUTS 0x10 #define FT_OUTLINE_INCLUDE_STUBS 0x20 +#define FT_OUTLINE_OVERLAP 0x80 #define FT_OUTLINE_HIGH_PRECISION 0x100 #define FT_OUTLINE_SINGLE_PASS 0x200 diff --git a/src/smooth/ftsmooth.c b/src/smooth/ftsmooth.c index 1e0d0a3e3..b32629205 100644 --- a/src/smooth/ftsmooth.c +++ b/src/smooth/ftsmooth.c @@ -333,7 +333,94 @@ #endif /* FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ - /* convert a slot's glyph image into a bitmap */ +/* Oversampling scale to be used in rendering overlaps */ +#define SCALE ( 1 << 2 ) + + /* This function averages inflated spans in direct rendering mode */ + static void + ft_smooth_overlap_spans( int y, + int count, + const FT_Span* spans, + TOrigin* target ) + { + unsigned char* dst = target->origin - ( y / SCALE ) * target->pitch; + unsigned short x; + unsigned int cover, sum; + + + /* When accumulating the oversampled spans we need to assure that */ + /* fully covered pixels are equal to 255 and do not overflow. */ + /* It is important that the SCALE is a power of 2, each subpixel */ + /* cover can also reach a power of 2 after rounding, and the total */ + /* is clamped to 255 when it adds up to 256. */ + for ( ; count--; spans++ ) + { + cover = ( spans->coverage + SCALE * SCALE / 2 ) / ( SCALE * SCALE ); + for ( x = 0; x < spans->len; x++ ) + { + sum = dst[ ( spans->x + x ) / SCALE ] + cover; + dst[ ( spans->x + x ) / SCALE ] = sum - ( sum >> 8 ); + } + } + } + + + static FT_Error + ft_smooth_raster_overlap( FT_Renderer render, + FT_Outline* outline, + FT_Bitmap* bitmap ) + { + FT_Error error = FT_Err_Ok; + FT_Vector* points = outline->points; + FT_Vector* points_end = FT_OFFSET( points, outline->n_points ); + FT_Vector* vec; + + FT_Raster_Params params; + TOrigin target; + + + /* Set up direct rendering to average oversampled spans. */ + params.target = bitmap; + params.source = outline; + params.flags = FT_RASTER_FLAG_AA | FT_RASTER_FLAG_DIRECT; + params.gray_spans = (FT_SpanFunc)ft_smooth_overlap_spans; + params.user = ⌖ + + params.clip_box.xMin = 0; + params.clip_box.yMin = 0; + params.clip_box.xMax = bitmap->width * SCALE; + params.clip_box.yMax = bitmap->rows * SCALE; + + if ( bitmap->pitch < 0 ) + target.origin = bitmap->buffer; + else + target.origin = bitmap->buffer + + ( bitmap->rows - 1 ) * (unsigned int)bitmap->pitch; + + target.pitch = bitmap->pitch; + + /* inflate outline */ + for ( vec = points; vec < points_end; vec++ ) + { + vec->x *= SCALE; + vec->y *= SCALE; + } + + /* render outline into the bitmap */ + error = render->raster_render( render->raster, ¶ms ); + + /* deflate outline */ + for ( vec = points; vec < points_end; vec++ ) + { + vec->x /= SCALE; + vec->y /= SCALE; + } + + return error; + } + +#undef SCALE + static FT_Error ft_smooth_render( FT_Renderer render, FT_GlyphSlot slot, @@ -407,14 +494,19 @@ if ( mode == FT_RENDER_MODE_NORMAL || mode == FT_RENDER_MODE_LIGHT ) { - FT_Raster_Params params; + if ( outline->flags & FT_OUTLINE_OVERLAP ) + error = ft_smooth_raster_overlap( render, outline, bitmap ); + else + { + FT_Raster_Params params; - params.target = bitmap; - params.source = outline; - params.flags = FT_RASTER_FLAG_AA; + params.target = bitmap; + params.source = outline; + params.flags = FT_RASTER_FLAG_AA; - error = render->raster_render( render->raster, ¶ms ); + error = render->raster_render( render->raster, ¶ms ); + } } else {