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