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> 2017-09-28 Ewald Hew <ewaldhew@gmail.com>
[psaux] Fix compiler warning. [psaux] Fix compiler warning.

View File

@ -316,6 +316,14 @@ FT_BEGIN_HEADER
typedef FT_Byte FT_LcdFiveTapFilter[FT_LCD_FILTER_FIVE_TAPS]; 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, typedef void (*FT_Bitmap_LcdFilterFunc)( FT_Bitmap* bitmap,
FT_Render_Mode render_mode, FT_Render_Mode render_mode,
FT_Byte* weights ); FT_Byte* weights );
@ -327,6 +335,8 @@ FT_BEGIN_HEADER
FT_Render_Mode mode, FT_Render_Mode mode,
FT_LcdFiveTapFilter weights ); 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 ); 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. */ /* Allocate a new bitmap buffer in a glyph slot. */
FT_BASE( FT_Error ) FT_BASE( FT_Error )
ft_glyphslot_alloc_bitmap( FT_GlyphSlot slot, 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 ) ) #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 */ /* FIR filter used by the default and light filters */
FT_BASE_DEF( void ) FT_BASE_DEF( void )
ft_lcd_filter_fir( FT_Bitmap* bitmap, ft_lcd_filter_fir( FT_Bitmap* bitmap,
@ -310,14 +343,16 @@
#else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ #else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
FT_BASE( void ) /* add padding according to accommodate outline shifts */
ft_lcd_filter_fir( FT_Bitmap* bitmap, FT_BASE_DEF (void)
FT_Render_Mode mode, ft_lcd_padding( FT_Pos* Min,
FT_LcdFiveTapFilter weights ) FT_Pos* Max,
FT_GlyphSlot slot )
{ {
FT_UNUSED( bitmap ); FT_UNUSED( slot );
FT_UNUSED( mode );
FT_UNUSED( weights ); *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_BASE_DEF( void )
ft_glyphslot_set_bitmap( FT_GlyphSlot slot, ft_glyphslot_set_bitmap( FT_GlyphSlot slot,
FT_Byte* buffer ) FT_Byte* buffer )

View File

@ -98,11 +98,11 @@
const FT_Vector* origin ) const FT_Vector* origin )
{ {
FT_Error error; FT_Error error;
FT_Outline* outline; FT_Outline* outline = &slot->outline;
FT_BBox cbox, cbox0; FT_Bitmap* bitmap = &slot->bitmap;
FT_UInt width, height, pitch; FT_Memory memory = render->root.memory;
FT_Bitmap* bitmap; FT_Pos x_shift = 0;
FT_Memory memory; FT_Pos y_shift = 0;
FT_Raster_Params params; FT_Raster_Params params;
@ -121,60 +121,6 @@
return FT_THROW( Cannot_Render_Glyph ); 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 */ /* release old bitmap buffer */
if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
{ {
@ -182,20 +128,26 @@
slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
} }
pitch = ( ( width + 15 ) >> 4 ) << 1; ft_glyphslot_preset_bitmap( slot, mode, origin );
bitmap->pixel_mode = FT_PIXEL_MODE_MONO;
bitmap->width = width; /* allocate new one */
bitmap->rows = height; if ( FT_ALLOC_MULT( bitmap->buffer, bitmap->rows, bitmap->pitch ) )
bitmap->pitch = (int)pitch;
if ( FT_ALLOC_MULT( bitmap->buffer, height, pitch ) )
goto Exit; goto Exit;
slot->internal->flags |= FT_GLYPH_OWN_BITMAP; 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 */ /* 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 */ /* set up parameters */
params.target = bitmap; params.target = bitmap;
@ -204,17 +156,24 @@
/* render outline into the bitmap */ /* render outline into the bitmap */
error = render->raster_render( render->raster, &params ); error = render->raster_render( render->raster, &params );
FT_Outline_Translate( outline, cbox.xMin, cbox.yMin );
if ( error ) if ( error )
goto Exit; goto Exit;
slot->format = FT_GLYPH_FORMAT_BITMAP; /* everything is fine; the glyph is now officially a bitmap */
slot->bitmap_left = (FT_Int)( cbox.xMin >> 6 ); slot->format = FT_GLYPH_FORMAT_BITMAP;
slot->bitmap_top = (FT_Int)( cbox.yMax >> 6 );
error = FT_Err_Ok;
Exit: 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; return error;
} }

View File

@ -101,36 +101,13 @@
FT_Outline* outline = &slot->outline; FT_Outline* outline = &slot->outline;
FT_Bitmap* bitmap = &slot->bitmap; FT_Bitmap* bitmap = &slot->bitmap;
FT_Memory memory = render->root.memory; FT_Memory memory = render->root.memory;
FT_BBox cbox;
FT_Pos x_shift = 0; FT_Pos x_shift = 0;
FT_Pos y_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 hmul = ( mode == FT_RENDER_MODE_LCD );
FT_Int vmul = ( mode == FT_RENDER_MODE_LCD_V ); FT_Int vmul = ( mode == FT_RENDER_MODE_LCD_V );
FT_Raster_Params params; 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 */ /* check glyph image format */
if ( slot->format != render->glyph_format ) if ( slot->format != render->glyph_format )
@ -146,100 +123,6 @@
goto Exit; 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 */ /* release old bitmap buffer */
if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
{ {
@ -247,30 +130,30 @@
slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
} }
ft_glyphslot_preset_bitmap( slot, mode, origin );
/* allocate new one */ /* allocate new one */
if ( FT_ALLOC( bitmap->buffer, (FT_ULong)( pitch * height ) ) ) if ( FT_ALLOC_MULT( bitmap->buffer, bitmap->rows, bitmap->pitch ) )
goto Exit; goto Exit;
else
have_buffer = TRUE;
slot->internal->flags |= FT_GLYPH_OWN_BITMAP; slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
slot->format = FT_GLYPH_FORMAT_BITMAP; x_shift = 64 * -slot->bitmap_left;
slot->bitmap_left = (FT_Int)x_left; y_shift = 64 * -slot->bitmap_top;
slot->bitmap_top = (FT_Int)y_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; if ( origin )
bitmap->num_grays = 256; {
bitmap->width = (unsigned int)width; x_shift += origin->x;
bitmap->rows = (unsigned int)height; y_shift += origin->y;
bitmap->pitch = pitch; }
/* translate outline to render it into the bitmap */ /* translate outline to render it into the bitmap */
if ( x_shift || y_shift ) if ( x_shift || y_shift )
{
FT_Outline_Translate( outline, x_shift, y_shift ); FT_Outline_Translate( outline, x_shift, y_shift );
have_outline_shifted = TRUE;
}
/* set up parameters */ /* set up parameters */
params.target = bitmap; params.target = bitmap;
@ -317,8 +200,28 @@
if ( error ) if ( error )
goto Exit; goto Exit;
if ( lcd_filter_func ) /* finally apply filtering */
lcd_filter_func( bitmap, mode, lcd_weights ); 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 */ #else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
@ -328,6 +231,10 @@
FT_Byte* temp; FT_Byte* temp;
FT_Int i, j; 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 */ /* Render 3 separate monochrome bitmaps, shifting the outline */
/* by 1/3 pixel. */ /* by 1/3 pixel. */
@ -378,6 +285,9 @@
} }
else if ( vmul ) /* lcd_v */ else if ( vmul ) /* lcd_v */
{ {
int pitch = bitmap->pitch;
/* Render 3 separate monochrome bitmaps, shifting the outline */ /* Render 3 separate monochrome bitmaps, shifting the outline */
/* by 1/3 pixel. Triple the pitch to render on each third row. */ /* by 1/3 pixel. Triple the pitch to render on each third row. */
bitmap->pitch *= 3; bitmap->pitch *= 3;
@ -418,15 +328,16 @@
#endif /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ #endif /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
/* everything is fine; don't deallocate buffer */ /* everything is fine; the glyph is now officially a bitmap */
have_buffer = FALSE; slot->format = FT_GLYPH_FORMAT_BITMAP;
error = FT_Err_Ok; error = FT_Err_Ok;
Exit: Exit:
if ( have_outline_shifted ) if ( x_shift || y_shift )
FT_Outline_Translate( outline, -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 ); FT_FREE( bitmap->buffer );
slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
@ -460,12 +371,8 @@
{ {
FT_Error error; FT_Error error;
error = ft_smooth_render_generic( render, slot, mode, origin, return ft_smooth_render_generic( render, slot, mode, origin,
FT_RENDER_MODE_LCD ); FT_RENDER_MODE_LCD );
if ( !error )
slot->bitmap.pixel_mode = FT_PIXEL_MODE_LCD;
return error;
} }
@ -478,12 +385,8 @@
{ {
FT_Error error; FT_Error error;
error = ft_smooth_render_generic( render, slot, mode, origin, return ft_smooth_render_generic( render, slot, mode, origin,
FT_RENDER_MODE_LCD_V ); FT_RENDER_MODE_LCD_V );
if ( !error )
slot->bitmap.pixel_mode = FT_PIXEL_MODE_LCD_V;
return error;
} }