[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.
This commit is contained in:
Alexei Podtelezhnikov 2020-07-03 22:29:34 -04:00
parent 19d39f43d2
commit 3bb512bc9f
3 changed files with 121 additions and 6 deletions

View File

@ -1,3 +1,18 @@
2020-07-03 Alexei Podtelezhnikov <apodtele@gmail.com>
[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 <apodtele@gmail.com>
[smooth] Use direct rendering mode in Harmony.

View File

@ -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

View File

@ -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 = &target;
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, &params );
/* 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, &params );
error = render->raster_render( render->raster, &params );
}
}
else
{