1 /****************************************************************************
   2  *
   3  * ftsmooth.c
   4  *
   5  *   Anti-aliasing renderer interface (body).
   6  *
   7  * Copyright (C) 2000-2019 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 #elif 0   /* or else, once ClearType patents expire */
  48 
  49     FT_Library_SetLcdFilter( render->root.library, FT_LCD_FILTER_DEFAULT );
  50 
  51 #endif
  52 
  53     render->clazz->raster_class->raster_reset( render->raster, NULL, 0 );
  54 
  55     return 0;
  56   }
  57 
  58 
  59   /* sets render-specific mode */
  60   static FT_Error
  61   ft_smooth_set_mode( FT_Renderer  render,
  62                       FT_ULong     mode_tag,
  63                       FT_Pointer   data )
  64   {
  65     /* we simply pass it to the raster */
  66     return render->clazz->raster_class->raster_set_mode( render->raster,
  67                                                          mode_tag,
  68                                                          data );
  69   }
  70 
  71   /* transform a given glyph image */
  72   static FT_Error
  73   ft_smooth_transform( FT_Renderer       render,
  74                        FT_GlyphSlot      slot,
  75                        const FT_Matrix*  matrix,
  76                        const FT_Vector*  delta )
  77   {
  78     FT_Error  error = FT_Err_Ok;
  79 
  80 
  81     if ( slot->format != render->glyph_format )
  82     {
  83       error = FT_THROW( Invalid_Argument );
  84       goto Exit;
  85     }
  86 
  87     if ( matrix )
  88       FT_Outline_Transform( &slot->outline, matrix );
  89 
  90     if ( delta )
  91       FT_Outline_Translate( &slot->outline, delta->x, delta->y );
  92 
  93   Exit:
  94     return error;
  95   }
  96 
  97 
  98   /* return the glyph's control box */
  99   static void
 100   ft_smooth_get_cbox( FT_Renderer   render,
 101                       FT_GlyphSlot  slot,
 102                       FT_BBox*      cbox )
 103   {
 104     FT_ZERO( cbox );
 105 
 106     if ( slot->format == render->glyph_format )
 107       FT_Outline_Get_CBox( &slot->outline, cbox );
 108   }
 109 
 110 
 111   /* convert a slot's glyph image into a bitmap */
 112   static FT_Error
 113   ft_smooth_render_generic( FT_Renderer       render,
 114                             FT_GlyphSlot      slot,
 115                             FT_Render_Mode    mode,
 116                             const FT_Vector*  origin,
 117                             FT_Render_Mode    required_mode )
 118   {
 119     FT_Error     error   = FT_Err_Ok;
 120     FT_Outline*  outline = &slot->outline;
 121     FT_Bitmap*   bitmap  = &slot->bitmap;
 122     FT_Memory    memory  = render->root.memory;
 123     FT_Pos       x_shift = 0;
 124     FT_Pos       y_shift = 0;
 125     FT_Int       hmul    = ( mode == FT_RENDER_MODE_LCD );
 126     FT_Int       vmul    = ( mode == FT_RENDER_MODE_LCD_V );
 127 
 128     FT_Raster_Params  params;
 129 
 130 
 131     /* check glyph image format */
 132     if ( slot->format != render->glyph_format )
 133     {
 134       error = FT_THROW( Invalid_Argument );
 135       goto Exit;
 136     }
 137 
 138     /* check mode */
 139     if ( mode != required_mode )
 140     {
 141       error = FT_THROW( Cannot_Render_Glyph );
 142       goto Exit;
 143     }
 144 
 145     /* release old bitmap buffer */
 146     if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
 147     {
 148       FT_FREE( bitmap->buffer );
 149       slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
 150     }
 151 
 152     if ( ft_glyphslot_preset_bitmap( slot, mode, origin ) )
 153     {
 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, 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,
 268                             -sub[0].x,
 269                             -sub[0].y );
 270       error = render->raster_render( render->raster, &params );
 271       if ( error )
 272         goto Exit;
 273 
 274       bitmap->buffer += width;
 275       FT_Outline_Translate( outline,
 276                             sub[0].x - sub[1].x,
 277                             sub[0].y - sub[1].y );
 278       error = render->raster_render( render->raster, &params );
 279       bitmap->buffer -= width;
 280       if ( error )
 281         goto Exit;
 282 
 283       bitmap->buffer += 2 * width;
 284       FT_Outline_Translate( outline,
 285                             sub[1].x - sub[2].x,
 286                             sub[1].y - sub[2].y );
 287       error = render->raster_render( render->raster, &params );
 288       bitmap->buffer -= 2 * width;
 289       if ( error )
 290         goto Exit;
 291 
 292       x_shift -= sub[2].x;
 293       y_shift -= sub[2].y;
 294 
 295       /* XXX: Rearrange the bytes according to FT_PIXEL_MODE_LCD.    */
 296       /* XXX: It is more efficient to render every third byte above. */
 297 
 298       if ( FT_ALLOC( temp, (FT_ULong)pitch ) )
 299         goto Exit;
 300 
 301       for ( i = 0; i < height; i++ )
 302       {
 303         line = bitmap->buffer + i * (FT_ULong)pitch;
 304         for ( j = 0; j < width; j++ )
 305         {
 306           temp[3 * j    ] = line[j];
 307           temp[3 * j + 1] = line[j + width];
 308           temp[3 * j + 2] = line[j + width + width];
 309         }
 310         FT_MEM_COPY( line, temp, pitch );
 311       }
 312 
 313       FT_FREE( temp );
 314     }
 315     else if ( vmul )  /* lcd_v */
 316     {
 317       int  pitch  = bitmap->pitch;
 318 
 319       FT_Vector*  sub = slot->library->lcd_geometry;
 320 
 321 
 322       /* Render 3 separate monochrome bitmaps, shifting the outline. */
 323       /* Notice that the subpixel geometry vectors are rotated.      */
 324       /* Triple the pitch to render on each third row.               */
 325       bitmap->pitch *= 3;
 326       bitmap->rows  /= 3;
 327 
 328       FT_Outline_Translate( outline,
 329                             -sub[0].y,
 330                             sub[0].x );
 331       error = render->raster_render( render->raster, &params );
 332       if ( error )
 333         goto Exit;
 334 
 335       bitmap->buffer += pitch;
 336       FT_Outline_Translate( outline,
 337                             sub[0].y - sub[1].y,
 338                             sub[1].x - sub[0].x );
 339       error = render->raster_render( render->raster, &params );
 340       bitmap->buffer -= pitch;
 341       if ( error )
 342         goto Exit;
 343 
 344       bitmap->buffer += 2 * pitch;
 345       FT_Outline_Translate( outline,
 346                             sub[1].y - sub[2].y,
 347                             sub[2].x - sub[1].x );
 348       error = render->raster_render( render->raster, &params );
 349       bitmap->buffer -= 2 * pitch;
 350       if ( error )
 351         goto Exit;
 352 
 353       x_shift -= sub[2].y;
 354       y_shift += sub[2].x;
 355 
 356       bitmap->pitch /= 3;
 357       bitmap->rows  *= 3;
 358     }
 359     else  /* grayscale */
 360       error = render->raster_render( render->raster, &params );
 361 
 362 #endif /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
 363 
 364   Exit:
 365     if ( !error )
 366     {
 367       /* everything is fine; the glyph is now officially a bitmap */
 368       slot->format = FT_GLYPH_FORMAT_BITMAP;
 369     }
 370     else if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
 371     {
 372       FT_FREE( bitmap->buffer );
 373       slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
 374     }
 375 
 376     if ( x_shift || y_shift )
 377       FT_Outline_Translate( outline, -x_shift, -y_shift );
 378 
 379     return error;
 380   }
 381 
 382 
 383   /* convert a slot's glyph image into a bitmap */
 384   static FT_Error
 385   ft_smooth_render( FT_Renderer       render,
 386                     FT_GlyphSlot      slot,
 387                     FT_Render_Mode    mode,
 388                     const FT_Vector*  origin )
 389   {
 390     if ( mode == FT_RENDER_MODE_LIGHT )
 391       mode = FT_RENDER_MODE_NORMAL;
 392 
 393     return ft_smooth_render_generic( render, slot, mode, origin,
 394                                      FT_RENDER_MODE_NORMAL );
 395   }
 396 
 397 
 398   /* convert a slot's glyph image into a horizontal LCD bitmap */
 399   static FT_Error
 400   ft_smooth_render_lcd( 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 );
 407   }
 408 
 409 
 410   /* convert a slot's glyph image into a vertical LCD bitmap */
 411   static FT_Error
 412   ft_smooth_render_lcd_v( FT_Renderer       render,
 413                           FT_GlyphSlot      slot,
 414                           FT_Render_Mode    mode,
 415                           const FT_Vector*  origin )
 416   {
 417     return ft_smooth_render_generic( render, slot, mode, origin,
 418                                      FT_RENDER_MODE_LCD_V );
 419   }
 420 
 421 
 422   FT_DEFINE_RENDERER(
 423     ft_smooth_renderer_class,
 424 
 425       FT_MODULE_RENDERER,
 426       sizeof ( FT_RendererRec ),
 427 
 428       "smooth",
 429       0x10000L,
 430       0x20000L,
 431 
 432       NULL,    /* module specific interface */
 433 
 434       (FT_Module_Constructor)ft_smooth_init,  /* module_init   */
 435       (FT_Module_Destructor) NULL,            /* module_done   */
 436       (FT_Module_Requester)  NULL,            /* get_interface */
 437 
 438     FT_GLYPH_FORMAT_OUTLINE,
 439 
 440     (FT_Renderer_RenderFunc)   ft_smooth_render,     /* render_glyph    */
 441     (FT_Renderer_TransformFunc)ft_smooth_transform,  /* transform_glyph */
 442     (FT_Renderer_GetCBoxFunc)  ft_smooth_get_cbox,   /* get_glyph_cbox  */
 443     (FT_Renderer_SetModeFunc)  ft_smooth_set_mode,   /* set_mode        */
 444 
 445     (FT_Raster_Funcs*)&ft_grays_raster               /* raster_class    */
 446   )
 447 
 448 
 449   FT_DEFINE_RENDERER(
 450     ft_smooth_lcd_renderer_class,
 451 
 452       FT_MODULE_RENDERER,
 453       sizeof ( FT_RendererRec ),
 454 
 455       "smooth-lcd",
 456       0x10000L,
 457       0x20000L,
 458 
 459       NULL,    /* module specific interface */
 460 
 461       (FT_Module_Constructor)ft_smooth_init,  /* module_init   */
 462       (FT_Module_Destructor) NULL,            /* module_done   */
 463       (FT_Module_Requester)  NULL,            /* get_interface */
 464 
 465     FT_GLYPH_FORMAT_OUTLINE,
 466 
 467     (FT_Renderer_RenderFunc)   ft_smooth_render_lcd,  /* render_glyph    */
 468     (FT_Renderer_TransformFunc)ft_smooth_transform,   /* transform_glyph */
 469     (FT_Renderer_GetCBoxFunc)  ft_smooth_get_cbox,    /* get_glyph_cbox  */
 470     (FT_Renderer_SetModeFunc)  ft_smooth_set_mode,    /* set_mode        */
 471 
 472     (FT_Raster_Funcs*)&ft_grays_raster                /* raster_class    */
 473   )
 474 
 475 
 476   FT_DEFINE_RENDERER(
 477     ft_smooth_lcdv_renderer_class,
 478 
 479       FT_MODULE_RENDERER,
 480       sizeof ( FT_RendererRec ),
 481 
 482       "smooth-lcdv",
 483       0x10000L,
 484       0x20000L,
 485 
 486       NULL,    /* module specific interface */
 487 
 488       (FT_Module_Constructor)ft_smooth_init,  /* module_init   */
 489       (FT_Module_Destructor) NULL,            /* module_done   */
 490       (FT_Module_Requester)  NULL,            /* get_interface */
 491 
 492     FT_GLYPH_FORMAT_OUTLINE,
 493 
 494     (FT_Renderer_RenderFunc)   ft_smooth_render_lcd_v,  /* render_glyph    */
 495     (FT_Renderer_TransformFunc)ft_smooth_transform,     /* transform_glyph */
 496     (FT_Renderer_GetCBoxFunc)  ft_smooth_get_cbox,      /* get_glyph_cbox  */
 497     (FT_Renderer_SetModeFunc)  ft_smooth_set_mode,      /* set_mode        */
 498 
 499     (FT_Raster_Funcs*)&ft_grays_raster                  /* raster_class    */
 500   )
 501 
 502 
 503 /* END */