1 /***************************************************************************/ 2 /* */ 3 /* ftsmooth.c */ 4 /* */ 5 /* Anti-aliasing renderer interface (body). */ 6 /* */ 7 /* Copyright 2000-2006, 2009-2013 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 ft_smooth_init(FT_Renderer render)32 ft_smooth_init( FT_Renderer render ) 33 { 34 FT_Library library = FT_MODULE_LIBRARY( render ); 35 36 37 render->clazz->raster_class->raster_reset( render->raster, 38 library->raster_pool, 39 library->raster_pool_size ); 40 41 return 0; 42 } 43 44 45 /* sets render-specific mode */ 46 static FT_Error ft_smooth_set_mode(FT_Renderer render,FT_ULong mode_tag,FT_Pointer data)47 ft_smooth_set_mode( FT_Renderer render, 48 FT_ULong mode_tag, 49 FT_Pointer data ) 50 { 51 /* we simply pass it to the raster */ 52 return render->clazz->raster_class->raster_set_mode( render->raster, 53 mode_tag, 54 data ); 55 } 56 57 /* transform a given glyph image */ 58 static FT_Error ft_smooth_transform(FT_Renderer render,FT_GlyphSlot slot,const FT_Matrix * matrix,const FT_Vector * delta)59 ft_smooth_transform( FT_Renderer render, 60 FT_GlyphSlot slot, 61 const FT_Matrix* matrix, 62 const FT_Vector* delta ) 63 { 64 FT_Error error = FT_Err_Ok; 65 66 67 if ( slot->format != render->glyph_format ) 68 { 69 error = FT_THROW( Invalid_Argument ); 70 goto Exit; 71 } 72 73 if ( matrix ) 74 FT_Outline_Transform( &slot->outline, matrix ); 75 76 if ( delta ) 77 FT_Outline_Translate( &slot->outline, delta->x, delta->y ); 78 79 Exit: 80 return error; 81 } 82 83 84 /* return the glyph's control box */ 85 static void ft_smooth_get_cbox(FT_Renderer render,FT_GlyphSlot slot,FT_BBox * cbox)86 ft_smooth_get_cbox( FT_Renderer render, 87 FT_GlyphSlot slot, 88 FT_BBox* cbox ) 89 { 90 FT_MEM_ZERO( cbox, sizeof ( *cbox ) ); 91 92 if ( slot->format == render->glyph_format ) 93 FT_Outline_Get_CBox( &slot->outline, cbox ); 94 } 95 96 97 /* convert a slot's glyph image into a bitmap */ 98 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)99 ft_smooth_render_generic( FT_Renderer render, 100 FT_GlyphSlot slot, 101 FT_Render_Mode mode, 102 const FT_Vector* origin, 103 FT_Render_Mode required_mode ) 104 { 105 FT_Error error; 106 FT_Outline* outline = NULL; 107 FT_BBox cbox; 108 FT_Pos width, height, pitch; 109 #ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING 110 FT_Pos height_org, width_org; 111 #endif 112 FT_Bitmap* bitmap = &slot->bitmap; 113 FT_Memory memory = render->root.memory; 114 FT_Int hmul = mode == FT_RENDER_MODE_LCD; 115 FT_Int vmul = mode == FT_RENDER_MODE_LCD_V; 116 FT_Pos x_shift = 0; 117 FT_Pos y_shift = 0; 118 FT_Pos x_left, y_top; 119 120 FT_Raster_Params params; 121 122 FT_Bool have_translated_origin = FALSE; 123 FT_Bool have_outline_shifted = FALSE; 124 FT_Bool have_buffer = FALSE; 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 outline = &slot->outline; 142 143 /* translate the outline to the new origin if needed */ 144 if ( origin ) 145 { 146 FT_Outline_Translate( outline, origin->x, origin->y ); 147 have_translated_origin = TRUE; 148 } 149 150 /* compute the control box, and grid fit it */ 151 FT_Outline_Get_CBox( outline, &cbox ); 152 153 cbox.xMin = FT_PIX_FLOOR( cbox.xMin ); 154 cbox.yMin = FT_PIX_FLOOR( cbox.yMin ); 155 cbox.xMax = FT_PIX_CEIL( cbox.xMax ); 156 cbox.yMax = FT_PIX_CEIL( cbox.yMax ); 157 158 if ( cbox.xMin < 0 && cbox.xMax > FT_INT_MAX + cbox.xMin ) 159 { 160 FT_ERROR(( "ft_smooth_render_generic: glyph too large:" 161 " xMin = %d, xMax = %d\n", 162 cbox.xMin >> 6, cbox.xMax >> 6 )); 163 error = FT_THROW( Raster_Overflow ); 164 goto Exit; 165 } 166 else 167 width = ( cbox.xMax - cbox.xMin ) >> 6; 168 169 if ( cbox.yMin < 0 && cbox.yMax > FT_INT_MAX + cbox.yMin ) 170 { 171 FT_ERROR(( "ft_smooth_render_generic: glyph too large:" 172 " yMin = %d, yMax = %d\n", 173 cbox.yMin >> 6, cbox.yMax >> 6 )); 174 error = FT_THROW( Raster_Overflow ); 175 goto Exit; 176 } 177 else 178 height = ( cbox.yMax - cbox.yMin ) >> 6; 179 180 #ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING 181 width_org = width; 182 height_org = height; 183 #endif 184 185 /* release old bitmap buffer */ 186 if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) 187 { 188 FT_FREE( bitmap->buffer ); 189 slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; 190 } 191 192 /* allocate new one */ 193 pitch = width; 194 if ( hmul ) 195 { 196 width = width * 3; 197 pitch = FT_PAD_CEIL( width, 4 ); 198 } 199 200 if ( vmul ) 201 height *= 3; 202 203 x_shift = (FT_Int) cbox.xMin; 204 y_shift = (FT_Int) cbox.yMin; 205 x_left = (FT_Int)( cbox.xMin >> 6 ); 206 y_top = (FT_Int)( cbox.yMax >> 6 ); 207 208 #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING 209 210 if ( slot->library->lcd_filter_func ) 211 { 212 FT_Int extra = slot->library->lcd_extra; 213 214 215 if ( hmul ) 216 { 217 x_shift -= 64 * ( extra >> 1 ); 218 width += 3 * extra; 219 pitch = FT_PAD_CEIL( width, 4 ); 220 x_left -= extra >> 1; 221 } 222 223 if ( vmul ) 224 { 225 y_shift -= 64 * ( extra >> 1 ); 226 height += 3 * extra; 227 y_top += extra >> 1; 228 } 229 } 230 231 #endif 232 233 #if FT_UINT_MAX > 0xFFFFU 234 235 /* Required check is (pitch * height < FT_ULONG_MAX), */ 236 /* but we care realistic cases only. Always pitch <= width. */ 237 if ( width > 0x7FFF || height > 0x7FFF ) 238 { 239 FT_ERROR(( "ft_smooth_render_generic: glyph too large: %u x %u\n", 240 width, height )); 241 error = FT_THROW( Raster_Overflow ); 242 goto Exit; 243 } 244 245 #endif 246 247 bitmap->pixel_mode = FT_PIXEL_MODE_GRAY; 248 bitmap->num_grays = 256; 249 bitmap->width = width; 250 bitmap->rows = height; 251 bitmap->pitch = pitch; 252 253 /* translate outline to render it into the bitmap */ 254 FT_Outline_Translate( outline, -x_shift, -y_shift ); 255 have_outline_shifted = TRUE; 256 257 if ( FT_ALLOC( bitmap->buffer, (FT_ULong)pitch * height ) ) 258 goto Exit; 259 else 260 have_buffer = TRUE; 261 262 slot->internal->flags |= FT_GLYPH_OWN_BITMAP; 263 264 /* set up parameters */ 265 params.target = bitmap; 266 params.source = outline; 267 params.flags = FT_RASTER_FLAG_AA; 268 269 #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING 270 271 /* implode outline if needed */ 272 { 273 FT_Vector* points = outline->points; 274 FT_Vector* points_end = points + outline->n_points; 275 FT_Vector* vec; 276 277 278 if ( hmul ) 279 for ( vec = points; vec < points_end; vec++ ) 280 vec->x *= 3; 281 282 if ( vmul ) 283 for ( vec = points; vec < points_end; vec++ ) 284 vec->y *= 3; 285 } 286 287 /* render outline into the bitmap */ 288 error = render->raster_render( render->raster, ¶ms ); 289 290 /* deflate outline if needed */ 291 { 292 FT_Vector* points = outline->points; 293 FT_Vector* points_end = points + outline->n_points; 294 FT_Vector* vec; 295 296 297 if ( hmul ) 298 for ( vec = points; vec < points_end; vec++ ) 299 vec->x /= 3; 300 301 if ( vmul ) 302 for ( vec = points; vec < points_end; vec++ ) 303 vec->y /= 3; 304 } 305 306 if ( error ) 307 goto Exit; 308 309 if ( slot->library->lcd_filter_func ) 310 slot->library->lcd_filter_func( bitmap, mode, slot->library ); 311 312 #else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ 313 314 /* render outline into bitmap */ 315 error = render->raster_render( render->raster, ¶ms ); 316 if ( error ) 317 goto Exit; 318 319 /* expand it horizontally */ 320 if ( hmul ) 321 { 322 FT_Byte* line = bitmap->buffer; 323 FT_UInt hh; 324 325 326 for ( hh = height_org; hh > 0; hh--, line += pitch ) 327 { 328 FT_UInt xx; 329 FT_Byte* end = line + width; 330 331 332 for ( xx = width_org; xx > 0; xx-- ) 333 { 334 FT_UInt pixel = line[xx-1]; 335 336 337 end[-3] = (FT_Byte)pixel; 338 end[-2] = (FT_Byte)pixel; 339 end[-1] = (FT_Byte)pixel; 340 end -= 3; 341 } 342 } 343 } 344 345 /* expand it vertically */ 346 if ( vmul ) 347 { 348 FT_Byte* read = bitmap->buffer + ( height - height_org ) * pitch; 349 FT_Byte* write = bitmap->buffer; 350 FT_UInt hh; 351 352 353 for ( hh = height_org; hh > 0; hh-- ) 354 { 355 ft_memcpy( write, read, pitch ); 356 write += pitch; 357 358 ft_memcpy( write, read, pitch ); 359 write += pitch; 360 361 ft_memcpy( write, read, pitch ); 362 write += pitch; 363 read += pitch; 364 } 365 } 366 367 #endif /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ 368 369 /* 370 * XXX: on 16bit system, we return an error for huge bitmap 371 * to prevent an overflow. 372 */ 373 if ( x_left > FT_INT_MAX || y_top > FT_INT_MAX ) 374 { 375 error = FT_THROW( Invalid_Pixel_Size ); 376 goto Exit; 377 } 378 379 slot->format = FT_GLYPH_FORMAT_BITMAP; 380 slot->bitmap_left = (FT_Int)x_left; 381 slot->bitmap_top = (FT_Int)y_top; 382 383 /* everything is fine; don't deallocate buffer */ 384 have_buffer = FALSE; 385 386 error = FT_Err_Ok; 387 388 Exit: 389 if ( have_outline_shifted ) 390 FT_Outline_Translate( outline, x_shift, y_shift ); 391 if ( have_translated_origin ) 392 FT_Outline_Translate( outline, -origin->x, -origin->y ); 393 if ( have_buffer ) 394 { 395 FT_FREE( bitmap->buffer ); 396 slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; 397 } 398 399 return error; 400 } 401 402 403 /* convert a slot's glyph image into a bitmap */ 404 static FT_Error ft_smooth_render(FT_Renderer render,FT_GlyphSlot slot,FT_Render_Mode mode,const FT_Vector * origin)405 ft_smooth_render( FT_Renderer render, 406 FT_GlyphSlot slot, 407 FT_Render_Mode mode, 408 const FT_Vector* origin ) 409 { 410 if ( mode == FT_RENDER_MODE_LIGHT ) 411 mode = FT_RENDER_MODE_NORMAL; 412 413 return ft_smooth_render_generic( render, slot, mode, origin, 414 FT_RENDER_MODE_NORMAL ); 415 } 416 417 418 /* convert a slot's glyph image into a horizontal LCD bitmap */ 419 static FT_Error ft_smooth_render_lcd(FT_Renderer render,FT_GlyphSlot slot,FT_Render_Mode mode,const FT_Vector * origin)420 ft_smooth_render_lcd( FT_Renderer render, 421 FT_GlyphSlot slot, 422 FT_Render_Mode mode, 423 const FT_Vector* origin ) 424 { 425 FT_Error error; 426 427 error = ft_smooth_render_generic( render, slot, mode, origin, 428 FT_RENDER_MODE_LCD ); 429 if ( !error ) 430 slot->bitmap.pixel_mode = FT_PIXEL_MODE_LCD; 431 432 return error; 433 } 434 435 436 /* convert a slot's glyph image into a vertical LCD bitmap */ 437 static FT_Error ft_smooth_render_lcd_v(FT_Renderer render,FT_GlyphSlot slot,FT_Render_Mode mode,const FT_Vector * origin)438 ft_smooth_render_lcd_v( FT_Renderer render, 439 FT_GlyphSlot slot, 440 FT_Render_Mode mode, 441 const FT_Vector* origin ) 442 { 443 FT_Error error; 444 445 error = ft_smooth_render_generic( render, slot, mode, origin, 446 FT_RENDER_MODE_LCD_V ); 447 if ( !error ) 448 slot->bitmap.pixel_mode = FT_PIXEL_MODE_LCD_V; 449 450 return error; 451 } 452 453 454 FT_DEFINE_RENDERER( ft_smooth_renderer_class, 455 456 FT_MODULE_RENDERER, 457 sizeof ( FT_RendererRec ), 458 459 "smooth", 460 0x10000L, 461 0x20000L, 462 463 0, /* module specific interface */ 464 465 (FT_Module_Constructor)ft_smooth_init, 466 (FT_Module_Destructor) 0, 467 (FT_Module_Requester) 0 468 , 469 470 FT_GLYPH_FORMAT_OUTLINE, 471 472 (FT_Renderer_RenderFunc) ft_smooth_render, 473 (FT_Renderer_TransformFunc)ft_smooth_transform, 474 (FT_Renderer_GetCBoxFunc) ft_smooth_get_cbox, 475 (FT_Renderer_SetModeFunc) ft_smooth_set_mode, 476 477 (FT_Raster_Funcs*) &FT_GRAYS_RASTER_GET 478 ) 479 480 481 FT_DEFINE_RENDERER( ft_smooth_lcd_renderer_class, 482 483 FT_MODULE_RENDERER, 484 sizeof ( FT_RendererRec ), 485 486 "smooth-lcd", 487 0x10000L, 488 0x20000L, 489 490 0, /* module specific interface */ 491 492 (FT_Module_Constructor)ft_smooth_init, 493 (FT_Module_Destructor) 0, 494 (FT_Module_Requester) 0 495 , 496 497 FT_GLYPH_FORMAT_OUTLINE, 498 499 (FT_Renderer_RenderFunc) ft_smooth_render_lcd, 500 (FT_Renderer_TransformFunc)ft_smooth_transform, 501 (FT_Renderer_GetCBoxFunc) ft_smooth_get_cbox, 502 (FT_Renderer_SetModeFunc) ft_smooth_set_mode, 503 504 (FT_Raster_Funcs*) &FT_GRAYS_RASTER_GET 505 ) 506 507 FT_DEFINE_RENDERER( ft_smooth_lcdv_renderer_class, 508 509 FT_MODULE_RENDERER, 510 sizeof ( FT_RendererRec ), 511 512 "smooth-lcdv", 513 0x10000L, 514 0x20000L, 515 516 0, /* module specific interface */ 517 518 (FT_Module_Constructor)ft_smooth_init, 519 (FT_Module_Destructor) 0, 520 (FT_Module_Requester) 0 521 , 522 523 FT_GLYPH_FORMAT_OUTLINE, 524 525 (FT_Renderer_RenderFunc) ft_smooth_render_lcd_v, 526 (FT_Renderer_TransformFunc)ft_smooth_transform, 527 (FT_Renderer_GetCBoxFunc) ft_smooth_get_cbox, 528 (FT_Renderer_SetModeFunc) ft_smooth_set_mode, 529 530 (FT_Raster_Funcs*) &FT_GRAYS_RASTER_GET 531 ) 532 533 534 /* END */ 535