Formulate Harmony LCD rendering.

This generalizes magic outline shifts that make Harmony LCD
rendering work in terms of precise two-dimensional RGB subpixel
positions. These coordinates are now set in time of the `smooth'
module initialization and later used to shift a glyph outline for
rendering. FT_RENDER_MODE_LCD and FT_RENDER_MODE_LCD_V use the same
coordinates. The letter, however, rotates them before using.
The LCD bitmap padding is also calculated using these coordinates.
There should be rendering changes resuting from this commit.
This commit is contained in:
Alexei Podtelezhnikov 2018-04-28 23:01:44 -04:00
parent b5a29cce2f
commit 11ffff2c91
4 changed files with 98 additions and 52 deletions

View File

@ -312,11 +312,11 @@ FT_BEGIN_HEADER
FT_CMap_Done( FT_CMap cmap );
/* adds LCD padding to Min and Max boundaries */
/* add LCD padding to CBox */
FT_BASE( void )
ft_lcd_padding( FT_Pos* Min,
FT_Pos* Max,
FT_GlyphSlot slot );
ft_lcd_padding( FT_BBox* cbox,
FT_GlyphSlot slot,
FT_Render_Mode mode );
#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
@ -392,8 +392,8 @@ FT_BEGIN_HEADER
/* */
/* lcd_weights :: */
/* lcd_filter_func :: */
/* If subpixel rendering is activated, the LCD filtering weights */
/* and callback function. */
/* These fields specify the LCD filtering weights and callback */
/* function for ClearType-style subpixel rendering. */
/* */
/* refcount :: */
/* A counter initialized to~1 at the time an @FT_Face structure is */
@ -897,11 +897,15 @@ FT_BEGIN_HEADER
/* interpreter. Currently, only the TrueType */
/* bytecode debugger uses this. */
/* */
/* lcd_weights :: If subpixel rendering is activated, the LCD */
/* filter weights, if any. */
/* lcd_weights :: The LCD filter weights for ClearType-style */
/* subpixel rendering. */
/* */
/* lcd_filter_func :: If subpixel rendering is activated, the LCD */
/* filtering callback function. */
/* lcd_filter_func :: The LCD filtering callback function for */
/* for ClearType-style subpixel rendering. */
/* */
/* lcd_geometry :: This array specifies LCD subpixel geometry */
/* and controls Harmony LCD rendering technique, */
/* alternative to ClearType. */
/* */
/* pic_container :: Contains global structs and tables, instead */
/* of defining them globally. */
@ -933,6 +937,8 @@ FT_BEGIN_HEADER
#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
FT_LcdFiveTapFilter lcd_weights; /* filter weights, if any */
FT_Bitmap_LcdFilterFunc lcd_filter_func; /* filtering callback */
#else
FT_Vector lcd_geometry[3]; /* RGB subpixel positions */
#endif
#ifdef FT_CONFIG_OPTION_PIC

View File

@ -34,9 +34,9 @@
/* add padding according to filter weights */
FT_BASE_DEF (void)
ft_lcd_padding( FT_Pos* Min,
FT_Pos* Max,
FT_GlyphSlot slot )
ft_lcd_padding( FT_BBox* cbox,
FT_GlyphSlot slot,
FT_Render_Mode mode )
{
FT_Byte* lcd_weights;
FT_Bitmap_LcdFilterFunc lcd_filter_func;
@ -56,10 +56,20 @@
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;
if ( mode == FT_RENDER_MODE_LCD )
{
cbox->xMin -= lcd_weights[0] ? 43 :
lcd_weights[1] ? 22 : 0;
cbox->xMax += lcd_weights[4] ? 43 :
lcd_weights[3] ? 22 : 0;
}
else if ( mode == FT_RENDER_MODE_LCD_V )
{
cbox->yMin -= lcd_weights[0] ? 43 :
lcd_weights[1] ? 22 : 0;
cbox->yMax += lcd_weights[4] ? 43 :
lcd_weights[3] ? 22 : 0;
}
}
}
@ -343,16 +353,28 @@
#else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
/* add padding according to accommodate outline shifts */
/* add padding to accommodate outline shifts */
FT_BASE_DEF (void)
ft_lcd_padding( FT_Pos* Min,
FT_Pos* Max,
FT_GlyphSlot slot )
ft_lcd_padding( FT_BBox* cbox,
FT_GlyphSlot slot,
FT_Render_Mode mode )
{
FT_UNUSED( slot );
FT_Vector* sub = slot->library->lcd_geometry;
*Min -= 21;
*Max += 21;
if ( mode == FT_RENDER_MODE_LCD )
{
cbox->xMin -= FT_MAX( FT_MAX( sub[0].x, sub[1].x ), sub[2].x );
cbox->xMax -= FT_MIN( FT_MIN( sub[0].x, sub[1].x ), sub[2].x );
cbox->yMin -= FT_MAX( FT_MAX( sub[0].y, sub[1].y ), sub[2].y );
cbox->yMax -= FT_MIN( FT_MIN( sub[0].y, sub[1].y ), sub[2].y );
}
else if ( mode == FT_RENDER_MODE_LCD_V )
{
cbox->xMin -= FT_MAX( FT_MAX( sub[0].y, sub[1].y ), sub[2].y );
cbox->xMax -= FT_MIN( FT_MIN( sub[0].y, sub[1].y ), sub[2].y );
cbox->yMin += FT_MIN( FT_MIN( sub[0].x, sub[1].x ), sub[2].x );
cbox->yMax += FT_MAX( FT_MAX( sub[0].x, sub[1].x ), sub[2].x );
}
}

View File

@ -403,12 +403,12 @@
case FT_RENDER_MODE_LCD:
pixel_mode = FT_PIXEL_MODE_LCD;
ft_lcd_padding( &cbox.xMin, &cbox.xMax, slot );
ft_lcd_padding( &cbox, slot, mode );
goto Round;
case FT_RENDER_MODE_LCD_V:
pixel_mode = FT_PIXEL_MODE_LCD_V;
ft_lcd_padding( &cbox.yMin, &cbox.yMax, slot );
ft_lcd_padding( &cbox, slot, mode );
goto Round;
case FT_RENDER_MODE_NORMAL:

View File

@ -31,6 +31,22 @@
static FT_Error
ft_smooth_init( FT_Renderer render )
{
#ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
FT_Vector* sub = render->root.library->lcd_geometry;
/* set up default subpixel geometry for striped RGB panels. */
sub[0].x = -21;
sub[0].y = 0;
sub[1].x = 0;
sub[1].y = 0;
sub[2].x = 21;
sub[2].y = 0;
#endif
render->clazz->raster_class->raster_reset( render->raster, NULL, 0 );
return 0;
@ -235,33 +251,33 @@
unsigned int width = bitmap->width;
int pitch = bitmap->pitch;
FT_Vector* sub = slot->library->lcd_geometry;
/* Render 3 separate monochrome bitmaps, shifting the outline */
/* by 1/3 pixel. */
/* Render 3 separate monochrome bitmaps, shifting the outline. */
width /= 3;
bitmap->buffer += width;
FT_Outline_Translate( outline, -sub[0].x, -sub[0].y );
error = render->raster_render( render->raster, &params );
if ( error )
goto Exit;
FT_Outline_Translate( outline, -21, 0 );
x_shift -= 21;
bitmap->buffer += width;
FT_Outline_Translate( outline, sub[0].x - sub[1].x, sub[0].y - sub[1].y );
error = render->raster_render( render->raster, &params );
if ( error )
goto Exit;
FT_Outline_Translate( outline, 42, 0 );
x_shift += 42;
bitmap->buffer += width;
FT_Outline_Translate( outline, sub[1].x - sub[2].x, sub[1].y - sub[2].y );
error = render->raster_render( render->raster, &params );
if ( error )
goto Exit;
x_shift -= sub[2].x;
y_shift -= sub[2].y;
bitmap->buffer -= 2 * width;
error = render->raster_render( render->raster, &params );
if ( error )
goto Exit;
/* XXX: Rearrange the bytes according to FT_PIXEL_MODE_LCD. */
/* XXX: It is more efficient to render every third byte above. */
@ -286,34 +302,36 @@
{
int pitch = bitmap->pitch;
FT_Vector* sub = slot->library->lcd_geometry;
/* Render 3 separate monochrome bitmaps, shifting the outline */
/* by 1/3 pixel. Triple the pitch to render on each third row. */
/* Render 3 separate monochrome bitmaps, shifting the outline. */
/* Notice that the subpixel geometry vectors are rotated. */
/* Triple the pitch to render on each third row. */
bitmap->pitch *= 3;
bitmap->rows /= 3;
bitmap->buffer += pitch;
FT_Outline_Translate( outline, -sub[0].y, sub[0].x );
error = render->raster_render( render->raster, &params );
if ( error )
goto Exit;
FT_Outline_Translate( outline, 0, 21 );
y_shift += 21;
bitmap->buffer += pitch;
FT_Outline_Translate( outline, sub[0].y - sub[1].y, sub[1].x - sub[0].x );
error = render->raster_render( render->raster, &params );
if ( error )
goto Exit;
FT_Outline_Translate( outline, 0, -42 );
y_shift -= 42;
bitmap->buffer += pitch;
FT_Outline_Translate( outline, sub[1].y - sub[2].y, sub[2].x - sub[1].x );
error = render->raster_render( render->raster, &params );
if ( error )
goto Exit;
x_shift -= sub[2].y;
y_shift += sub[2].x;
bitmap->buffer -= 2 * pitch;
error = render->raster_render( render->raster, &params );
if ( error )
goto Exit;
bitmap->pitch /= 3;
bitmap->rows *= 3;
}