Bitmap metrics presetting [1/2].

This mainly just extracts the code for presetting the bitmap metrics
from the monochrome, grayscale, and LCD renderers into a separate
function.

* src/base/ftobjs.c (ft_glyphslot_preset_bitmap): New function that
calculates prespective bitmap metrics for the given rendering mode.
* include/freetype/internal/ftobjs.h (ft_glyphslot_preset_bitmap):
Declare it.

* src/base/ftlcdfil.c (ft_lcd_padding): New helper function that adds
padding to CBox taking into account pecularities of LCD rendering.
* include/freetype/ftlcdfil.h (ft_lcd_padding): Declare it.

* src/raster/ftrend1.c (ft_raster1_render): Reworked to use
`ft_glyphslot_preset_bitmap'.
* src/smooth/ftsmooth.c (ft_smooth_render_generic): Ditto.
(ft_smooth_render_lcd, ft_smooth_render_lcd): The pixel_mode setting
is moved to `ft_glyphslot_preset_bitmap'.
This commit is contained in:
Alexei Podtelezhnikov 2017-09-28 00:20:50 -04:00
parent dd40d10e81
commit 61d1818b5e
7 changed files with 294 additions and 229 deletions

View File

@ -1,3 +1,26 @@
2017-09-28 Alexei Podtelezhnikov <apodtele@gmail.com>
Bitmap metrics presetting [1/2].
This mainly just extracts the code for presetting the bitmap metrics
from the monochrome, grayscale, and LCD renderers into a separate
function.
* src/base/ftobjs.c (ft_glyphslot_preset_bitmap): New function that
calculates prespective bitmap metrics for the given rendering mode.
* include/freetype/internal/ftobjs.h (ft_glyphslot_preset_bitmap):
Declare it.
* src/base/ftlcdfil.c (ft_lcd_padding): New helper function that adds
padding to CBox taking into account pecularities of LCD rendering.
* include/freetype/ftlcdfil.h (ft_lcd_padding): Declare it.
* src/raster/ftrend1.c (ft_raster1_render): Reworked to use
`ft_glyphslot_preset_bitmap'.
* src/smooth/ftsmooth.c (ft_smooth_render_generic): Ditto.
(ft_smooth_render_lcd, ft_smooth_render_lcd): The pixel_mode setting
is moved to `ft_glyphslot_preset_bitmap'.
2017-09-28 Ewald Hew <ewaldhew@gmail.com>
[psaux] Fix compiler warning.

View File

@ -316,6 +316,14 @@ FT_BEGIN_HEADER
typedef FT_Byte FT_LcdFiveTapFilter[FT_LCD_FILTER_FIVE_TAPS];
FT_BASE( void )
ft_lcd_padding( FT_Pos* Min,
FT_Pos* Max,
FT_GlyphSlot slot );
#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
typedef void (*FT_Bitmap_LcdFilterFunc)( FT_Bitmap* bitmap,
FT_Render_Mode render_mode,
FT_Byte* weights );
@ -327,6 +335,8 @@ FT_BEGIN_HEADER
FT_Render_Mode mode,
FT_LcdFiveTapFilter weights );
#endif /* FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
/* */

View File

