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 #include "ftspic.h" 26 27 #include "ftsmerrs.h" 28 29 30 /* initialize renderer -- init its raster */ 31 static FT_Error 32 ft_smooth_init( FT_Renderer render ) 33 { 34 render->clazz->raster_class->raster_reset( render->raster, NULL, 0 ); 35 36 return 0; 37 } 38 39 40 /* sets render-specific mode */ 41 static FT_Error 42 ft_smooth_set_mode( FT_Renderer render, 43 FT_ULong mode_tag, 44 FT_Pointer data ) 45 { 46 /* we simply pass it to the raster */ 47 return render->clazz->raster_class->raster_set_mode( render->raster, 48 mode_tag, 49 data ); 50 } 51 52 /* transform a given glyph image */ 53 static FT_Error 54 ft_smooth_transform( FT_Renderer render, 55 FT_GlyphSlot slot, 56 const FT_Matrix* matrix, 57 const FT_Vector* delta ) 58 { 59 FT_Error error = FT_Err_Ok; 60 61 62 if ( slot->format != render->glyph_format ) 63 { 64 error = FT_THROW( Invalid_Argument ); 65 goto Exit; 66 } 67 68 if ( matrix ) 69 FT_Outline_Transform( &slot->outline, matrix ); 70 71 if ( delta ) 72 FT_Outline_Translate( &slot->outline, delta->x, delta->y ); 73 74 Exit: 75 return error; 76 } 77 78 79 /* return the glyph's control box */ 80 static void 81 ft_smooth_get_cbox( FT_Renderer render, 82 FT_GlyphSlot slot, 83 FT_BBox* cbox ) 84 { 85 FT_ZERO( cbox ); 86 87 if ( slot->format == render->glyph_format ) 88 FT_Outline_Get_CBox( &slot->outline, cbox ); 89 } 90 91 92 /* convert a slot's glyph image into a bitmap */ 93 static FT_Error 94 ft_smooth_render_generic( FT_Renderer render, 95 FT_GlyphSlot slot, 96 FT_Render_Mode mode, 97 const FT_Vector* origin, 98 FT_Render_Mode required_mode ) 99 { 100 FT_Error error = FT_Err_Ok; 101 FT_Outline* outline = &slot->outline; 102 FT_Bitmap* bitmap = &slot->bitmap; 103 FT_Memory memory = render->root.memory; 104 FT_Pos x_shift = 0; 105 FT_Pos y_shift = 0; 106 FT_Int hmul = ( mode == FT_RENDER_MODE_LCD ); 107 FT_Int vmul = ( mode == FT_RENDER_MODE_LCD_V ); 108 109 FT_Raster_Params params; 110 111 112 /* check glyph image format */ 113 if ( slot->format != render->glyph_format ) 114 { 115 error = FT_THROW( Invalid_Argument ); 116 goto Exit; 117 } 118 119 /* check mode */ 120 if ( mode != required_mode ) 121 { 122 error = FT_THROW( Cannot_Render_Glyph ); 123 goto Exit; 124 } 125 126 /* release old bitmap buffer */ 127 if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) 128 { 129 FT_FREE( bitmap->buffer ); 130 slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; 131 } 132 133 ft_glyphslot_preset_bitmap( slot, mode, origin ); 134 135 /* allocate new one */ 136 if ( FT_ALLOC_MULT( bitmap->buffer, bitmap->rows, bitmap->pitch ) ) 137 goto Exit; 138 139 slot->internal->flags |= FT_GLYPH_OWN_BITMAP; 140 141 x_shift = 64 * -slot->bitmap_left; 142 y_shift = 64 * -slot->bitmap_top; 143 if ( bitmap->pixel_mode == FT_PIXEL_MODE_LCD_V ) 144 y_shift += 64 * (FT_Int)bitmap->rows / 3; 145 else 146 y_shift += 64 * (FT_Int)bitmap->rows; 147 148 if ( origin ) 149 { 150 x_shift += origin->x; 151 y_shift += origin->y; 152 } 153 154 /* translate outline to render it into the bitmap */ 155 if ( x_shift || y_shift ) 156 FT_Outline_Translate( outline, x_shift, y_shift ); 157 158 /* set up parameters */ 159 params.target = bitmap; 160 params.source = outline; 161 params.flags = FT_RASTER_FLAG_AA; 162 163 #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING 164 165 /* implode outline if needed */ 166 { 167 FT_Vector* points = outline->points; 168 FT_Vector* points_end = points + outline->n_points; 169 FT_Vector* vec; 170 171 172 if ( hmul ) 173 for ( vec = points; vec < points_end; vec++ ) 174 vec->x *= 3; 175 176 if ( vmul ) 177 for ( vec = points; vec < points_end; vec++ ) 178 vec->y *= 3; 179 } 180 181 /* render outline into the bitmap */ 182 error = render->raster_render( render->raster, ¶ms ); 183 184 /* deflate outline if needed */ 185 { 186 FT_Vector* points = outline->points; 187 FT_Vector* points_end = points + outline->n_points; 188 FT_Vector* vec; 189 190 191 if ( hmul ) 192 for ( vec = points; vec < points_end; vec++ ) 193 vec->x /= 3; 194 195 if ( vmul ) 196 for ( vec = points; vec < points_end; vec++ ) 197 vec->y /= 3; 198 } 199 200 if ( error ) 201 goto Exit; 202 203 /* finally apply filtering */ 204 if ( hmul || vmul ) 205 { 206 FT_Byte* lcd_weights; 207 FT_Bitmap_LcdFilterFunc lcd_filter_func; 208 209 210 /* Per-face LCD filtering takes priority if set up. */ 211 if ( slot->face && slot->face->internal->lcd_filter_func ) 212 { 213 lcd_weights = slot->face->internal->lcd_weights; 214 lcd_filter_func = slot->face->internal->lcd_filter_func; 215 } 216 else 217 { 218 lcd_weights = slot->library->lcd_weights; 219 lcd_filter_func = slot->library->lcd_filter_func; 220 } 221 222 if ( lcd_filter_func ) 223 lcd_filter_func( bitmap, mode, lcd_weights ); 224 } 225 226 #else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ 227 228 if ( hmul ) /* lcd */ 229 { 230 FT_Byte* line; 231 FT_Byte* temp = NULL; 232 FT_UInt i, j; 233 234 unsigned int height = bitmap->rows; 235 unsigned int width = bitmap->width; 236 int pitch = bitmap->pitch; 237 238 239 /* Render 3 separate monochrome bitmaps, shifting the outline */ 240 /* by 1/3 pixel. */ 241 width /= 3; 242 243 bitmap->buffer += width; 244 245 error = render->raster_render( render->raster, ¶ms ); 246 if ( error ) 247 goto Exit; 248 249 FT_Outline_Translate( outline, -21, 0 ); 250 x_shift -= 21; 251 bitmap->buffer += width; 252 253 error = render->raster_render( render->raster, ¶ms ); 254 if ( error ) 255 goto Exit; 256 257 FT_Outline_Translate( outline, 42, 0 ); 258 x_shift += 42; 259 bitmap->buffer -= 2 * width; 260 261 error = render->raster_render( render->raster, ¶ms ); 262 if ( error ) 263 goto Exit; 264 265 /* XXX: Rearrange the bytes according to FT_PIXEL_MODE_LCD. */ 266 /* XXX: It is more efficient to render every third byte above. */ 267 268 if ( FT_ALLOC( temp, (FT_ULong)pitch ) ) 269 goto Exit; 270 271 for ( i = 0; i < height; i++ ) 272 { 273 line = bitmap->buffer + i * (FT_ULong)pitch; 274 for ( j = 0; j < width; j++ ) 275 { 276 temp[3 * j ] = line[j]; 277 temp[3 * j + 1] = line[j + width]; 278 temp[3 * j + 2] = line[j + width + width]; 279 } 280 FT_MEM_COPY( line, temp, pitch ); 281 } 282 283 FT_FREE( temp ); 284 } 285 else if ( vmul ) /* lcd_v */ 286 { 287 int pitch = bitmap->pitch; 288 289 290 /* Render 3 separate monochrome bitmaps, shifting the outline */ 291 /* by 1/3 pixel. Triple the pitch to render on each third row. */ 292 bitmap->pitch *= 3; 293 bitmap->rows /= 3; 294 295 bitmap->buffer += pitch; 296 297 error = render->raster_render( render->raster, ¶ms ); 298 if ( error ) 299 goto Exit; 300 301 FT_Outline_Translate( outline, 0, 21 ); 302 y_shift += 21; 303 bitmap->buffer += pitch; 304 305 error = render->raster_render( render->raster, ¶ms ); 306 if ( error ) 307 goto Exit; 308 309 FT_Outline_Translate( outline, 0, -42 ); 310 y_shift -= 42; 311 bitmap->buffer -= 2 * pitch; 312 313 error = render->raster_render( render->raster, ¶ms ); 314 if ( error ) 315 goto Exit; 316 317 bitmap->pitch /= 3; 318 bitmap->rows *= 3; 319 } 320 else /* grayscale */ 321 error = render->raster_render( render->raster, ¶ms ); 322 323 #endif /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ 324 325 Exit: 326 if ( !error ) 327 { 328 /* everything is fine; the glyph is now officially a bitmap */ 329 slot->format = FT_GLYPH_FORMAT_BITMAP; 330 } 331 else if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) 332 { 333 FT_FREE( bitmap->buffer ); 334 slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; 335 } 336 337 if ( x_shift || y_shift ) 338 FT_Outline_Translate( outline, -x_shift, -y_shift ); 339 340 return error; 341 } 342 343 344 /* convert a slot's glyph image into a bitmap */ 345 static FT_Error 346 ft_smooth_render( FT_Renderer render, 347 FT_GlyphSlot slot, 348 FT_Render_Mode mode, 349 const FT_Vector* origin ) 350 { 351 if ( mode == FT_RENDER_MODE_LIGHT ) 352 mode = FT_RENDER_MODE_NORMAL; 353 354 return ft_smooth_render_generic( render, slot, mode, origin, 355 FT_RENDER_MODE_NORMAL ); 356 } 357 358 359 /* convert a slot's glyph image into a horizontal LCD bitmap */ 360 static FT_Error 361 ft_smooth_render_lcd( FT_Renderer render, 362 FT_GlyphSlot slot, 363 FT_Render_Mode mode, 364 const FT_Vector* origin ) 365 { 366 return ft_smooth_render_generic( render, slot, mode, origin, 367 FT_RENDER_MODE_LCD ); 368 } 369 370 371 /* convert a slot's glyph image into a vertical LCD bitmap */ 372 static FT_Error 373 ft_smooth_render_lcd_v( FT_Renderer render, 374 FT_GlyphSlot slot, 375 FT_Render_Mode mode, 376 const FT_Vector* origin ) 377 { 378 return ft_smooth_render_generic( render, slot, mode, origin, 379 FT_RENDER_MODE_LCD_V ); 380 } 381 382 383 FT_DEFINE_RENDERER( 384 ft_smooth_renderer_class, 385 386 FT_MODULE_RENDERER, 387 sizeof ( FT_RendererRec ), 388 389 "smooth", 390 0x10000L, 391 0x20000L, 392 393 NULL, /* module specific interface */ 394 395 (FT_Module_Constructor)ft_smooth_init, /* module_init */ 396 (FT_Module_Destructor) NULL, /* module_done */ 397 (FT_Module_Requester) NULL, /* get_interface */ 398 399 FT_GLYPH_FORMAT_OUTLINE, 400 401 (FT_Renderer_RenderFunc) ft_smooth_render, /* render_glyph */ 402 (FT_Renderer_TransformFunc)ft_smooth_transform, /* transform_glyph */ 403 (FT_Renderer_GetCBoxFunc) ft_smooth_get_cbox, /* get_glyph_cbox */ 404 (FT_Renderer_SetModeFunc) ft_smooth_set_mode, /* set_mode */ 405 406 (FT_Raster_Funcs*)&FT_GRAYS_RASTER_GET /* raster_class */ 407 ) 408 409 410 FT_DEFINE_RENDERER( 411 ft_smooth_lcd_renderer_class, 412 413 FT_MODULE_RENDERER, 414 sizeof ( FT_RendererRec ), 415 416 "smooth-lcd", 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_lcd, /* 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_GET /* raster_class */ 434 ) 435 436 437 FT_DEFINE_RENDERER( 438 ft_smooth_lcdv_renderer_class, 439 440 FT_MODULE_RENDERER, 441 sizeof ( FT_RendererRec ), 442 443 "smooth-lcdv", 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_v, /* 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_GET /* raster_class */ 461 ) 462 463 464 /* END */