Home | History | Annotate | Download | only in smooth
      1 /***************************************************************************/
      2 /*                                                                         */
      3 /*  ftsmooth.c                                                             */
      4 /*                                                                         */
      5 /*    Anti-aliasing renderer interface (body).                             */
      6 /*                                                                         */
      7 /*  Copyright 2000-2017 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 #include "ftspic.h"
     26 
     27 #include "ftsmerrs.h"
     28 
     29 
     30   /* initialize renderer -- init its raster */
     31   static FT_Error
     32   ft_smooth_init( FT_Renderer  render )
     33   {
     34     FT_Library  library = FT_MODULE_LIBRARY( render );
     35 
     36 
     37     render->clazz->raster_class->raster_reset( render->raster,
     38                                                library->raster_pool,
     39                                                library->raster_pool_size );
     40 
     41     return 0;
     42   }
     43 
     44 
     45   /* sets render-specific mode */
     46   static FT_Error
     47   ft_smooth_set_mode( FT_Renderer  render,
     48                       FT_ULong     mode_tag,
     49                       FT_Pointer   data )
     50   {
     51     /* we simply pass it to the raster */
     52     return render->clazz->raster_class->raster_set_mode( render->raster,
     53                                                          mode_tag,
     54                                                          data );
     55   }
     56 
     57   /* transform a given glyph image */
     58   static FT_Error
     59   ft_smooth_transform( FT_Renderer       render,
     60                        FT_GlyphSlot      slot,
     61                        const FT_Matrix*  matrix,
     62                        const FT_Vector*  delta )
     63   {
     64     FT_Error  error = FT_Err_Ok;
     65 
     66 
     67     if ( slot->format != render->glyph_format )
     68     {
     69       error = FT_THROW( Invalid_Argument );
     70       goto Exit;
     71     }
     72 
     73     if ( matrix )
     74       FT_Outline_Transform( &slot->outline, matrix );
     75 
     76     if ( delta )
     77       FT_Outline_Translate( &slot->outline, delta->x, delta->y );
     78 
     79   Exit:
     80     return error;
     81   }
     82 
     83 
     84   /* return the glyph's control box */
     85   static void
     86   ft_smooth_get_cbox( FT_Renderer   render,
     87                       FT_GlyphSlot  slot,
     88                       FT_BBox*      cbox )
     89   {
     90     FT_ZERO( cbox );
     91 
     92     if ( slot->format == render->glyph_format )
     93       FT_Outline_Get_CBox( &slot->outline, cbox );
     94   }
     95 
     96 
     97   /* convert a slot's glyph image into a bitmap */
     98   static FT_Error
     99   ft_smooth_render_generic( FT_Renderer       render,
    100                             FT_GlyphSlot      slot,
    101                             FT_Render_Mode    mode,
    102                             const FT_Vector*  origin,
    103                             FT_Render_Mode    required_mode )
    104   {
    105     FT_Error     error;
    106     FT_Outline*  outline = &slot->outline;
    107     FT_Bitmap*   bitmap  = &slot->bitmap;
    108     FT_Memory    memory  = render->root.memory;
    109     FT_BBox      cbox;
    110     FT_Pos       x_shift = 0;
    111     FT_Pos       y_shift = 0;
    112     FT_Pos       x_left, y_top;
    113     FT_Pos       width, height, pitch;
    114 #ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
    115     FT_Pos       height_org, width_org;
    116 #endif
    117     FT_Int       hmul    = ( mode == FT_RENDER_MODE_LCD );
    118     FT_Int       vmul    = ( mode == FT_RENDER_MODE_LCD_V );
    119 
    120     FT_Raster_Params  params;
    121 
    122     FT_Bool  have_outline_shifted = FALSE;
    123     FT_Bool  have_buffer          = FALSE;
    124 
    125 
    126     /* check glyph image format */
    127     if ( slot->format != render->glyph_format )
    128     {
    129       error = FT_THROW( Invalid_Argument );
    130       goto Exit;
    131     }
    132 
    133     /* check mode */
    134     if ( mode != required_mode )
    135     {
    136       error = FT_THROW( Cannot_Render_Glyph );
    137       goto Exit;
    138     }
    139 
    140     if ( origin )
    141     {
    142       x_shift = origin->x;
    143       y_shift = origin->y;
    144     }
    145 
    146     /* compute the control box, and grid fit it */
    147     /* taking into account the origin shift     */
    148     FT_Outline_Get_CBox( outline, &cbox );
    149 
    150     cbox.xMin = FT_PIX_FLOOR( cbox.xMin + x_shift );
    151     cbox.yMin = FT_PIX_FLOOR( cbox.yMin + y_shift );
    152     cbox.xMax = FT_PIX_CEIL( cbox.xMax + x_shift );
    153     cbox.yMax = FT_PIX_CEIL( cbox.yMax + y_shift );
    154 
    155     x_shift -= cbox.xMin;
    156     y_shift -= cbox.yMin;
    157 
    158     x_left  = cbox.xMin >> 6;
    159     y_top   = cbox.yMax >> 6;
    160 
    161     width  = (FT_ULong)( cbox.xMax - cbox.xMin ) >> 6;
    162     height = (FT_ULong)( cbox.yMax - cbox.yMin ) >> 6;
    163 
    164 #ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
    165     width_org  = width;
    166     height_org = height;
    167 #endif
    168 
    169     pitch = width;
    170     if ( hmul )
    171     {
    172       width *= 3;
    173       pitch  = FT_PAD_CEIL( width, 4 );
    174     }
    175 
    176     if ( vmul )
    177       height *= 3;
    178 
    179 #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
    180 
    181     if ( slot->library->lcd_filter_func )
    182     {
    183       FT_Int  extra = slot->library->lcd_extra;
    184 
    185 
    186       if ( hmul )
    187       {
    188         x_shift += 64 * ( extra >> 1 );
    189         x_left  -= extra >> 1;
    190         width   += 3 * extra;
    191         pitch    = FT_PAD_CEIL( width, 4 );
    192       }
    193 
    194       if ( vmul )
    195       {
    196         y_shift += 64 * ( extra >> 1 );
    197         y_top   += extra >> 1;
    198         height  += 3 * extra;
    199       }
    200     }
    201 
    202 #endif
    203 
    204     /*
    205      * XXX: on 16bit system, we return an error for huge bitmap
    206      * to prevent an overflow.
    207      */
    208     if ( x_left > FT_INT_MAX || y_top > FT_INT_MAX ||
    209          x_left < FT_INT_MIN || y_top < FT_INT_MIN )
    210     {
    211       error = FT_THROW( Invalid_Pixel_Size );
    212       goto Exit;
    213     }
    214 
    215     /* Required check is (pitch * height < FT_ULONG_MAX),        */
    216     /* but we care realistic cases only.  Always pitch <= width. */
    217     if ( width > 0x7FFF || height > 0x7FFF )
    218     {
    219       FT_ERROR(( "ft_smooth_render_generic: glyph too large: %u x %u\n",
    220                  width, height ));
    221       error = FT_THROW( Raster_Overflow );
    222       goto Exit;
    223     }
    224 
    225     /* release old bitmap buffer */
    226     if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
    227     {
    228       FT_FREE( bitmap->buffer );
    229       slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
    230     }
    231 
    232     /* allocate new one */
    233     if ( FT_ALLOC( bitmap->buffer, (FT_ULong)( pitch * height ) ) )
    234       goto Exit;
    235     else
    236       have_buffer = TRUE;
    237 
    238     slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
    239 
    240     slot->format      = FT_GLYPH_FORMAT_BITMAP;
    241     slot->bitmap_left = (FT_Int)x_left;
    242     slot->bitmap_top  = (FT_Int)y_top;
    243 
    244     bitmap->pixel_mode = FT_PIXEL_MODE_GRAY;
    245     bitmap->num_grays  = 256;
    246     bitmap->width      = (unsigned int)width;
    247     bitmap->rows       = (unsigned int)height;
    248     bitmap->pitch      = pitch;
    249 
    250     /* translate outline to render it into the bitmap */
    251     if ( x_shift || y_shift )
    252     {
    253       FT_Outline_Translate( outline, x_shift, y_shift );
    254       have_outline_shifted = TRUE;
    255     }
    256 
    257     /* set up parameters */
    258     params.target = bitmap;
    259     params.source = outline;
    260     params.flags  = FT_RASTER_FLAG_AA;
    261 
    262 #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
    263 
    264     /* implode outline if needed */
    265     {
    266       FT_Vector*  points     = outline->points;
    267       FT_Vector*  points_end = points + outline->n_points;
    268       FT_Vector*  vec;
    269 
    270 
    271       if ( hmul )
    272         for ( vec = points; vec < points_end; vec++ )
    273           vec->x *= 3;
    274 
    275       if ( vmul )
    276         for ( vec = points; vec < points_end; vec++ )
    277           vec->y *= 3;
    278     }
    279 
    280     /* render outline into the bitmap */
    281     error = render->raster_render( render->raster, &params );
    282 
    283     /* deflate outline if needed */
    284     {
    285       FT_Vector*  points     = outline->points;
    286       FT_Vector*  points_end = points + outline->n_points;
    287       FT_Vector*  vec;
    288 
    289 
    290       if ( hmul )
    291         for ( vec = points; vec < points_end; vec++ )
    292           vec->x /= 3;
    293 
    294       if ( vmul )
    295         for ( vec = points; vec < points_end; vec++ )
    296           vec->y /= 3;
    297     }
    298 
    299     if ( error )
    300       goto Exit;
    301 
    302     if ( slot->library->lcd_filter_func )
    303       slot->library->lcd_filter_func( bitmap, mode, slot->library );
    304 
    305 #else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
    306 
    307     /* render outline into bitmap */
    308     error = render->raster_render( render->raster, &params );
    309     if ( error )
    310       goto Exit;
    311 
    312     /* expand it horizontally */
    313     if ( hmul )
    314     {
    315       FT_Byte*  line = bitmap->buffer;
    316       FT_UInt   hh;
    317 
    318 
    319       for ( hh = height_org; hh > 0; hh--, line += pitch )
    320       {
    321         FT_UInt   xx;
    322         FT_Byte*  end = line + width;
    323 
    324 
    325         for ( xx = width_org; xx > 0; xx-- )
    326         {
    327           FT_UInt  pixel = line[xx-1];
    328 
    329 
    330           end[-3] = (FT_Byte)pixel;
    331           end[-2] = (FT_Byte)pixel;
    332           end[-1] = (FT_Byte)pixel;
    333           end    -= 3;
    334         }
    335       }
    336     }
    337 
    338     /* expand it vertically */
    339     if ( vmul )
    340     {
    341       FT_Byte*  read  = bitmap->buffer + ( height - height_org ) * pitch;
    342       FT_Byte*  write = bitmap->buffer;
    343       FT_UInt   hh;
    344 
    345 
    346       for ( hh = height_org; hh > 0; hh-- )
    347       {
    348         ft_memcpy( write, read, pitch );
    349         write += pitch;
    350 
    351         ft_memcpy( write, read, pitch );
    352         write += pitch;
    353 
    354         ft_memcpy( write, read, pitch );
    355         write += pitch;
    356         read  += pitch;
    357       }
    358     }
    359 
    360 #endif /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
    361 
    362     /* everything is fine; don't deallocate buffer */
    363     have_buffer = FALSE;
    364 
    365     error = FT_Err_Ok;
    366 
    367   Exit:
    368     if ( have_outline_shifted )
    369       FT_Outline_Translate( outline, -x_shift, -y_shift );
    370     if ( have_buffer )
    371     {
    372       FT_FREE( bitmap->buffer );
    373       slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
    374     }
    375 
    376     return error;
    377   }
    378 
    379 
    380   /* convert a slot's glyph image into a bitmap */
    381   static FT_Error
    382   ft_smooth_render( FT_Renderer       render,
    383                     FT_GlyphSlot      slot,
    384                     FT_Render_Mode    mode,
    385                     const FT_Vector*  origin )
    386   {
    387     if ( mode == FT_RENDER_MODE_LIGHT )
    388       mode = FT_RENDER_MODE_NORMAL;
    389 
    390     return ft_smooth_render_generic( render, slot, mode, origin,
    391                                      FT_RENDER_MODE_NORMAL );
    392   }
    393 
    394 
    395   /* convert a slot's glyph image into a horizontal LCD bitmap */
    396   static FT_Error
    397   ft_smooth_render_lcd( FT_Renderer       render,
    398                         FT_GlyphSlot      slot,
    399                         FT_Render_Mode    mode,
    400                         const FT_Vector*  origin )
    401   {
    402     FT_Error  error;
    403 
    404     error = ft_smooth_render_generic( render, slot, mode, origin,
    405                                       FT_RENDER_MODE_LCD );
    406     if ( !error )
    407       slot->bitmap.pixel_mode = FT_PIXEL_MODE_LCD;
    408 
    409     return error;
    410   }
    411 
    412 
    413   /* convert a slot's glyph image into a vertical LCD bitmap */
    414   static FT_Error
    415   ft_smooth_render_lcd_v( FT_Renderer       render,
    416                           FT_GlyphSlot      slot,
    417                           FT_Render_Mode    mode,
    418                           const FT_Vector*  origin )
    419   {
    420     FT_Error  error;
    421 
    422     error = ft_smooth_render_generic( render, slot, mode, origin,
    423                                       FT_RENDER_MODE_LCD_V );
    424     if ( !error )
    425       slot->bitmap.pixel_mode = FT_PIXEL_MODE_LCD_V;
    426 
    427     return error;
    428   }
    429 
    430 
    431   FT_DEFINE_RENDERER(
    432     ft_smooth_renderer_class,
    433 
    434       FT_MODULE_RENDERER,
    435       sizeof ( FT_RendererRec ),
    436 
    437       "smooth",
    438       0x10000L,
    439       0x20000L,
    440 
    441       NULL,    /* module specific interface */
    442 
    443       (FT_Module_Constructor)ft_smooth_init,  /* module_init   */
    444       (FT_Module_Destructor) NULL,            /* module_done   */
    445       (FT_Module_Requester)  NULL,            /* get_interface */
    446 
    447     FT_GLYPH_FORMAT_OUTLINE,
    448 
    449     (FT_Renderer_RenderFunc)   ft_smooth_render,     /* render_glyph    */
    450     (FT_Renderer_TransformFunc)ft_smooth_transform,  /* transform_glyph */
    451     (FT_Renderer_GetCBoxFunc)  ft_smooth_get_cbox,   /* get_glyph_cbox  */
    452     (FT_Renderer_SetModeFunc)  ft_smooth_set_mode,   /* set_mode        */
    453 
    454     (FT_Raster_Funcs*)&FT_GRAYS_RASTER_GET           /* raster_class    */
    455   )
    456 
    457 
    458   FT_DEFINE_RENDERER(
    459     ft_smooth_lcd_renderer_class,
    460 
    461       FT_MODULE_RENDERER,
    462       sizeof ( FT_RendererRec ),
    463 
    464       "smooth-lcd",
    465       0x10000L,
    466       0x20000L,
    467 
    468       NULL,    /* module specific interface */
    469 
    470       (FT_Module_Constructor)ft_smooth_init,  /* module_init   */
    471       (FT_Module_Destructor) NULL,            /* module_done   */
    472       (FT_Module_Requester)  NULL,            /* get_interface */
    473 
    474     FT_GLYPH_FORMAT_OUTLINE,
    475 
    476     (FT_Renderer_RenderFunc)   ft_smooth_render_lcd,  /* render_glyph    */
    477     (FT_Renderer_TransformFunc)ft_smooth_transform,   /* transform_glyph */
    478     (FT_Renderer_GetCBoxFunc)  ft_smooth_get_cbox,    /* get_glyph_cbox  */
    479     (FT_Renderer_SetModeFunc)  ft_smooth_set_mode,    /* set_mode        */
    480 
    481     (FT_Raster_Funcs*)&FT_GRAYS_RASTER_GET            /* raster_class    */
    482   )
    483 
    484 
    485   FT_DEFINE_RENDERER(
    486     ft_smooth_lcdv_renderer_class,
    487 
    488       FT_MODULE_RENDERER,
    489       sizeof ( FT_RendererRec ),
    490 
    491       "smooth-lcdv",
    492       0x10000L,
    493       0x20000L,
    494 
    495       NULL,    /* module specific interface */
    496 
    497       (FT_Module_Constructor)ft_smooth_init,  /* module_init   */
    498       (FT_Module_Destructor) NULL,            /* module_done   */
    499       (FT_Module_Requester)  NULL,            /* get_interface */
    500 
    501     FT_GLYPH_FORMAT_OUTLINE,
    502 
    503     (FT_Renderer_RenderFunc)   ft_smooth_render_lcd_v,  /* render_glyph    */
    504     (FT_Renderer_TransformFunc)ft_smooth_transform,     /* transform_glyph */
    505     (FT_Renderer_GetCBoxFunc)  ft_smooth_get_cbox,      /* get_glyph_cbox  */
    506     (FT_Renderer_SetModeFunc)  ft_smooth_set_mode,      /* set_mode        */
    507 
    508     (FT_Raster_Funcs*)&FT_GRAYS_RASTER_GET              /* raster_class    */
    509   )
    510 
    511 
    512 /* END */
    513