Home | History | Annotate | Download | only in smooth
      1 /****************************************************************************
      2  *
      3  * ftsmooth.c
      4  *
      5  *   Anti-aliasing renderer interface (body).
      6  *
      7  * Copyright 2000-2018 by
      8  * David Turner, Robert Wilhelm, and Werner Lemberg.
      9  *
     10  * This file is part of the FreeType project, and may only be used,
     11  * modified, and distributed under the terms of the FreeType project
     12  * license, LICENSE.TXT.  By continuing to use, modify, or distribute
     13  * this file you indicate that you have read the license and
     14  * understand and accept it fully.
     15  *
     16  */
     17 
     18 
     19 #include <ft2build.h>
     20 #include FT_INTERNAL_DEBUG_H
     21 #include FT_INTERNAL_OBJECTS_H
     22 #include FT_OUTLINE_H
     23 #include "ftsmooth.h"
     24 #include "ftgrays.h"
     25 
     26 #include "ftsmerrs.h"
     27 
     28 
     29   /* initialize renderer -- init its raster */
     30   static FT_Error
     31   ft_smooth_init( FT_Renderer  render )
     32   {
     33 
     34 #ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
     35 
     36     FT_Vector*  sub = render->root.library->lcd_geometry;
     37 
     38 
     39     /* set up default subpixel geometry for striped RGB panels. */
     40     sub[0].x = -21;
     41     sub[0].y = 0;
     42     sub[1].x = 0;
     43     sub[1].y = 0;
     44     sub[2].x = 21;
     45     sub[2].y = 0;
     46 
     47 #endif
     48 
     49     render->clazz->raster_class->raster_reset( render->raster, NULL, 0 );
     50 
     51     return 0;
     52   }
     53 
     54 
     55   /* sets render-specific mode */
     56   static FT_Error
     57   ft_smooth_set_mode( FT_Renderer  render,
     58                       FT_ULong     mode_tag,
     59                       FT_Pointer   data )
     60   {
     61     /* we simply pass it to the raster */
     62     return render->clazz->raster_class->raster_set_mode( render->raster,
     63                                                          mode_tag,
     64                                                          data );
     65   }
     66 
     67   /* transform a given glyph image */
     68   static FT_Error
     69   ft_smooth_transform( FT_Renderer       render,
     70                        FT_GlyphSlot      slot,
     71                        const FT_Matrix*  matrix,
     72                        const FT_Vector*  delta )
     73   {
     74     FT_Error  error = FT_Err_Ok;
     75 
     76 
     77     if ( slot->format != render->glyph_format )
     78     {
     79       error = FT_THROW( Invalid_Argument );
     80       goto Exit;
     81     }
     82 
     83     if ( matrix )
     84       FT_Outline_Transform( &slot->outline, matrix );
     85 
     86     if ( delta )
     87       FT_Outline_Translate( &slot->outline, delta->x, delta->y );
     88 
     89   Exit:
     90     return error;
     91   }
     92 
     93 
     94   /* return the glyph's control box */
     95   static void
     96   ft_smooth_get_cbox( FT_Renderer   render,
     97                       FT_GlyphSlot  slot,
     98                       FT_BBox*      cbox )
     99   {
    100     FT_ZERO( cbox );
    101 
    102     if ( slot->format == render->glyph_format )
    103       FT_Outline_Get_CBox( &slot->outline, cbox );
    104   }
    105 
    106 
    107   /* convert a slot's glyph image into a bitmap */
    108   static FT_Error
    109   ft_smooth_render_generic( FT_Renderer       render,
    110                             FT_GlyphSlot      slot,
    111                             FT_Render_Mode    mode,
    112                             const FT_Vector*  origin,
    113                             FT_Render_Mode    required_mode )
    114   {
    115     FT_Error     error   = FT_Err_Ok;
    116     FT_Outline*  outline = &slot->outline;
    117     FT_Bitmap*   bitmap  = &slot->bitmap;
    118     FT_Memory    memory  = render->root.memory;
    119     FT_Pos       x_shift = 0;
    120     FT_Pos       y_shift = 0;
    121     FT_Int       hmul    = ( mode == FT_RENDER_MODE_LCD );
    122     FT_Int       vmul    = ( mode == FT_RENDER_MODE_LCD_V );
    123 
    124     FT_Raster_Params  params;
    125 
    126 
    127     /* check glyph image format */
    128     if ( slot->format != render->glyph_format )
    129     {
    130       error = FT_THROW( Invalid_Argument );
    131       goto Exit;
    132     }
    133 
    134     /* check mode */
    135     if ( mode != required_mode )
    136     {
    137       error = FT_THROW( Cannot_Render_Glyph );
    138       goto Exit;
    139     }
    140 
    141     /* release old bitmap buffer */
    142     if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
    143     {
    144       FT_FREE( bitmap->buffer );
    145       slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
    146     }
    147 
    148     ft_glyphslot_preset_bitmap( slot, mode, origin );
    149 
    150     if ( bitmap->width > 0x7FFF || bitmap->rows > 0x7FFF )
    151     {
    152       FT_ERROR(( "ft_smooth_render_generic: glyph is too large: %u x %u\n",
    153                  bitmap->width, bitmap->rows ));
    154       error = FT_THROW( Raster_Overflow );
    155       goto Exit;
    156     }
    157 
    158     /* allocate new one */
    159     if ( FT_ALLOC_MULT( bitmap->buffer, bitmap->rows, bitmap->pitch ) )
    160       goto Exit;
    161 
    162     slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
    163 
    164     x_shift = 64 * -slot->bitmap_left;
    165     y_shift = 64 * -slot->bitmap_top;
    166     if ( bitmap->pixel_mode == FT_PIXEL_MODE_LCD_V )
    167       y_shift += 64 * (FT_Int)bitmap->rows / 3;
    168     else
    169       y_shift += 64 * (FT_Int)bitmap->rows;
    170 
    171     if ( origin )
    172     {
    173       x_shift += origin->x;
    174       y_shift += origin->y;
    175     }
    176 
    177     /* translate outline to render it into the bitmap */
    178     if ( x_shift || y_shift )
    179       FT_Outline_Translate( outline, x_shift, y_shift );
    180 
    181     /* set up parameters */
    182     params.target = bitmap;
    183     params.source = outline;
    184     params.flags  = FT_RASTER_FLAG_AA;
    185 
    186 #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
    187 
    188     /* implode outline if needed */
    189     {
    190       FT_Vector*  points     = outline->points;
    191       FT_Vector*  points_end = points + outline->n_points;
    192       FT_Vector*  vec;
    193 
    194 
    195       if ( hmul )
    196         for ( vec = points; vec < points_end; vec++ )
    197           vec->x *= 3;
    198 
    199       if ( vmul )
    200         for ( vec = points; vec < points_end; vec++ )
    201           vec->y *= 3;
    202     }
    203 
    204     /* render outline into the bitmap */
    205     error = render->raster_render( render->raster, &params );
    206 
    207     /* deflate outline if needed */
    208     {
    209       FT_Vector*  points     = outline->points;
    210       FT_Vector*  points_end = points + outline->n_points;
    211       FT_Vector*  vec;
    212 
    213 
    214       if ( hmul )
    215         for ( vec = points; vec < points_end; vec++ )
    216           vec->x /= 3;
    217 
    218       if ( vmul )
    219         for ( vec = points; vec < points_end; vec++ )
    220           vec->y /= 3;
    221     }
    222 
    223     if ( error )
    224       goto Exit;
    225 
    226     /* finally apply filtering */
    227     if ( hmul || vmul )
    228     {
    229       FT_Byte*                 lcd_weights;
    230       FT_Bitmap_LcdFilterFunc  lcd_filter_func;
    231 
    232 
    233       /* Per-face LCD filtering takes priority if set up. */
    234       if ( slot->face && slot->face->internal->lcd_filter_func )
    235       {
    236         lcd_weights     = slot->face->internal->lcd_weights;
    237         lcd_filter_func = slot->face->internal->lcd_filter_func;
    238       }
    239       else
    240       {
    241         lcd_weights     = slot->library->lcd_weights;
    242         lcd_filter_func = slot->library->lcd_filter_func;
    243       }
    244 
    245       if ( lcd_filter_func )
    246         lcd_filter_func( bitmap, mode, lcd_weights );
    247     }
    248 
    249 #else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
    250 
    251     if ( hmul )  /* lcd */
    252     {
    253       FT_Byte*  line;
    254       FT_Byte*  temp = NULL;
    255       FT_UInt   i, j;
    256 
    257       unsigned int  height = bitmap->rows;
    258       unsigned int  width  = bitmap->width;
    259       int           pitch  = bitmap->pitch;
    260 
    261       FT_Vector*  sub = slot->library->lcd_geometry;
    262 
    263 
    264       /* Render 3 separate monochrome bitmaps, shifting the outline.  */
    265       width /= 3;
    266 
    267       FT_Outline_Translate( outline,           -sub[0].x,           -sub[0].y );
    268       error = render->raster_render( render->raster, &params );
    269       if ( error )
    270         goto Exit;
    271 
    272       bitmap->buffer += width;
    273       FT_Outline_Translate( outline, sub[0].x - sub[1].x, sub[0].y - sub[1].y );
    274       error = render->raster_render( render->raster, &params );
    275       bitmap->buffer -= width;
    276       if ( error )
    277         goto Exit;
    278 
    279       bitmap->buffer += 2 * width;
    280       FT_Outline_Translate( outline, sub[1].x - sub[2].x, sub[1].y - sub[2].y );
    281       error = render->raster_render( render->raster, &params );
    282       bitmap->buffer -= 2 * width;
    283       if ( error )
    284         goto Exit;
    285 
    286       x_shift        -= sub[2].x;
    287       y_shift        -= sub[2].y;
    288 
    289       /* XXX: Rearrange the bytes according to FT_PIXEL_MODE_LCD.    */
    290       /* XXX: It is more efficient to render every third byte above. */
    291 
    292       if ( FT_ALLOC( temp, (FT_ULong)pitch ) )
    293         goto Exit;
    294 
    295       for ( i = 0; i < height; i++ )
    296       {
    297         line = bitmap->buffer + i * (FT_ULong)pitch;
    298         for ( j = 0; j < width; j++ )
    299         {
    300           temp[3 * j    ] = line[j];
    301           temp[3 * j + 1] = line[j + width];
    302           temp[3 * j + 2] = line[j + width + width];
    303         }
    304         FT_MEM_COPY( line, temp, pitch );
    305       }
    306 
    307       FT_FREE( temp );
    308     }
    309     else if ( vmul )  /* lcd_v */
    310     {
    311       int  pitch  = bitmap->pitch;
    312 
    313       FT_Vector*  sub = slot->library->lcd_geometry;
    314 
    315 
    316       /* Render 3 separate monochrome bitmaps, shifting the outline. */
    317       /* Notice that the subpixel geometry vectors are rotated.      */
    318       /* Triple the pitch to render on each third row.               */
    319       bitmap->pitch *= 3;
    320       bitmap->rows  /= 3;
    321 
    322       FT_Outline_Translate( outline,           -sub[0].y, sub[0].x            );
    323       error = render->raster_render( render->raster, &params );
    324       if ( error )
    325         goto Exit;
    326 
    327       bitmap->buffer += pitch;
    328       FT_Outline_Translate( outline, sub[0].y - sub[1].y, sub[1].x - sub[0].x );
    329       error = render->raster_render( render->raster, &params );
    330       bitmap->buffer -= pitch;
    331       if ( error )
    332         goto Exit;
    333 
    334       bitmap->buffer += 2 * pitch;
    335       FT_Outline_Translate( outline, sub[1].y - sub[2].y, sub[2].x - sub[1].x );
    336       error = render->raster_render( render->raster, &params );
    337       bitmap->buffer -= 2 * pitch;
    338       if ( error )
    339         goto Exit;
    340 
    341       x_shift        -= sub[2].y;
    342       y_shift        += sub[2].x;
    343 
    344       bitmap->pitch /= 3;
    345       bitmap->rows  *= 3;
    346     }
    347     else  /* grayscale */
    348       error = render->raster_render( render->raster, &params );
    349 
    350 #endif /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
    351 
    352   Exit:
    353     if ( !error )
    354     {
    355       /* everything is fine; the glyph is now officially a bitmap */
    356       slot->format = FT_GLYPH_FORMAT_BITMAP;
    357     }
    358     else if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
    359     {
    360       FT_FREE( bitmap->buffer );
    361       slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
    362     }
    363 
    364     if ( x_shift || y_shift )
    365       FT_Outline_Translate( outline, -x_shift, -y_shift );
    366 
    367     return error;
    368   }
    369 
    370 
    371   /* convert a slot's glyph image into a bitmap */
    372   static FT_Error
    373   ft_smooth_render( FT_Renderer       render,
    374                     FT_GlyphSlot      slot,
    375                     FT_Render_Mode    mode,
    376                     const FT_Vector*  origin )
    377   {
    378     if ( mode == FT_RENDER_MODE_LIGHT )
    379       mode = FT_RENDER_MODE_NORMAL;
    380 
    381     return ft_smooth_render_generic( render, slot, mode, origin,
    382                                      FT_RENDER_MODE_NORMAL );
    383   }
    384 
    385 
    386   /* convert a slot's glyph image into a horizontal LCD bitmap */
    387   static FT_Error
    388   ft_smooth_render_lcd( FT_Renderer       render,
    389                         FT_GlyphSlot      slot,
    390                         FT_Render_Mode    mode,
    391                         const FT_Vector*  origin )
    392   {
    393     return ft_smooth_render_generic( render, slot, mode, origin,
    394                                      FT_RENDER_MODE_LCD );
    395   }
    396 
    397 
    398   /* convert a slot's glyph image into a vertical LCD bitmap */
    399   static FT_Error
    400   ft_smooth_render_lcd_v( FT_Renderer       render,
    401                           FT_GlyphSlot      slot,
    402                           FT_Render_Mode    mode,
    403                           const FT_Vector*  origin )
    404   {
    405     return ft_smooth_render_generic( render, slot, mode, origin,
    406                                      FT_RENDER_MODE_LCD_V );
    407   }
    408 
    409 
    410   FT_DEFINE_RENDERER(
    411     ft_smooth_renderer_class,
    412 
    413       FT_MODULE_RENDERER,
    414       sizeof ( FT_RendererRec ),
    415 
    416       "smooth",
    417       0x10000L,
    418       0x20000L,
    419 
    420       NULL,    /* module specific interface */
    421 
    422       (FT_Module_Constructor)ft_smooth_init,  /* module_init   */
    423       (FT_Module_Destructor) NULL,            /* module_done   */
    424       (FT_Module_Requester)  NULL,            /* get_interface */
    425 
    426     FT_GLYPH_FORMAT_OUTLINE,
    427 
    428     (FT_Renderer_RenderFunc)   ft_smooth_render,     /* render_glyph    */
    429     (FT_Renderer_TransformFunc)ft_smooth_transform,  /* transform_glyph */
    430     (FT_Renderer_GetCBoxFunc)  ft_smooth_get_cbox,   /* get_glyph_cbox  */
    431     (FT_Renderer_SetModeFunc)  ft_smooth_set_mode,   /* set_mode        */
    432 
    433     (FT_Raster_Funcs*)&ft_grays_raster               /* raster_class    */
    434   )
    435 
    436 
    437   FT_DEFINE_RENDERER(
    438     ft_smooth_lcd_renderer_class,
    439 
    440       FT_MODULE_RENDERER,
    441       sizeof ( FT_RendererRec ),
    442 
    443       "smooth-lcd",
    444       0x10000L,
    445       0x20000L,
    446 
    447       NULL,    /* module specific interface */
    448 
    449       (FT_Module_Constructor)ft_smooth_init,  /* module_init   */
    450       (FT_Module_Destructor) NULL,            /* module_done   */
    451       (FT_Module_Requester)  NULL,            /* get_interface */
    452 
    453     FT_GLYPH_FORMAT_OUTLINE,
    454 
    455     (FT_Renderer_RenderFunc)   ft_smooth_render_lcd,  /* render_glyph    */
    456     (FT_Renderer_TransformFunc)ft_smooth_transform,   /* transform_glyph */
    457     (FT_Renderer_GetCBoxFunc)  ft_smooth_get_cbox,    /* get_glyph_cbox  */
    458     (FT_Renderer_SetModeFunc)  ft_smooth_set_mode,    /* set_mode        */
    459 
    460     (FT_Raster_Funcs*)&ft_grays_raster                /* raster_class    */
    461   )
    462 
    463 
    464   FT_DEFINE_RENDERER(
    465     ft_smooth_lcdv_renderer_class,
    466 
    467       FT_MODULE_RENDERER,
    468       sizeof ( FT_RendererRec ),
    469 
    470       "smooth-lcdv",
    471       0x10000L,
    472       0x20000L,
    473 
    474       NULL,    /* module specific interface */
    475 
    476       (FT_Module_Constructor)ft_smooth_init,  /* module_init   */
    477       (FT_Module_Destructor) NULL,            /* module_done   */
    478       (FT_Module_Requester)  NULL,            /* get_interface */
    479 
    480     FT_GLYPH_FORMAT_OUTLINE,
    481 
    482     (FT_Renderer_RenderFunc)   ft_smooth_render_lcd_v,  /* render_glyph    */
    483     (FT_Renderer_TransformFunc)ft_smooth_transform,     /* transform_glyph */
    484     (FT_Renderer_GetCBoxFunc)  ft_smooth_get_cbox,      /* get_glyph_cbox  */
    485     (FT_Renderer_SetModeFunc)  ft_smooth_set_mode,      /* set_mode        */
    486 
    487     (FT_Raster_Funcs*)&ft_grays_raster                  /* raster_class    */
    488   )
    489 
    490 
    491 /* END */
    492