| 1 | /**************************************************************************** | 
| 2 |  * | 
| 3 |  * ftsmooth.c | 
| 4 |  * | 
| 5 |  *   Anti-aliasing renderer interface (body). | 
| 6 |  * | 
| 7 |  * Copyright (C) 2000-2023 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 <freetype/internal/ftdebug.h> | 
| 20 | #include <freetype/internal/ftobjs.h> | 
| 21 | #include <freetype/ftoutln.h> | 
| 22 | #include "ftsmooth.h" | 
| 23 | #include "ftgrays.h" | 
| 24 |  | 
| 25 | #include "ftsmerrs.h" | 
| 26 |  | 
| 27 |  | 
| 28 |   /* sets render-specific mode */ | 
| 29 |   static FT_Error | 
| 30 |   ft_smooth_set_mode( FT_Renderer  render, | 
| 31 |                       FT_ULong     mode_tag, | 
| 32 |                       FT_Pointer   data ) | 
| 33 |   { | 
| 34 |     /* we simply pass it to the raster */ | 
| 35 |     return render->clazz->raster_class->raster_set_mode( render->raster, | 
| 36 |                                                          mode_tag, | 
| 37 |                                                          data ); | 
| 38 |   } | 
| 39 |  | 
| 40 |   /* transform a given glyph image */ | 
| 41 |   static FT_Error | 
| 42 |   ft_smooth_transform( FT_Renderer       render, | 
| 43 |                        FT_GlyphSlot      slot, | 
| 44 |                        const FT_Matrix*  matrix, | 
| 45 |                        const FT_Vector*  delta ) | 
| 46 |   { | 
| 47 |     FT_Error  error = FT_Err_Ok; | 
| 48 |  | 
| 49 |  | 
| 50 |     if ( slot->format != render->glyph_format ) | 
| 51 |     { | 
| 52 |       error = FT_THROW( Invalid_Argument ); | 
| 53 |       goto Exit; | 
| 54 |     } | 
| 55 |  | 
| 56 |     if ( matrix ) | 
| 57 |       FT_Outline_Transform( &slot->outline, matrix ); | 
| 58 |  | 
| 59 |     if ( delta ) | 
| 60 |       FT_Outline_Translate( &slot->outline, delta->x, delta->y ); | 
| 61 |  | 
| 62 |   Exit: | 
| 63 |     return error; | 
| 64 |   } | 
| 65 |  | 
| 66 |  | 
| 67 |   /* return the glyph's control box */ | 
| 68 |   static void | 
| 69 |   ft_smooth_get_cbox( FT_Renderer   render, | 
| 70 |                       FT_GlyphSlot  slot, | 
| 71 |                       FT_BBox*      cbox ) | 
| 72 |   { | 
| 73 |     FT_ZERO( cbox ); | 
| 74 |  | 
| 75 |     if ( slot->format == render->glyph_format ) | 
| 76 |       FT_Outline_Get_CBox( &slot->outline, cbox ); | 
| 77 |   } | 
| 78 |  | 
| 79 |   typedef struct TOrigin_ | 
| 80 |   { | 
| 81 |     unsigned char*  origin;  /* pixmap origin at the bottom-left */ | 
| 82 |     int             pitch;   /* pitch to go down one row */ | 
| 83 |  | 
| 84 |   } TOrigin; | 
| 85 |  | 
| 86 | #ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING | 
| 87 |  | 
| 88 |   /* initialize renderer -- init its raster */ | 
| 89 |   static FT_Error | 
| 90 |   ft_smooth_init( FT_Module  module )   /* FT_Renderer */ | 
| 91 |   { | 
| 92 |     FT_Renderer  render = (FT_Renderer)module; | 
| 93 |  | 
| 94 |     FT_Vector*  sub = render->root.library->lcd_geometry; | 
| 95 |  | 
| 96 |  | 
| 97 |     /* set up default subpixel geometry for striped RGB panels. */ | 
| 98 |     sub[0].x = -21; | 
| 99 |     sub[0].y = 0; | 
| 100 |     sub[1].x = 0; | 
| 101 |     sub[1].y = 0; | 
| 102 |     sub[2].x = 21; | 
| 103 |     sub[2].y = 0; | 
| 104 |  | 
| 105 |     render->clazz->raster_class->raster_reset( render->raster, NULL, 0 ); | 
| 106 |  | 
| 107 |     return 0; | 
| 108 |   } | 
| 109 |  | 
| 110 |  | 
| 111 |   /* This function writes every third byte in direct rendering mode */ | 
| 112 |   static void | 
| 113 |   ft_smooth_lcd_spans( int             y, | 
| 114 |                        int             count, | 
| 115 |                        const FT_Span*  spans, | 
| 116 |                        void*           target_ )   /* TOrigin* */ | 
| 117 |   { | 
| 118 |     TOrigin*  target = (TOrigin*)target_; | 
| 119 |  | 
| 120 |     unsigned char*  dst_line = target->origin - y * target->pitch; | 
| 121 |     unsigned char*  dst; | 
| 122 |     unsigned short  w; | 
| 123 |  | 
| 124 |  | 
| 125 |     for ( ; count--; spans++ ) | 
| 126 |       for ( dst = dst_line + spans->x * 3, w = spans->len; w--; dst += 3 ) | 
| 127 |         *dst = spans->coverage; | 
| 128 |   } | 
| 129 |  | 
| 130 |  | 
| 131 |   static FT_Error | 
| 132 |   ft_smooth_raster_lcd( FT_Renderer  render, | 
| 133 |                         FT_Outline*  outline, | 
| 134 |                         FT_Bitmap*   bitmap ) | 
| 135 |   { | 
| 136 |     FT_Error      error = FT_Err_Ok; | 
| 137 |     FT_Vector*    sub   = render->root.library->lcd_geometry; | 
| 138 |     FT_Pos        x, y; | 
| 139 |  | 
| 140 |     FT_Raster_Params   params; | 
| 141 |     TOrigin            target; | 
| 142 |  | 
| 143 |  | 
| 144 |     /* Render 3 separate coverage bitmaps, shifting the outline.  */ | 
| 145 |     /* Set up direct rendering to record them on each third byte. */ | 
| 146 |     params.source     = outline; | 
| 147 |     params.flags      = FT_RASTER_FLAG_AA | FT_RASTER_FLAG_DIRECT; | 
| 148 |     params.gray_spans = ft_smooth_lcd_spans; | 
| 149 |     params.user       = ⌖ | 
| 150 |  | 
| 151 |     params.clip_box.xMin = 0; | 
| 152 |     params.clip_box.yMin = 0; | 
| 153 |     params.clip_box.xMax = bitmap->width; | 
| 154 |     params.clip_box.yMax = bitmap->rows; | 
| 155 |  | 
| 156 |     if ( bitmap->pitch < 0 ) | 
| 157 |       target.origin = bitmap->buffer; | 
| 158 |     else | 
| 159 |       target.origin = bitmap->buffer | 
| 160 |                       + ( bitmap->rows - 1 ) * (unsigned int)bitmap->pitch; | 
| 161 |  | 
| 162 |     target.pitch = bitmap->pitch; | 
| 163 |  | 
| 164 |     FT_Outline_Translate( outline, | 
| 165 |                           -sub[0].x, | 
| 166 |                           -sub[0].y ); | 
| 167 |     error = render->raster_render( render->raster, ¶ms ); | 
| 168 |     x = sub[0].x; | 
| 169 |     y = sub[0].y; | 
| 170 |     if ( error ) | 
| 171 |       goto Exit; | 
| 172 |  | 
| 173 |     target.origin++; | 
| 174 |     FT_Outline_Translate( outline, | 
| 175 |                           sub[0].x - sub[1].x, | 
| 176 |                           sub[0].y - sub[1].y ); | 
| 177 |     error = render->raster_render( render->raster, ¶ms ); | 
| 178 |     x = sub[1].x; | 
| 179 |     y = sub[1].y; | 
| 180 |     if ( error ) | 
| 181 |       goto Exit; | 
| 182 |  | 
| 183 |     target.origin++; | 
| 184 |     FT_Outline_Translate( outline, | 
| 185 |                           sub[1].x - sub[2].x, | 
| 186 |                           sub[1].y - sub[2].y ); | 
| 187 |     error = render->raster_render( render->raster, ¶ms ); | 
| 188 |     x = sub[2].x; | 
| 189 |     y = sub[2].y; | 
| 190 |  | 
| 191 |   Exit: | 
| 192 |     FT_Outline_Translate( outline, x, y ); | 
| 193 |  | 
| 194 |     return error; | 
| 195 |   } | 
| 196 |  | 
| 197 |  | 
| 198 |   static FT_Error | 
| 199 |   ft_smooth_raster_lcdv( FT_Renderer  render, | 
| 200 |                          FT_Outline*  outline, | 
| 201 |                          FT_Bitmap*   bitmap ) | 
| 202 |   { | 
| 203 |     FT_Error     error = FT_Err_Ok; | 
| 204 |     int          pitch = bitmap->pitch; | 
| 205 |     FT_Vector*   sub   = render->root.library->lcd_geometry; | 
| 206 |     FT_Pos       x, y; | 
| 207 |  | 
| 208 |     FT_Raster_Params  params; | 
| 209 |  | 
| 210 |  | 
| 211 |     params.target = bitmap; | 
| 212 |     params.source = outline; | 
| 213 |     params.flags  = FT_RASTER_FLAG_AA; | 
| 214 |  | 
| 215 |     /* Render 3 separate coverage bitmaps, shifting the outline. */ | 
| 216 |     /* Notice that the subpixel geometry vectors are rotated.    */ | 
| 217 |     /* Triple the pitch to render on each third row.            */ | 
| 218 |     bitmap->pitch *= 3; | 
| 219 |     bitmap->rows  /= 3; | 
| 220 |  | 
| 221 |     FT_Outline_Translate( outline, | 
| 222 |                           -sub[0].y, | 
| 223 |                           sub[0].x ); | 
| 224 |     error = render->raster_render( render->raster, ¶ms ); | 
| 225 |     x = sub[0].y; | 
| 226 |     y = -sub[0].x; | 
| 227 |     if ( error ) | 
| 228 |       goto Exit; | 
| 229 |  | 
| 230 |     bitmap->buffer += pitch; | 
| 231 |     FT_Outline_Translate( outline, | 
| 232 |                           sub[0].y - sub[1].y, | 
| 233 |                           sub[1].x - sub[0].x ); | 
| 234 |     error = render->raster_render( render->raster, ¶ms ); | 
| 235 |     x = sub[1].y; | 
| 236 |     y = -sub[1].x; | 
| 237 |     bitmap->buffer -= pitch; | 
| 238 |     if ( error ) | 
| 239 |       goto Exit; | 
| 240 |  | 
| 241 |     bitmap->buffer += 2 * pitch; | 
| 242 |     FT_Outline_Translate( outline, | 
| 243 |                           sub[1].y - sub[2].y, | 
| 244 |                           sub[2].x - sub[1].x ); | 
| 245 |     error = render->raster_render( render->raster, ¶ms ); | 
| 246 |     x = sub[2].y; | 
| 247 |     y = -sub[2].x; | 
| 248 |     bitmap->buffer -= 2 * pitch; | 
| 249 |  | 
| 250 |   Exit: | 
| 251 |     FT_Outline_Translate( outline, x, y ); | 
| 252 |  | 
| 253 |     bitmap->pitch /= 3; | 
| 254 |     bitmap->rows  *= 3; | 
| 255 |  | 
| 256 |     return error; | 
| 257 |   } | 
| 258 |  | 
| 259 | #else   /* FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ | 
| 260 |  | 
| 261 |   /* initialize renderer -- init its raster */ | 
| 262 |   static FT_Error | 
| 263 |   ft_smooth_init( FT_Module  module )   /* FT_Renderer */ | 
| 264 |   { | 
| 265 |     FT_Renderer  render = (FT_Renderer)module; | 
| 266 |  | 
| 267 |  | 
| 268 |     /* set up default LCD filtering */ | 
| 269 |     FT_Library_SetLcdFilter( render->root.library, FT_LCD_FILTER_DEFAULT ); | 
| 270 |  | 
| 271 |     render->clazz->raster_class->raster_reset( render->raster, NULL, 0 ); | 
| 272 |  | 
| 273 |     return 0; | 
| 274 |   } | 
| 275 |  | 
| 276 |  | 
| 277 |   static FT_Error | 
| 278 |   ft_smooth_raster_lcd( FT_Renderer  render, | 
| 279 |                         FT_Outline*  outline, | 
| 280 |                         FT_Bitmap*   bitmap ) | 
| 281 |   { | 
| 282 |     FT_Error    error      = FT_Err_Ok; | 
| 283 |     FT_Vector*  points     = outline->points; | 
| 284 |     FT_Vector*  points_end = FT_OFFSET( points, outline->n_points ); | 
| 285 |     FT_Vector*  vec; | 
| 286 |  | 
| 287 |     FT_Raster_Params  params; | 
| 288 |  | 
| 289 |  | 
| 290 |     params.target = bitmap; | 
| 291 |     params.source = outline; | 
| 292 |     params.flags  = FT_RASTER_FLAG_AA; | 
| 293 |  | 
| 294 |     /* implode outline */ | 
| 295 |     for ( vec = points; vec < points_end; vec++ ) | 
| 296 |       vec->x *= 3; | 
| 297 |  | 
| 298 |     /* render outline into the bitmap */ | 
| 299 |     error = render->raster_render( render->raster, ¶ms ); | 
| 300 |  | 
| 301 |     /* deflate outline */ | 
| 302 |     for ( vec = points; vec < points_end; vec++ ) | 
| 303 |       vec->x /= 3; | 
| 304 |  | 
| 305 |     return error; | 
| 306 |   } | 
| 307 |  | 
| 308 |  | 
| 309 |   static FT_Error | 
| 310 |   ft_smooth_raster_lcdv( FT_Renderer  render, | 
| 311 |                          FT_Outline*  outline, | 
| 312 |                          FT_Bitmap*   bitmap ) | 
| 313 |   { | 
| 314 |     FT_Error    error      = FT_Err_Ok; | 
| 315 |     FT_Vector*  points     = outline->points; | 
| 316 |     FT_Vector*  points_end = FT_OFFSET( points, outline->n_points ); | 
| 317 |     FT_Vector*  vec; | 
| 318 |  | 
| 319 |     FT_Raster_Params  params; | 
| 320 |  | 
| 321 |  | 
| 322 |     params.target = bitmap; | 
| 323 |     params.source = outline; | 
| 324 |     params.flags  = FT_RASTER_FLAG_AA; | 
| 325 |  | 
| 326 |     /* implode outline */ | 
| 327 |     for ( vec = points; vec < points_end; vec++ ) | 
| 328 |       vec->y *= 3; | 
| 329 |  | 
| 330 |     /* render outline into the bitmap */ | 
| 331 |     error = render->raster_render( render->raster, ¶ms ); | 
| 332 |  | 
| 333 |     /* deflate outline */ | 
| 334 |     for ( vec = points; vec < points_end; vec++ ) | 
| 335 |       vec->y /= 3; | 
| 336 |  | 
| 337 |     return error; | 
| 338 |   } | 
| 339 |  | 
| 340 | #endif  /* FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ | 
| 341 |  | 
| 342 | /* Oversampling scale to be used in rendering overlaps */ | 
| 343 | #define SCALE  ( 1 << 2 ) | 
| 344 |  | 
| 345 |   /* This function averages inflated spans in direct rendering mode */ | 
| 346 |   static void | 
| 347 |   ft_smooth_overlap_spans( int             y, | 
| 348 |                            int             count, | 
| 349 |                            const FT_Span*  spans, | 
| 350 |                            void*           target_ ) | 
| 351 |   { | 
| 352 |     TOrigin*  target = (TOrigin*)target_; | 
| 353 |  | 
| 354 |  | 
| 355 |     unsigned char*  dst = target->origin - ( y / SCALE ) * target->pitch; | 
| 356 |     unsigned short  x; | 
| 357 |     unsigned int    cover, sum; | 
| 358 |  | 
| 359 |  | 
| 360 |     /* When accumulating the oversampled spans we need to assure that  */ | 
| 361 |     /* fully covered pixels are equal to 255 and do not overflow.      */ | 
| 362 |     /* It is important that the SCALE is a power of 2, each subpixel   */ | 
| 363 |     /* cover can also reach a power of 2 after rounding, and the total */ | 
| 364 |     /* is clamped to 255 when it adds up to 256.                       */ | 
| 365 |     for ( ; count--; spans++ ) | 
| 366 |     { | 
| 367 |       cover = ( spans->coverage + SCALE * SCALE / 2 ) / ( SCALE * SCALE ); | 
| 368 |       for ( x = 0; x < spans->len; x++ ) | 
| 369 |       { | 
| 370 |         sum                           = dst[( spans->x + x ) / SCALE] + cover; | 
| 371 |         dst[( spans->x + x ) / SCALE] = (unsigned char)( sum - ( sum >> 8 ) ); | 
| 372 |       } | 
| 373 |     } | 
| 374 |   } | 
| 375 |  | 
| 376 |  | 
| 377 |   static FT_Error | 
| 378 |   ft_smooth_raster_overlap( FT_Renderer  render, | 
| 379 |                             FT_Outline*  outline, | 
| 380 |                             FT_Bitmap*   bitmap ) | 
| 381 |   { | 
| 382 |     FT_Error    error      = FT_Err_Ok; | 
| 383 |     FT_Vector*  points     = outline->points; | 
| 384 |     FT_Vector*  points_end = FT_OFFSET( points, outline->n_points ); | 
| 385 |     FT_Vector*  vec; | 
| 386 |  | 
| 387 |     FT_Raster_Params   params; | 
| 388 |     TOrigin            target; | 
| 389 |  | 
| 390 |  | 
| 391 |     /* Reject outlines that are too wide for 16-bit FT_Span.       */ | 
| 392 |     /* Other limits are applied upstream with the same error code. */ | 
| 393 |     if ( bitmap->width * SCALE > 0x7FFF ) | 
| 394 |       return FT_THROW( Raster_Overflow ); | 
| 395 |  | 
| 396 |     /* Set up direct rendering to average oversampled spans. */ | 
| 397 |     params.source     = outline; | 
| 398 |     params.flags      = FT_RASTER_FLAG_AA | FT_RASTER_FLAG_DIRECT; | 
| 399 |     params.gray_spans = ft_smooth_overlap_spans; | 
| 400 |     params.user       = ⌖ | 
| 401 |  | 
| 402 |     params.clip_box.xMin = 0; | 
| 403 |     params.clip_box.yMin = 0; | 
| 404 |     params.clip_box.xMax = bitmap->width * SCALE; | 
| 405 |     params.clip_box.yMax = bitmap->rows  * SCALE; | 
| 406 |  | 
| 407 |     if ( bitmap->pitch < 0 ) | 
| 408 |       target.origin = bitmap->buffer; | 
| 409 |     else | 
| 410 |       target.origin = bitmap->buffer | 
| 411 |                       + ( bitmap->rows - 1 ) * (unsigned int)bitmap->pitch; | 
| 412 |  | 
| 413 |     target.pitch = bitmap->pitch; | 
| 414 |  | 
| 415 |     /* inflate outline */ | 
| 416 |     for ( vec = points; vec < points_end; vec++ ) | 
| 417 |     { | 
| 418 |       vec->x *= SCALE; | 
| 419 |       vec->y *= SCALE; | 
| 420 |     } | 
| 421 |  | 
| 422 |     /* render outline into the bitmap */ | 
| 423 |     error = render->raster_render( render->raster, ¶ms ); | 
| 424 |  | 
| 425 |     /* deflate outline */ | 
| 426 |     for ( vec = points; vec < points_end; vec++ ) | 
| 427 |     { | 
| 428 |       vec->x /= SCALE; | 
| 429 |       vec->y /= SCALE; | 
| 430 |     } | 
| 431 |  | 
| 432 |     return error; | 
| 433 |   } | 
| 434 |  | 
| 435 | #undef SCALE | 
| 436 |  | 
| 437 |   static FT_Error | 
| 438 |   ft_smooth_render( FT_Renderer       render, | 
| 439 |                     FT_GlyphSlot      slot, | 
| 440 |                     FT_Render_Mode    mode, | 
| 441 |                     const FT_Vector*  origin ) | 
| 442 |   { | 
| 443 |     FT_Error     error   = FT_Err_Ok; | 
| 444 |     FT_Outline*  outline = &slot->outline; | 
| 445 |     FT_Bitmap*   bitmap  = &slot->bitmap; | 
| 446 |     FT_Memory    memory  = render->root.memory; | 
| 447 |     FT_Pos       x_shift = 0; | 
| 448 |     FT_Pos       y_shift = 0; | 
| 449 |  | 
| 450 |  | 
| 451 |     /* check glyph image format */ | 
| 452 |     if ( slot->format != render->glyph_format ) | 
| 453 |     { | 
| 454 |       error = FT_THROW( Invalid_Argument ); | 
| 455 |       goto Exit; | 
| 456 |     } | 
| 457 |  | 
| 458 |     /* check mode */ | 
| 459 |     if ( mode != FT_RENDER_MODE_NORMAL && | 
| 460 |          mode != FT_RENDER_MODE_LIGHT  && | 
| 461 |          mode != FT_RENDER_MODE_LCD    && | 
| 462 |          mode != FT_RENDER_MODE_LCD_V  ) | 
| 463 |     { | 
| 464 |       error = FT_THROW( Cannot_Render_Glyph ); | 
| 465 |       goto Exit; | 
| 466 |     } | 
| 467 |  | 
| 468 |     /* release old bitmap buffer */ | 
| 469 |     if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) | 
| 470 |     { | 
| 471 |       FT_FREE( bitmap->buffer ); | 
| 472 |       slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; | 
| 473 |     } | 
| 474 |  | 
| 475 |     if ( ft_glyphslot_preset_bitmap( slot, mode, origin ) ) | 
| 476 |     { | 
| 477 |       error = FT_THROW( Raster_Overflow ); | 
| 478 |       goto Exit; | 
| 479 |     } | 
| 480 |  | 
| 481 |     if ( !bitmap->rows || !bitmap->pitch ) | 
| 482 |       goto Exit; | 
| 483 |  | 
| 484 |     /* allocate new one */ | 
| 485 |     if ( FT_ALLOC_MULT( bitmap->buffer, bitmap->rows, bitmap->pitch ) ) | 
| 486 |       goto Exit; | 
| 487 |  | 
| 488 |     slot->internal->flags |= FT_GLYPH_OWN_BITMAP; | 
| 489 |  | 
| 490 |     x_shift = 64 * -slot->bitmap_left; | 
| 491 |     y_shift = 64 * -slot->bitmap_top; | 
| 492 |     if ( bitmap->pixel_mode == FT_PIXEL_MODE_LCD_V ) | 
| 493 |       y_shift += 64 * (FT_Int)bitmap->rows / 3; | 
| 494 |     else | 
| 495 |       y_shift += 64 * (FT_Int)bitmap->rows; | 
| 496 |  | 
| 497 |     if ( origin ) | 
| 498 |     { | 
| 499 |       x_shift += origin->x; | 
| 500 |       y_shift += origin->y; | 
| 501 |     } | 
| 502 |  | 
| 503 |     /* translate outline to render it into the bitmap */ | 
| 504 |     if ( x_shift || y_shift ) | 
| 505 |       FT_Outline_Translate( outline, x_shift, y_shift ); | 
| 506 |  | 
| 507 |     if ( mode == FT_RENDER_MODE_NORMAL || | 
| 508 |          mode == FT_RENDER_MODE_LIGHT  ) | 
| 509 |     { | 
| 510 |       if ( outline->flags & FT_OUTLINE_OVERLAP ) | 
| 511 |         error = ft_smooth_raster_overlap( render, outline, bitmap ); | 
| 512 |       else | 
| 513 |       { | 
| 514 |         FT_Raster_Params  params; | 
| 515 |  | 
| 516 |  | 
| 517 |         params.target = bitmap; | 
| 518 |         params.source = outline; | 
| 519 |         params.flags  = FT_RASTER_FLAG_AA; | 
| 520 |  | 
| 521 |         error = render->raster_render( render->raster, ¶ms ); | 
| 522 |       } | 
| 523 |     } | 
| 524 |     else | 
| 525 |     { | 
| 526 |       if ( mode == FT_RENDER_MODE_LCD ) | 
| 527 |         error = ft_smooth_raster_lcd ( render, outline, bitmap ); | 
| 528 |       else if ( mode == FT_RENDER_MODE_LCD_V ) | 
| 529 |         error = ft_smooth_raster_lcdv( render, outline, bitmap ); | 
| 530 |  | 
| 531 | #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING | 
| 532 |  | 
| 533 |       /* finally apply filtering */ | 
| 534 |       { | 
| 535 |         FT_Byte*                 lcd_weights; | 
| 536 |         FT_Bitmap_LcdFilterFunc  lcd_filter_func; | 
| 537 |  | 
| 538 |  | 
| 539 |         /* Per-face LCD filtering takes priority if set up. */ | 
| 540 |         if ( slot->face && slot->face->internal->lcd_filter_func ) | 
| 541 |         { | 
| 542 |           lcd_weights     = slot->face->internal->lcd_weights; | 
| 543 |           lcd_filter_func = slot->face->internal->lcd_filter_func; | 
| 544 |         } | 
| 545 |         else | 
| 546 |         { | 
| 547 |           lcd_weights     = slot->library->lcd_weights; | 
| 548 |           lcd_filter_func = slot->library->lcd_filter_func; | 
| 549 |         } | 
| 550 |  | 
| 551 |         if ( lcd_filter_func ) | 
| 552 |           lcd_filter_func( bitmap, lcd_weights ); | 
| 553 |       } | 
| 554 |  | 
| 555 | #endif /* FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ | 
| 556 |  | 
| 557 |     } | 
| 558 |  | 
| 559 |   Exit: | 
| 560 |     if ( !error ) | 
| 561 |     { | 
| 562 |       /* everything is fine; the glyph is now officially a bitmap */ | 
| 563 |       slot->format = FT_GLYPH_FORMAT_BITMAP; | 
| 564 |     } | 
| 565 |     else if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) | 
| 566 |     { | 
| 567 |       FT_FREE( bitmap->buffer ); | 
| 568 |       slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; | 
| 569 |     } | 
| 570 |  | 
| 571 |     if ( x_shift || y_shift ) | 
| 572 |       FT_Outline_Translate( outline, -x_shift, -y_shift ); | 
| 573 |  | 
| 574 |     return error; | 
| 575 |   } | 
| 576 |  | 
| 577 |  | 
| 578 |   FT_DEFINE_RENDERER( | 
| 579 |     ft_smooth_renderer_class, | 
| 580 |  | 
| 581 |       FT_MODULE_RENDERER, | 
| 582 |       sizeof ( FT_RendererRec ), | 
| 583 |  | 
| 584 |       "smooth" , | 
| 585 |       0x10000L, | 
| 586 |       0x20000L, | 
| 587 |  | 
| 588 |       NULL,    /* module specific interface */ | 
| 589 |  | 
| 590 |       (FT_Module_Constructor)ft_smooth_init,  /* module_init   */ | 
| 591 |       (FT_Module_Destructor) NULL,            /* module_done   */ | 
| 592 |       (FT_Module_Requester)  NULL,            /* get_interface */ | 
| 593 |  | 
| 594 |     FT_GLYPH_FORMAT_OUTLINE, | 
| 595 |  | 
| 596 |     (FT_Renderer_RenderFunc)   ft_smooth_render,     /* render_glyph    */ | 
| 597 |     (FT_Renderer_TransformFunc)ft_smooth_transform,  /* transform_glyph */ | 
| 598 |     (FT_Renderer_GetCBoxFunc)  ft_smooth_get_cbox,   /* get_glyph_cbox  */ | 
| 599 |     (FT_Renderer_SetModeFunc)  ft_smooth_set_mode,   /* set_mode        */ | 
| 600 |  | 
| 601 |     (FT_Raster_Funcs*)&ft_grays_raster               /* raster_class    */ | 
| 602 |   ) | 
| 603 |  | 
| 604 |  | 
| 605 | /* END */ | 
| 606 |  |