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, ¶ms ); 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, ¶ms ); 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, ¶ms ); 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, ¶ms ); 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, ¶ms ); 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, ¶ms ); 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, ¶ms ); 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, ¶ms ); 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 */