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 #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     render->clazz->raster_class->raster_reset( render->raster, NULL, 0 );
  35 
  36     return 0;
  37   }
  38 
  39 
  40   /* sets render-specific mode */
  41   static FT_Error
  42   ft_smooth_set_mode( FT_Renderer  render,
  43                       FT_ULong     mode_tag,
  44                       FT_Pointer   data )
  45   {
  46     /* we simply pass it to the raster */
  47     return render->clazz->raster_class->raster_set_mode( render->raster,
  48                                                          mode_tag,
  49                                                          data );
  50   }
  51 
  52   /* transform a given glyph image */
  53   static FT_Error
  54   ft_smooth_transform( FT_Renderer       render,
  55                        FT_GlyphSlot      slot,
  56                        const FT_Matrix*  matrix,
  57                        const FT_Vector*  delta )
  58   {
  59     FT_Error  error = FT_Err_Ok;
  60 
  61 
  62     if ( slot->format != render->glyph_format )
  63     {
  64       error = FT_THROW( Invalid_Argument );
  65       goto Exit;
  66     }
  67 
  68     if ( matrix )
  69       FT_Outline_Transform( &slot->outline, matrix );
  70 
  71     if ( delta )
  72       FT_Outline_Translate( &slot->outline, delta->x, delta->y );
  73 
  74   Exit:
  75     return error;
  76   }
  77 
  78 
  79   /* return the glyph's control box */
  80   static void
  81   ft_smooth_get_cbox( FT_Renderer   render,
  82                       FT_GlyphSlot  slot,
  83                       FT_BBox*      cbox )
  84   {
  85     FT_ZERO( cbox );
  86 
  87     if ( slot->format == render->glyph_format )
  88       FT_Outline_Get_CBox( &slot->outline, cbox );
  89   }
  90 
  91 
  92   /* convert a slot's glyph image into a bitmap */
  93   static FT_Error
  94   ft_smooth_render_generic( FT_Renderer       render,
  95                             FT_GlyphSlot      slot,
  96                             FT_Render_Mode    mode,
  97                             const FT_Vector*  origin,
  98                             FT_Render_Mode    required_mode )
  99   {
 100     FT_Error     error   = FT_Err_Ok;
 101     FT_Outline*  outline = &slot->outline;
 102     FT_Bitmap*   bitmap  = &slot->bitmap;
 103     FT_Memory    memory  = render->root.memory;
 104     FT_Pos       x_shift = 0;
 105     FT_Pos       y_shift = 0;
 106     FT_Int       hmul    = ( mode == FT_RENDER_MODE_LCD );
 107     FT_Int       vmul    = ( mode == FT_RENDER_MODE_LCD_V );
 108 
 109     FT_Raster_Params  params;
 110 
 111 
 112     /* check glyph image format */
 113     if ( slot->format != render->glyph_format )
 114     {
 115       error = FT_THROW( Invalid_Argument );
 116       goto Exit;
 117     }
 118 
 119     /* check mode */
 120     if ( mode != required_mode )
 121     {
 122       error = FT_THROW( Cannot_Render_Glyph );
 123       goto Exit;
 124     }
 125 
 126     /* release old bitmap buffer */
 127     if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
 128     {
 129       FT_FREE( bitmap->buffer );
 130       slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
 131     }
 132 
 133     ft_glyphslot_preset_bitmap( slot, mode, origin );
 134 
 135     /* allocate new one */
 136     if ( FT_ALLOC_MULT( bitmap->buffer, bitmap->rows, bitmap->pitch ) )
 137       goto Exit;
 138 
 139     slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
 140 
 141     x_shift = 64 * -slot->bitmap_left;
 142     y_shift = 64 * -slot->bitmap_top;
 143     if ( bitmap->pixel_mode == FT_PIXEL_MODE_LCD_V )
 144       y_shift += 64 * (FT_Int)bitmap->rows / 3;
 145     else
 146       y_shift += 64 * (FT_Int)bitmap->rows;
 147 
 148     if ( origin )
 149     {
 150       x_shift += origin->x;
 151       y_shift += origin->y;
 152     }
 153 
 154     /* translate outline to render it into the bitmap */
 155     if ( x_shift || y_shift )
 156       FT_Outline_Translate( outline, x_shift, y_shift );
 157 
 158     /* set up parameters */
 159     params.target = bitmap;
 160     params.source = outline;
 161     params.flags  = FT_RASTER_FLAG_AA;
 162 
 163 #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
 164 
 165     /* implode outline if needed */
 166     {
 167       FT_Vector*  points     = outline->points;
 168       FT_Vector*  points_end = points + outline->n_points;
 169       FT_Vector*  vec;
 170 
 171 
 172       if ( hmul )
 173         for ( vec = points; vec < points_end; vec++ )
 174           vec->x *= 3;
 175 
 176       if ( vmul )
 177         for ( vec = points; vec < points_end; vec++ )
 178           vec->y *= 3;
 179     }
 180 
 181     /* render outline into the bitmap */
 182     error = render->raster_render( render->raster, &params );
 183 
 184     /* deflate outline if needed */
 185     {
 186       FT_Vector*  points     = outline->points;
 187       FT_Vector*  points_end = points + outline->n_points;
 188       FT_Vector*  vec;
 189 
 190 
 191       if ( hmul )
 192         for ( vec = points; vec < points_end; vec++ )
 193           vec->x /= 3;
 194 
 195       if ( vmul )
 196         for ( vec = points; vec < points_end; vec++ )
 197           vec->y /= 3;
 198     }
 199 
 200     if ( error )
 201       goto Exit;
 202 
 203     /* finally apply filtering */
 204     if ( hmul || vmul )
 205     {
 206       FT_Byte*                 lcd_weights;
 207       FT_Bitmap_LcdFilterFunc  lcd_filter_func;
 208 
 209 
 210       /* Per-face LCD filtering takes priority if set up. */
 211       if ( slot->face && slot->face->internal->lcd_filter_func )
 212       {
 213         lcd_weights     = slot->face->internal->lcd_weights;
 214         lcd_filter_func = slot->face->internal->lcd_filter_func;
 215       }
 216       else
 217       {
 218         lcd_weights     = slot->library->lcd_weights;
 219         lcd_filter_func = slot->library->lcd_filter_func;
 220       }
 221 
 222       if ( lcd_filter_func )
 223         lcd_filter_func( bitmap, mode, lcd_weights );
 224     }
 225 
 226 #else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
 227 
 228     if ( hmul )  /* lcd */
 229     {
 230       FT_Byte*  line;
 231       FT_Byte*  temp = NULL;
 232       FT_UInt   i, j;
 233 
 234       unsigned int  height = bitmap->rows;
 235       unsigned int  width  = bitmap->width;
 236       int           pitch  = bitmap->pitch;
 237 
 238 
 239       /* Render 3 separate monochrome bitmaps, shifting the outline  */
 240       /* by 1/3 pixel.                                               */
 241       width /= 3;
 242 
 243       bitmap->buffer += width;
 244 
 245       error = render->raster_render( render->raster, &params );
 246       if ( error )
 247         goto Exit;
 248 
 249       FT_Outline_Translate( outline, -21, 0 );
 250       x_shift        -= 21;
 251       bitmap->buffer += width;
 252 
 253       error = render->raster_render( render->raster, &params );
 254       if ( error )
 255         goto Exit;
 256 
 257       FT_Outline_Translate( outline,  42, 0 );
 258       x_shift        += 42;
 259       bitmap->buffer -= 2 * width;
 260 
 261       error = render->raster_render( render->raster, &params );
 262       if ( error )
 263         goto Exit;
 264 
 265       /* XXX: Rearrange the bytes according to FT_PIXEL_MODE_LCD.    */
 266       /* XXX: It is more efficient to render every third byte above. */
 267 
 268       if ( FT_ALLOC( temp, (FT_ULong)pitch ) )
 269         goto Exit;
 270 
 271       for ( i = 0; i < height; i++ )
 272       {
 273         line = bitmap->buffer + i * (FT_ULong)pitch;
 274         for ( j = 0; j < width; j++ )
 275         {
 276           temp[3 * j    ] = line[j];
 277           temp[3 * j + 1] = line[j + width];
 278           temp[3 * j + 2] = line[j + width + width];
 279         }
 280         FT_MEM_COPY( line, temp, pitch );
 281       }
 282 
 283       FT_FREE( temp );
 284     }
 285     else if ( vmul )  /* lcd_v */
 286     {
 287       int  pitch  = bitmap->pitch;
 288 
 289 
 290       /* Render 3 separate monochrome bitmaps, shifting the outline  */
 291       /* by 1/3 pixel. Triple the pitch to render on each third row. */
 292       bitmap->pitch *= 3;
 293       bitmap->rows  /= 3;
 294 
 295       bitmap->buffer += pitch;
 296 
 297       error = render->raster_render( render->raster, &params );
 298       if ( error )
 299         goto Exit;
 300 
 301       FT_Outline_Translate( outline, 0,  21 );
 302       y_shift        += 21;
 303       bitmap->buffer += pitch;
 304 
 305       error = render->raster_render( render->raster, &params );
 306       if ( error )
 307         goto Exit;
 308 
 309       FT_Outline_Translate( outline, 0, -42 );
 310       y_shift        -= 42;
 311       bitmap->buffer -= 2 * pitch;
 312 
 313       error = render->raster_render( render->raster, &params );
 314       if ( error )
 315         goto Exit;
 316 
 317       bitmap->pitch /= 3;
 318       bitmap->rows  *= 3;
 319     }
 320     else  /* grayscale */
 321       error = render->raster_render( render->raster, &params );
 322 
 323 #endif /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
 324 
 325   Exit:
 326     if ( !error )
 327     {
 328       /* everything is fine; the glyph is now officially a bitmap */
 329       slot->format = FT_GLYPH_FORMAT_BITMAP;
 330     }
 331     else if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
 332     {
 333       FT_FREE( bitmap->buffer );
 334       slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
 335     }
 336 
 337     if ( x_shift || y_shift )
 338       FT_Outline_Translate( outline, -x_shift, -y_shift );
 339 
 340     return error;
 341   }
 342 
 343 
 344   /* convert a slot's glyph image into a bitmap */
 345   static FT_Error
 346   ft_smooth_render( FT_Renderer       render,
 347                     FT_GlyphSlot      slot,
 348                     FT_Render_Mode    mode,
 349                     const FT_Vector*  origin )
 350   {
 351     if ( mode == FT_RENDER_MODE_LIGHT )
 352       mode = FT_RENDER_MODE_NORMAL;
 353 
 354     return ft_smooth_render_generic( render, slot, mode, origin,
 355                                      FT_RENDER_MODE_NORMAL );
 356   }
 357 
 358 
 359   /* convert a slot's glyph image into a horizontal LCD bitmap */
 360   static FT_Error
 361   ft_smooth_render_lcd( FT_Renderer       render,
 362                         FT_GlyphSlot      slot,
 363                         FT_Render_Mode    mode,
 364                         const FT_Vector*  origin )
 365   {
 366     return ft_smooth_render_generic( render, slot, mode, origin,
 367                                      FT_RENDER_MODE_LCD );
 368   }
 369 
 370 
 371   /* convert a slot's glyph image into a vertical LCD bitmap */
 372   static FT_Error
 373   ft_smooth_render_lcd_v( FT_Renderer       render,
 374                           FT_GlyphSlot      slot,
 375                           FT_Render_Mode    mode,
 376                           const FT_Vector*  origin )
 377   {
 378     return ft_smooth_render_generic( render, slot, mode, origin,
 379                                      FT_RENDER_MODE_LCD_V );
 380   }
 381 
 382 
 383   FT_DEFINE_RENDERER(
 384     ft_smooth_renderer_class,
 385 
 386       FT_MODULE_RENDERER,
 387       sizeof ( FT_RendererRec ),
 388 
 389       "smooth",
 390       0x10000L,
 391       0x20000L,
 392 
 393       NULL,    /* module specific interface */
 394 
 395       (FT_Module_Constructor)ft_smooth_init,  /* module_init   */
 396       (FT_Module_Destructor) NULL,            /* module_done   */
 397       (FT_Module_Requester)  NULL,            /* get_interface */
 398 
 399     FT_GLYPH_FORMAT_OUTLINE,
 400 
 401     (FT_Renderer_RenderFunc)   ft_smooth_render,     /* render_glyph    */
 402     (FT_Renderer_TransformFunc)ft_smooth_transform,  /* transform_glyph */
 403     (FT_Renderer_GetCBoxFunc)  ft_smooth_get_cbox,   /* get_glyph_cbox  */
 404     (FT_Renderer_SetModeFunc)  ft_smooth_set_mode,   /* set_mode        */
 405 
 406     (FT_Raster_Funcs*)&FT_GRAYS_RASTER_GET           /* raster_class    */
 407   )
 408 
 409 
 410   FT_DEFINE_RENDERER(
 411     ft_smooth_lcd_renderer_class,
 412 
 413       FT_MODULE_RENDERER,
 414       sizeof ( FT_RendererRec ),
 415 
 416       "smooth-lcd",
 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_lcd,  /* 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_GET            /* raster_class    */
 434   )
 435 
 436 
 437   FT_DEFINE_RENDERER(
 438     ft_smooth_lcdv_renderer_class,
 439 
 440       FT_MODULE_RENDERER,
 441       sizeof ( FT_RendererRec ),
 442 
 443       "smooth-lcdv",
 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_v,  /* 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_GET              /* raster_class    */
 461   )
 462 
 463 
 464 /* END */