@ -708,6 +708,12 @@ FT_BEGIN_HEADER
ft_glyphslot_free_bitmap( FT_GlyphSlot slot );
/* Preset bitmap metrics of an outline glyphslot prior to rendering. */
FT_BASE( void )
ft_glyphslot_preset_bitmap( FT_GlyphSlot slot,
FT_Render_Mode mode,
const FT_Vector* origin );
/* Allocate a new bitmap buffer in a glyph slot. */
FT_BASE( FT_Error )
ft_glyphslot_alloc_bitmap( FT_GlyphSlot slot,

View File

@ -31,6 +31,39 @@
#define FT_SHIFTCLAMP( x ) ( x >>= 8, (FT_Byte)( x > 255 ? 255 : x ) )
/* add padding according to filter weights */
FT_BASE_DEF (void)
ft_lcd_padding( FT_Pos* Min,
FT_Pos* Max,
FT_GlyphSlot slot )
{
FT_Byte* lcd_weights;
FT_Bitmap_LcdFilterFunc lcd_filter_func;
/* Per-face LCD filtering takes priority if set up. */
if ( slot->face && slot->face->internal->lcd_filter_func )
{
lcd_weights = slot->face->internal->lcd_weights;
lcd_filter_func = slot->face->internal->lcd_filter_func;
}
else
{
lcd_weights = slot->library->lcd_weights;
lcd_filter_func = slot->library->lcd_filter_func;
}
if ( lcd_filter_func == ft_lcd_filter_fir )
{
*Min -= lcd_weights[0] ? 43 :
lcd_weights[1] ? 22 : 0;
*Max += lcd_weights[4] ? 43 :
lcd_weights[3] ? 22 : 0;
}
}
/* FIR filter used by the default and light filters */
FT_BASE_DEF( void )
ft_lcd_filter_fir( FT_Bitmap* bitmap,
@ -310,14 +343,16 @@
#else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
FT_BASE( void )
ft_lcd_filter_fir( FT_Bitmap* bitmap,
FT_Render_Mode mode,
FT_LcdFiveTapFilter weights )
/* add padding according to accommodate outline shifts */
FT_BASE_DEF (void)
ft_lcd_padding( FT_Pos* Min,
FT_Pos* Max,
FT_GlyphSlot slot )
{
FT_UNUSED( bitmap );
FT_UNUSED( mode );
FT_UNUSED( weights );
FT_UNUSED( slot );
*Min -= 21;
*Max += 21;
}

View File

@ -327,6 +327,135 @@
}
FT_BASE_DEF( void )
ft_glyphslot_preset_bitmap( FT_GlyphSlot slot,
FT_Render_Mode mode,
const FT_Vector* origin )
{
FT_Outline* outline = &slot->outline;
FT_Bitmap* bitmap = &slot->bitmap;
FT_Pixel_Mode pixel_mode;
FT_BBox cbox;
FT_Pos x_shift = 0;
FT_Pos y_shift = 0;
FT_Pos x_left, y_top;
FT_Pos width, height, pitch;
if ( slot->internal && ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) )
return;
if ( origin )
{
x_shift = origin->x;
y_shift = origin->y;
}
/* compute the control box, and grid fit it */
/* taking into account the origin shift */
FT_Outline_Get_CBox( outline, &cbox );
cbox.xMin += x_shift;
cbox.yMin += y_shift;
cbox.xMax += x_shift;
cbox.yMax += y_shift;
switch ( mode )
{
case FT_RENDER_MODE_MONO:
pixel_mode = FT_PIXEL_MODE_MONO;
#if 1
/* undocumented but confirmed: bbox values get rounded */
/* unless the rounded box can collapse for a narrow glyph */
if ( cbox.xMax - cbox.xMin < 64 )
{
cbox.xMin = FT_PIX_FLOOR( cbox.xMin );
cbox.xMax = FT_PIX_CEIL( cbox.xMax );
}
else
{
cbox.xMin = FT_PIX_ROUND( cbox.xMin );
cbox.xMax = FT_PIX_ROUND( cbox.xMax );
}
if ( cbox.yMax - cbox.yMin < 64 )
{
cbox.yMin = FT_PIX_FLOOR( cbox.yMin );
cbox.yMax = FT_PIX_CEIL( cbox.yMax );
}
else
{
cbox.yMin = FT_PIX_ROUND( cbox.yMin );
cbox.yMax = FT_PIX_ROUND( cbox.yMax );
}
#else
cbox.xMin = FT_PIX_FLOOR( cbox.xMin );
cbox.yMin = FT_PIX_FLOOR( cbox.yMin );
cbox.xMax = FT_PIX_CEIL( cbox.xMax );
cbox.yMax = FT_PIX_CEIL( cbox.yMax );
#endif
break;
case FT_RENDER_MODE_LCD:
pixel_mode = FT_PIXEL_MODE_LCD;
ft_lcd_padding( &cbox.xMin, &cbox.xMax, slot );
goto Round;
case FT_RENDER_MODE_LCD_V:
pixel_mode = FT_PIXEL_MODE_LCD_V;
ft_lcd_padding( &cbox.yMin, &cbox.yMax, slot );
goto Round;
case FT_RENDER_MODE_NORMAL:
case FT_RENDER_MODE_LIGHT:
default:
pixel_mode = FT_PIXEL_MODE_GRAY;
Round:
cbox.xMin = FT_PIX_FLOOR( cbox.xMin );
cbox.yMin = FT_PIX_FLOOR( cbox.yMin );
cbox.xMax = FT_PIX_CEIL( cbox.xMax );
cbox.yMax = FT_PIX_CEIL( cbox.yMax );
}
x_shift -= cbox.xMin;
y_shift -= cbox.yMin;
x_left = cbox.xMin >> 6;
y_top = cbox.yMax >> 6;
width = (FT_ULong)( cbox.xMax - cbox.xMin ) >> 6;
height = (FT_ULong)( cbox.yMax - cbox.yMin ) >> 6;
switch ( pixel_mode )
{
case FT_PIXEL_MODE_MONO:
pitch = ( ( width + 15 ) >> 4 ) << 1;
break;
case FT_PIXEL_MODE_LCD:
width *= 3;
pitch = FT_PAD_CEIL( width, 4 );
break;
case FT_PIXEL_MODE_LCD_V:
height *= 3;
/* fall through */
case FT_PIXEL_MODE_GRAY:
default:
pitch = width;
}
slot->bitmap_left = (FT_Int)x_left;
slot->bitmap_top = (FT_Int)y_top;
bitmap->pixel_mode = pixel_mode;
bitmap->num_grays = 256;
bitmap->width = (unsigned int)width;
bitmap->rows = (unsigned int)height;
bitmap->pitch = pitch;
}
FT_BASE_DEF( void )
ft_glyphslot_set_bitmap( FT_GlyphSlot slot,
FT_Byte* buffer )

