1 /****************************************************************************
   2  *
   3  * ftsmooth.c
   4  *
   5  *   Anti-aliasing renderer interface (body).
   6  *
   7  * Copyright (C) 2000-2020 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     if ( !bitmap->rows || !bitmap->pitch )
 159       goto Exit;
 160 
 161     /* allocate new one */
 162     if ( FT_ALLOC_MULT( bitmap->buffer, bitmap->rows, bitmap->pitch ) )
 163       goto Exit;
 164 
 165     slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
 166 
 167     x_shift = 64 * -slot->bitmap_left;
 168     y_shift = 64 * -slot->bitmap_top;
 169     if ( bitmap->pixel_mode == FT_PIXEL_MODE_LCD_V )
 170       y_shift += 64 * (FT_Int)bitmap->rows / 3;
 171     else
 172       y_shift += 64 * (FT_Int)bitmap->rows;
 173 
 174     if ( origin )
 175     {
 176       x_shift += origin->x;
 177       y_shift += origin->y;
 178     }
 179 
 180     /* translate outline to render it into the bitmap */
 181     if ( x_shift || y_shift )
 182       FT_Outline_Translate( outline, x_shift, y_shift );
 183 
 184     /* set up parameters */
 185     params.target = bitmap;
 186     params.source = outline;
 187     params.flags  = FT_RASTER_FLAG_AA;
 188 
 189 #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
 190 
 191     /* implode outline if needed */
 192     {
 193       FT_Vector*  points     = outline->points;
 194       FT_Vector*  points_end = FT_OFFSET( points, outline->n_points );
 195       FT_Vector*  vec;
 196 
 197 
 198       if ( hmul )
 199         for ( vec = points; vec < points_end; vec++ )
 200           vec->x *= 3;
 201 
 202       if ( vmul )
 203         for ( vec = points; vec < points_end; vec++ )
 204           vec->y *= 3;
 205     }
 206 
 207     /* render outline into the bitmap */
 208     error = render->raster_render( render->raster, &params );
 209 
 210     /* deflate outline if needed */
 211     {
 212       FT_Vector*  points     = outline->points;
 213       FT_Vector*  points_end = FT_OFFSET( points, outline->n_points );
 214       FT_Vector*  vec;
 215 
 216 
 217       if ( hmul )
 218         for ( vec = points; vec < points_end; vec++ )
 219           vec->x /= 3;
 220 
 221       if ( vmul )
 222         for ( vec = points; vec < points_end; vec++ )
 223           vec->y /= 3;
 224     }
 225 
 226     if ( error )
 227       goto Exit;
 228 
 229     /* finally apply filtering */
 230     if ( hmul || vmul )
 231     {
 232       FT_Byte*                 lcd_weights;
 233       FT_Bitmap_LcdFilterFunc  lcd_filter_func;
 234 
 235 
 236       /* Per-face LCD filtering takes priority if set up. */
 237       if ( slot->face && slot->face->internal->lcd_filter_func )
 238       {
 239         lcd_weights     = slot->face->internal->lcd_weights;
 240         lcd_filter_func = slot->face->internal->lcd_filter_func;
 241       }
 242       else
 243       {
 244         lcd_weights     = slot->library->lcd_weights;
 245         lcd_filter_func = slot->library->lcd_filter_func;
 246       }
 247 
 248       if ( lcd_filter_func )
 249         lcd_filter_func( bitmap, lcd_weights );
 250     }
 251 
 252 #else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
 253 
 254     if ( hmul )  /* lcd */
 255     {
 256       FT_Byte*  line;
 257       FT_Byte*  temp = NULL;
 258       FT_UInt   i, j;
 259 
 260       unsigned int  height = bitmap->rows;
 261       unsigned int  width  = bitmap->width;
 262       int           pitch  = bitmap->pitch;
 263 
 264       FT_Vector*  sub = slot->library->lcd_geometry;
 265 
 266 
 267       /* Render 3 separate monochrome bitmaps, shifting the outline.  */
 268       width /= 3;
 269 
 270       FT_Outline_Translate( outline,
 271                             -sub[0].x,
 272                             -sub[0].y );
 273       error = render->raster_render( render->raster, &params );
 274       if ( error )
 275         goto Exit;
 276 
 277       bitmap->buffer += width;
 278       FT_Outline_Translate( outline,
 279                             sub[0].x - sub[1].x,
 280                             sub[0].y - sub[1].y );
 281       error = render->raster_render( render->raster, &params );
 282       bitmap->buffer -= width;
 283       if ( error )
 284         goto Exit;
 285 
 286       bitmap->buffer += 2 * width;
 287       FT_Outline_Translate( outline,
 288                             sub[1].x - sub[2].x,
 289                             sub[1].y - sub[2].y );
 290       error = render->raster_render( render->raster, &params );
 291       bitmap->buffer -= 2 * width;
 292       if ( error )
 293         goto Exit;
 294 
 295       x_shift -= sub[2].x;
 296       y_shift -= sub[2].y;
 297 
 298       /* XXX: Rearrange the bytes according to FT_PIXEL_MODE_LCD.    */
 299       /* XXX: It is more efficient to render every third byte above. */
 300 
 301       if ( FT_ALLOC( temp, (FT_ULong)pitch ) )
 302         goto Exit;
 303 
 304       for ( i = 0; i < height; i++ )
 305       {
 306         line = bitmap->buffer + i * (FT_ULong)pitch;
 307         for ( j = 0; j < width; j++ )
 308         {
 309           temp[3 * j    ] = line[j];
 310           temp[3 * j + 1] = line[j + width];
 311           temp[3 * j + 2] = line[j + width + width];
 312         }
 313         FT_MEM_COPY( line, temp, pitch );
 314       }
 315 
 316       FT_FREE( temp );
 317     }
 318     else if ( vmul )  /* lcd_v */
 319     {
 320       int  pitch  = bitmap->pitch;
 321 
 322       FT_Vector*  sub = slot->library->lcd_geometry;
 323 
 324 
 325       /* Render 3 separate monochrome bitmaps, shifting the outline. */
 326       /* Notice that the subpixel geometry vectors are rotated.      */
 327       /* Triple the pitch to render on each third row.               */
 328       bitmap->pitch *= 3;
 329       bitmap->rows  /= 3;
 330 
 331       FT_Outline_Translate( outline,
 332                             -sub[0].y,
 333                             sub[0].x );
 334       error = render->raster_render( render->raster, &params );
 335       if ( error )
 336         goto Exit;
 337 
 338       bitmap->buffer += pitch;
 339       FT_Outline_Translate( outline,
 340                             sub[0].y - sub[1].y,
 341                             sub[1].x - sub[0].x );
 342       error = render->raster_render( render->raster, &params );
 343       bitmap->buffer -= pitch;
 344       if ( error )
 345         goto Exit;
 346 
 347       bitmap->buffer += 2 * pitch;
 348       FT_Outline_Translate( outline,
 349                             sub[1].y - sub[2].y,
 350                             sub[2].x - sub[1].x );
 351       error = render->raster_render( render->raster, &params );
 352       bitmap->buffer -= 2 * pitch;
 353       if ( error )
 354         goto Exit;
 355 
 356       x_shift -= sub[2].y;
 357       y_shift += sub[2].x;
 358 
 359       bitmap->pitch /= 3;
 360       bitmap->rows  *= 3;
 361     }
 362     else  /* grayscale */
 363       error = render->raster_render( render->raster, &params );
 364 
 365 #endif /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
 366 
 367   Exit:
 368     if ( !error )
 369     {
 370       /* everything is fine; the glyph is now officially a bitmap */
 371       slot->format = FT_GLYPH_FORMAT_BITMAP;
 372     }
 373     else if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
 374     {
 375       FT_FREE( bitmap->buffer );
 376       slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
 377     }
 378 
 379     if ( x_shift || y_shift )
 380       FT_Outline_Translate( outline, -x_shift, -y_shift );
 381 
 382     return error;
 383   }
 384 
 385 
 386   /* convert a slot's glyph image into a bitmap */
 387   static FT_Error
 388   ft_smooth_render( FT_Renderer       render,
 389                     FT_GlyphSlot      slot,
 390                     FT_Render_Mode    mode,
 391                     const FT_Vector*  origin )
 392   {
 393     if ( mode == FT_RENDER_MODE_LIGHT )
 394       mode = FT_RENDER_MODE_NORMAL;
 395 
 396     return ft_smooth_render_generic( render, slot, mode, origin,
 397                                      FT_RENDER_MODE_NORMAL );
 398   }
 399 
 400 
 401   /* convert a slot's glyph image into a horizontal LCD bitmap */
 402   static FT_Error
 403   ft_smooth_render_lcd( FT_Renderer       render,
 404                         FT_GlyphSlot      slot,
 405                         FT_Render_Mode    mode,
 406                         const FT_Vector*  origin )
 407   {
 408     return ft_smooth_render_generic( render, slot, mode, origin,
 409                                      FT_RENDER_MODE_LCD );
 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     return ft_smooth_render_generic( render, slot, mode, origin,
 421                                      FT_RENDER_MODE_LCD_V );
 422   }
 423 
 424 
 425   FT_DEFINE_RENDERER(
 426     ft_smooth_renderer_class,
 427 
 428       FT_MODULE_RENDERER,
 429       sizeof ( FT_RendererRec ),
 430 
 431       "smooth",
 432       0x10000L,
 433       0x20000L,
 434 
 435       NULL,    /* module specific interface */
 436 
 437       (FT_Module_Constructor)ft_smooth_init,  /* module_init   */
 438       (FT_Module_Destructor) NULL,            /* module_done   */
 439       (FT_Module_Requester)  NULL,            /* get_interface */
 440 
 441     FT_GLYPH_FORMAT_OUTLINE,
 442 
 443     (FT_Renderer_RenderFunc)   ft_smooth_render,     /* render_glyph    */
 444     (FT_Renderer_TransformFunc)ft_smooth_transform,  /* transform_glyph */
 445     (FT_Renderer_GetCBoxFunc)  ft_smooth_get_cbox,   /* get_glyph_cbox  */
 446     (FT_Renderer_SetModeFunc)  ft_smooth_set_mode,   /* set_mode        */
 447 
 448     (FT_Raster_Funcs*)&ft_grays_raster               /* raster_class    */
 449   )
 450 
 451 
 452   FT_DEFINE_RENDERER(
 453     ft_smooth_lcd_renderer_class,
 454 
 455       FT_MODULE_RENDERER,
 456       sizeof ( FT_RendererRec ),
 457 
 458       "smooth-lcd",
 459       0x10000L,
 460       0x20000L,
 461 
 462       NULL,    /* module specific interface */
 463 
 464       (FT_Module_Constructor)ft_smooth_init,  /* module_init   */
 465       (FT_Module_Destructor) NULL,            /* module_done   */
 466       (FT_Module_Requester)  NULL,            /* get_interface */
 467 
 468     FT_GLYPH_FORMAT_OUTLINE,
 469 
 470     (FT_Renderer_RenderFunc)   ft_smooth_render_lcd,  /* render_glyph    */
 471     (FT_Renderer_TransformFunc)ft_smooth_transform,   /* transform_glyph */
 472     (FT_Renderer_GetCBoxFunc)  ft_smooth_get_cbox,    /* get_glyph_cbox  */
 473     (FT_Renderer_SetModeFunc)  ft_smooth_set_mode,    /* set_mode        */
 474 
 475     (FT_Raster_Funcs*)&ft_grays_raster                /* raster_class    */
 476   )
 477 
 478 
 479   FT_DEFINE_RENDERER(
 480     ft_smooth_lcdv_renderer_class,
 481 
 482       FT_MODULE_RENDERER,
 483       sizeof ( FT_RendererRec ),
 484 
 485       "smooth-lcdv",
 486       0x10000L,
 487       0x20000L,
 488 
 489       NULL,    /* module specific interface */
 490 
 491       (FT_Module_Constructor)ft_smooth_init,  /* module_init   */
 492       (FT_Module_Destructor) NULL,            /* module_done   */
 493       (FT_Module_Requester)  NULL,            /* get_interface */
 494 
 495     FT_GLYPH_FORMAT_OUTLINE,
 496 
 497     (FT_Renderer_RenderFunc)   ft_smooth_render_lcd_v,  /* render_glyph    */
 498     (FT_Renderer_TransformFunc)ft_smooth_transform,     /* transform_glyph */
 499     (FT_Renderer_GetCBoxFunc)  ft_smooth_get_cbox,      /* get_glyph_cbox  */
 500     (FT_Renderer_SetModeFunc)  ft_smooth_set_mode,      /* set_mode        */
 501 
 502     (FT_Raster_Funcs*)&ft_grays_raster                  /* raster_class    */
 503   )
 504 
 505 
 506 /* END */