diff --git a/ChangeLog b/ChangeLog index 789ac9461..7c19448c0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,24 @@ +2018-05-24 Alexei Podtelezhnikov + + [smooth] Formalize 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. + + * include/freetype/internal/ftobjs.h (FT_LibraryRec): New array field + `lcd_geometry'. + * src/base/ftlcdfil.c (ft_lcd_padding): Reworked. + * src/base/ftobjs.c (ft_glyphslot_preset_bitmap): Updated accordingly. + + * src/smooth/ftsmooth.c [!FT_CONFIG_OPTION_SUBPIXEL_RENDERING] + (ft_smooth_init): Initialize `lcd_geometry'. + (ft_smooth_render_generic): Formalize outline shifts. + 2018-05-22 Werner Lemberg [truetype] Reject elements of composites with invalid glyph indices. diff --git a/include/freetype/internal/ftobjs.h b/include/freetype/internal/ftobjs.h index a8d987fcc..77f5dc463 100644 --- a/include/freetype/internal/ftobjs.h +++ b/include/freetype/internal/ftobjs.h @@ -270,11 +270,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 @@ -350,8 +350,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 */ @@ -868,11 +868,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. */ @@ -904,6 +908,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 FT_Int refcount; diff --git a/src/base/ftlcdfil.c b/src/base/ftlcdfil.c index 8d314df08..213f3f1dd 100644 --- a/src/base/ftlcdfil.c +++ b/src/base/ftlcdfil.c @@ -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 ); + } } diff --git a/src/base/ftobjs.c b/src/base/ftobjs.c index d7768dd69..2cd0c9293 100644 --- a/src/base/ftobjs.c +++ b/src/base/ftobjs.c @@ -397,12 +397,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: diff --git a/src/smooth/ftsmooth.c b/src/smooth/ftsmooth.c index 497926ea4..381325109 100644 --- a/src/smooth/ftsmooth.c +++ b/src/smooth/ftsmooth.c @@ -30,6 +30,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; @@ -234,33 +250,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, ¶ms ); 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, ¶ms ); 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, ¶ms ); + if ( error ) + goto Exit; + + x_shift -= sub[2].x; + y_shift -= sub[2].y; bitmap->buffer -= 2 * width; - error = render->raster_render( render->raster, ¶ms ); - 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. */ @@ -285,34 +301,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, ¶ms ); 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, ¶ms ); 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, ¶ms ); + if ( error ) + goto Exit; + + x_shift -= sub[2].y; + y_shift += sub[2].x; bitmap->buffer -= 2 * pitch; - error = render->raster_render( render->raster, ¶ms ); - if ( error ) - goto Exit; - bitmap->pitch /= 3; bitmap->rows *= 3; }