View File

@ -98,11 +98,11 @@
const FT_Vector* origin )
{
FT_Error error;
FT_Outline* outline;
FT_BBox cbox, cbox0;
FT_UInt width, height, pitch;
FT_Bitmap* bitmap;
FT_Memory memory;
FT_Outline* outline = &slot->outline;
FT_Bitmap* bitmap = &slot->bitmap;
FT_Memory memory = render->root.memory;
FT_Pos x_shift = 0;
FT_Pos y_shift = 0;
FT_Raster_Params params;
@ -121,60 +121,6 @@
return FT_THROW( Cannot_Render_Glyph );
}
outline = &slot->outline;
/* translate the outline to the new origin if needed */
if ( origin )
FT_Outline_Translate( outline, origin->x, origin->y );
/* compute the control box, and grid fit it */
FT_Outline_Get_CBox( outline, &cbox0 );
/* undocumented but confirmed: bbox values get rounded */
#if 1
cbox.xMin = FT_PIX_ROUND( cbox0.xMin );
cbox.yMin = FT_PIX_ROUND( cbox0.yMin );
cbox.xMax = FT_PIX_ROUND( cbox0.xMax );
cbox.yMax = FT_PIX_ROUND( cbox0.yMax );
#else
cbox.xMin = FT_PIX_FLOOR( cbox.xMin );
cbox.yMin = FT_PIX_FLOOR( cbox.yMin );
cbox.xMax = FT_PIX_CEIL( cbox.xMax );
cbox.yMax = FT_PIX_CEIL( cbox.yMax );
#endif
/* If either `width' or `height' round to 0, try */
/* explicitly rounding up/down. In the case of */
/* glyphs containing only one very narrow feature, */
/* this gives the drop-out compensation in the scan */
/* conversion code a chance to do its stuff. */
width = (FT_UInt)( ( cbox.xMax - cbox.xMin ) >> 6 );
if ( width == 0 )
{
cbox.xMin = FT_PIX_FLOOR( cbox0.xMin );
cbox.xMax = FT_PIX_CEIL( cbox0.xMax );
width = (FT_UInt)( ( cbox.xMax - cbox.xMin ) >> 6 );
}
height = (FT_UInt)( ( cbox.yMax - cbox.yMin ) >> 6 );
if ( height == 0 )
{
cbox.yMin = FT_PIX_FLOOR( cbox0.yMin );
cbox.yMax = FT_PIX_CEIL( cbox0.yMax );
height = (FT_UInt)( ( cbox.yMax - cbox.yMin ) >> 6 );
}
if ( width > FT_USHORT_MAX || height > FT_USHORT_MAX )
{
error = FT_THROW( Invalid_Argument );
goto Exit;
}
bitmap = &slot->bitmap;
memory = render->root.memory;
/* release old bitmap buffer */
if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
{
@ -182,20 +128,26 @@
slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
}
pitch = ( ( width + 15 ) >> 4 ) << 1;
bitmap->pixel_mode = FT_PIXEL_MODE_MONO;
ft_glyphslot_preset_bitmap( slot, mode, origin );
bitmap->width = width;
bitmap->rows = height;
bitmap->pitch = (int)pitch;
if ( FT_ALLOC_MULT( bitmap->buffer, height, pitch ) )
/* allocate new one */
if ( FT_ALLOC_MULT( bitmap->buffer, bitmap->rows, bitmap->pitch ) )
goto Exit;
slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
x_shift = -slot->bitmap_left * 64;
y_shift = ( bitmap->rows - slot->bitmap_top ) * 64;
if ( origin )
{
x_shift += origin->x;
y_shift += origin->y;
}
/* translate outline to render it into the bitmap */
FT_Outline_Translate( outline, -cbox.xMin, -cbox.yMin );
if ( x_shift || y_shift )
FT_Outline_Translate( outline, x_shift, y_shift );
/* set up parameters */
params.target = bitmap;
@ -204,17 +156,24 @@
/* render outline into the bitmap */
error = render->raster_render( render->raster, &params );
FT_Outline_Translate( outline, cbox.xMin, cbox.yMin );
if ( error )
goto Exit;
slot->format = FT_GLYPH_FORMAT_BITMAP;
slot->bitmap_left = (FT_Int)( cbox.xMin >> 6 );
slot->bitmap_top = (FT_Int)( cbox.yMax >> 6 );
/* everything is fine; the glyph is now officially a bitmap */
slot->format = FT_GLYPH_FORMAT_BITMAP;
error = FT_Err_Ok;
Exit:
if ( x_shift || y_shift )
FT_Outline_Translate( outline, -x_shift, -y_shift );
if ( slot->format != FT_GLYPH_FORMAT_BITMAP &&
slot->internal->flags & FT_GLYPH_OWN_BITMAP )
{
FT_FREE( bitmap->buffer );
slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
}
return error;
}

