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