View File

@ -101,36 +101,13 @@
FT_Outline* outline = &slot->outline;
FT_Bitmap* bitmap = &slot->bitmap;
FT_Memory memory = render->root.memory;
FT_BBox cbox;
FT_Pos x_shift = 0;
FT_Pos y_shift = 0;
FT_Pos x_left, y_top;
FT_Pos width, height, pitch;
FT_Int hmul = ( mode == FT_RENDER_MODE_LCD );
FT_Int vmul = ( mode == FT_RENDER_MODE_LCD_V );
FT_Raster_Params params;
FT_Bool have_outline_shifted = FALSE;
FT_Bool have_buffer = FALSE;
#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
FT_Byte* lcd_weights;
FT_Bitmap_LcdFilterFunc lcd_filter_func;
/* Per-face LCD filtering takes priority if set up. */
if ( slot->face && slot->face->internal->lcd_filter_func )
{
lcd_weights = slot->face->internal->lcd_weights;
lcd_filter_func = slot->face->internal->lcd_filter_func;
}
else
{
lcd_weights = slot->library->lcd_weights;
lcd_filter_func = slot->library->lcd_filter_func;
}
#endif /* FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
/* check glyph image format */
if ( slot->format != render->glyph_format )
@ -146,100 +123,6 @@
goto Exit;
}
if ( origin )
{
x_shift = origin->x;
y_shift = origin->y;
}
/* compute the control box, and grid fit it */
/* taking into account the origin shift */
FT_Outline_Get_CBox( outline, &cbox );
#ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
/* add minimal padding for LCD rendering */
if ( hmul )
{
cbox.xMax += 21;
cbox.xMin -= 21;
}
if ( vmul )
{
cbox.yMax += 21;
cbox.yMin -= 21;
}
#else /* FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
/* add minimal padding for LCD filter depending on specific weights */
if ( lcd_filter_func == ft_lcd_filter_fir )
{
if ( hmul )
{
cbox.xMax += lcd_weights[4] ? 43
: lcd_weights[3] ? 22 : 0;
cbox.xMin -= lcd_weights[0] ? 43
: lcd_weights[1] ? 22 : 0;
}
if ( vmul )
{
cbox.yMax += lcd_weights[4] ? 43
: lcd_weights[3] ? 22 : 0;
cbox.yMin -= lcd_weights[0] ? 43
: lcd_weights[1] ? 22 : 0;
}
}
#endif /* FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
cbox.xMin = FT_PIX_FLOOR( cbox.xMin + x_shift );
cbox.yMin = FT_PIX_FLOOR( cbox.yMin + y_shift );
cbox.xMax = FT_PIX_CEIL( cbox.xMax + x_shift );
cbox.yMax = FT_PIX_CEIL( cbox.yMax + y_shift );
x_shift -= cbox.xMin;
y_shift -= cbox.yMin;
x_left = cbox.xMin >> 6;
y_top = cbox.yMax >> 6;
width = (FT_ULong)( cbox.xMax - cbox.xMin ) >> 6;
height = (FT_ULong)( cbox.yMax - cbox.yMin ) >> 6;
pitch = width;
if ( hmul )
{
width *= 3;
pitch = FT_PAD_CEIL( width, 4 );
}
if ( vmul )
height *= 3;
/*
* XXX: on 16bit system, we return an error for huge bitmap
* to prevent an overflow.
*/
if ( x_left > FT_INT_MAX || y_top > FT_INT_MAX ||
x_left < FT_INT_MIN || y_top < FT_INT_MIN )
{
error = FT_THROW( Invalid_Pixel_Size );
goto Exit;
}
/* Required check is (pitch * height < FT_ULONG_MAX), */
/* but we care realistic cases only. Always pitch <= width. */
if ( width > 0x7FFF || height > 0x7FFF )
{
FT_ERROR(( "ft_smooth_render_generic: glyph too large: %u x %u\n",
width, height ));
error = FT_THROW( Raster_Overflow );
goto Exit;
}
/* release old bitmap buffer */
if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
{
@ -247,30 +130,30 @@
slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
}
ft_glyphslot_preset_bitmap( slot, mode, origin );
/* allocate new one */
if ( FT_ALLOC( bitmap->buffer, (FT_ULong)( pitch * height ) ) )
if ( FT_ALLOC_MULT( bitmap->buffer, bitmap->rows, bitmap->pitch ) )
goto Exit;
else
have_buffer = TRUE;
slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
slot->format = FT_GLYPH_FORMAT_BITMAP;
slot->bitmap_left = (FT_Int)x_left;
slot->bitmap_top = (FT_Int)y_top;
x_shift = 64 * -slot->bitmap_left;
y_shift = 64 * -slot->bitmap_top;
if ( bitmap->pixel_mode == FT_PIXEL_MODE_LCD_V )
y_shift += 64 * bitmap->rows / 3;
else
y_shift += 64 * bitmap->rows;
bitmap->pixel_mode = FT_PIXEL_MODE_GRAY;
bitmap->num_grays = 256;
bitmap->width = (unsigned int)width;
bitmap->rows = (unsigned int)height;
bitmap->pitch = pitch;
if ( origin )
{
x_shift += origin->x;
y_shift += origin->y;
}
/* translate outline to render it into the bitmap */
if ( x_shift || y_shift )
{
FT_Outline_Translate( outline, x_shift, y_shift );
have_outline_shifted = TRUE;
}
/* set up parameters */
params.target = bitmap;
@ -317,8 +200,28 @@
if ( error )
goto Exit;
if ( lcd_filter_func )
lcd_filter_func( bitmap, mode, lcd_weights );
/* finally apply filtering */
if ( hmul || vmul )
{
FT_Byte* lcd_weights;
FT_Bitmap_LcdFilterFunc lcd_filter_func;
/* Per-face LCD filtering takes priority if set up. */
if ( slot->face && slot->face->internal->lcd_filter_func )
{
lcd_weights = slot->face->internal->lcd_weights;
lcd_filter_func = slot->face->internal->lcd_filter_func;
}
else
{
lcd_weights = slot->library->lcd_weights;
lcd_filter_func = slot->library->lcd_filter_func;
}
if ( lcd_filter_func )
lcd_filter_func( bitmap, mode, lcd_weights );
}
#else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
@ -328,6 +231,10 @@
FT_Byte* temp;
FT_Int i, j;
unsigned int height = bitmap->rows;
unsigned int width = bitmap->width;
int pitch = bitmap->pitch;
/* Render 3 separate monochrome bitmaps, shifting the outline */
/* by 1/3 pixel. */
@ -378,6 +285,9 @@
}
else if ( vmul ) /* lcd_v */
{
int pitch = bitmap->pitch;
/* Render 3 separate monochrome bitmaps, shifting the outline */
/* by 1/3 pixel. Triple the pitch to render on each third row. */
bitmap->pitch *= 3;
@ -418,15 +328,16 @@
#endif /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
/* everything is fine; don't deallocate buffer */
have_buffer = FALSE;
/* everything is fine; the glyph is now officially a bitmap */
slot->format = FT_GLYPH_FORMAT_BITMAP;
error = FT_Err_Ok;
Exit:
if ( have_outline_shifted )
if ( x_shift || y_shift )
FT_Outline_Translate( outline, -x_shift, -y_shift );
if ( have_buffer )
if ( slot->format != FT_GLYPH_FORMAT_BITMAP &&
slot->internal->flags & FT_GLYPH_OWN_BITMAP )
{
FT_FREE( bitmap->buffer );
slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
@ -460,12 +371,8 @@
{
FT_Error error;
error = ft_smooth_render_generic( render, slot, mode, origin,
FT_RENDER_MODE_LCD );
if ( !error )
slot->bitmap.pixel_mode = FT_PIXEL_MODE_LCD;
return error;
return ft_smooth_render_generic( render, slot, mode, origin,
FT_RENDER_MODE_LCD );
}
@ -478,12 +385,8 @@
{
FT_Error error;
error = ft_smooth_render_generic( render, slot, mode, origin,
FT_RENDER_MODE_LCD_V );
if ( !error )
slot->bitmap.pixel_mode = FT_PIXEL_MODE_LCD_V;
return error;
return ft_smooth_render_generic( render, slot, mode, origin,
FT_RENDER_MODE_LCD_V );
}