1 /***************************************************************************/ 2 /* */ 3 /* ftsmooth.c */ 4 /* */ 5 /* Anti-aliasing renderer interface (body). */ 6 /* */ 7 /* Copyright 2000-2006, 2009-2011 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 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 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 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 = Smooth_Err_Ok; 65 66 67 if ( slot->format != render->glyph_format ) 68 { 69 error = Smooth_Err_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 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 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_UInt width, height, pitch; 109 #ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING 110 FT_UInt height_org, width_org; 111 #endif 112 FT_Bitmap* bitmap; 113 FT_Memory 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, y_shift, x_left, y_top; 117 118 FT_Raster_Params params; 119 120 121 /* check glyph image format */ 122 if ( slot->format != render->glyph_format ) 123 { 124 error = Smooth_Err_Invalid_Argument; 125 goto Exit; 126 } 127 128 /* check mode */ 129 if ( mode != required_mode ) 130 return Smooth_Err_Cannot_Render_Glyph; 131 132 outline = &slot->outline; 133 134 /* translate the outline to the new origin if needed */ 135 if ( origin ) 136 FT_Outline_Translate( outline, origin->x, origin->y ); 137 138 /* compute the control box, and grid fit it */ 139 FT_Outline_Get_CBox( outline, &cbox ); 140 141 cbox.xMin = FT_PIX_FLOOR( cbox.xMin ); 142 cbox.yMin = FT_PIX_FLOOR( cbox.yMin ); 143 cbox.xMax = FT_PIX_CEIL( cbox.xMax ); 144 cbox.yMax = FT_PIX_CEIL( cbox.yMax ); 145 146 if ( cbox.xMin < 0 && cbox.xMax > FT_INT_MAX + cbox.xMin ) 147 { 148 FT_ERROR(( "ft_smooth_render_generic: glyph too large:" 149 " xMin = %d, xMax = %d\n", 150 cbox.xMin >> 6, cbox.xMax >> 6 )); 151 return Smooth_Err_Raster_Overflow; 152 } 153 else 154 width = (FT_UInt)( ( cbox.xMax - cbox.xMin ) >> 6 ); 155 156 if ( cbox.yMin < 0 && cbox.yMax > FT_INT_MAX + cbox.yMin ) 157 { 158 FT_ERROR(( "ft_smooth_render_generic: glyph too large:" 159 " yMin = %d, yMax = %d\n", 160 cbox.yMin >> 6, cbox.yMax >> 6 )); 161 return Smooth_Err_Raster_Overflow; 162 } 163 else 164 height = (FT_UInt)( ( cbox.yMax - cbox.yMin ) >> 6 ); 165 166 bitmap = &slot->bitmap; 167 memory = render->root.memory; 168 169 #ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING 170 width_org = width; 171 height_org = height; 172 #endif 173 174 /* release old bitmap buffer */ 175 if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) 176 { 177 FT_FREE( bitmap->buffer ); 178 slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; 179 } 180 181 /* allocate new one */ 182 pitch = width; 183 if ( hmul ) 184 { 185 width = width * 3; 186 pitch = FT_PAD_CEIL( width, 4 ); 187 } 188 189 if ( vmul ) 190 height *= 3; 191 192 x_shift = (FT_Int) cbox.xMin; 193 y_shift = (FT_Int) cbox.yMin; 194 x_left = (FT_Int)( cbox.xMin >> 6 ); 195 y_top = (FT_Int)( cbox.yMax >> 6 ); 196 197 #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING 198 199 if ( slot->library->lcd_filter_func ) 200 { 201 FT_Int extra = slot->library->lcd_extra; 202 203 204 if ( hmul ) 205 { 206 x_shift -= 64 * ( extra >> 1 ); 207 width += 3 * extra; 208 pitch = FT_PAD_CEIL( width, 4 ); 209 x_left -= extra >> 1; 210 } 211 212 if ( vmul ) 213 { 214 y_shift -= 64 * ( extra >> 1 ); 215 height += 3 * extra; 216 y_top += extra >> 1; 217 } 218 } 219 220 #endif 221 222 #if FT_UINT_MAX > 0xFFFFU 223 224 /* Required check is ( pitch * height < FT_ULONG_MAX ), */ 225 /* but we care realistic cases only. Always pitch <= width. */ 226 if ( width > 0x7FFFU || height > 0x7FFFU ) 227 { 228 FT_ERROR(( "ft_smooth_render_generic: glyph too large: %u x %u\n", 229 width, height )); 230 return Smooth_Err_Raster_Overflow; 231 } 232 233 #endif 234 235 bitmap->pixel_mode = FT_PIXEL_MODE_GRAY; 236 bitmap->num_grays = 256; 237 bitmap->width = width; 238 bitmap->rows = height; 239 bitmap->pitch = pitch; 240 241 /* translate outline to render it into the bitmap */ 242 FT_Outline_Translate( outline, -x_shift, -y_shift ); 243 244 if ( FT_ALLOC( bitmap->buffer, (FT_ULong)pitch * height ) ) 245 goto Exit; 246 247 slot->internal->flags |= FT_GLYPH_OWN_BITMAP; 248 249 /* set up parameters */ 250 params.target = bitmap; 251 params.source = outline; 252 params.flags = FT_RASTER_FLAG_AA; 253 254 #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING 255 256 /* implode outline if needed */ 257 { 258 FT_Vector* points = outline->points; 259 FT_Vector* points_end = points + outline->n_points; 260 FT_Vector* vec; 261 262 263 if ( hmul ) 264 for ( vec = points; vec < points_end; vec++ ) 265 vec->x *= 3; 266 267 if ( vmul ) 268 for ( vec = points; vec < points_end; vec++ ) 269 vec->y *= 3; 270 } 271 272 /* render outline into the bitmap */ 273 error = render->raster_render( render->raster, ¶ms ); 274 275 /* deflate outline if needed */ 276 { 277 FT_Vector* points = outline->points; 278 FT_Vector* points_end = points + outline->n_points; 279 FT_Vector* vec; 280 281 282 if ( hmul ) 283 for ( vec = points; vec < points_end; vec++ ) 284 vec->x /= 3; 285 286 if ( vmul ) 287 for ( vec = points; vec < points_end; vec++ ) 288 vec->y /= 3; 289 } 290 291 if ( slot->library->lcd_filter_func ) 292 slot->library->lcd_filter_func( bitmap, mode, slot->library ); 293 294 #else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ 295 296 /* render outline into bitmap */ 297 error = render->raster_render( render->raster, ¶ms ); 298 299 /* expand it horizontally */ 300 if ( hmul ) 301 { 302 FT_Byte* line = bitmap->buffer; 303 FT_UInt hh; 304 305 306 for ( hh = height_org; hh > 0; hh--, line += pitch ) 307 { 308 FT_UInt xx; 309 FT_Byte* end = line + width; 310 311 312 for ( xx = width_org; xx > 0; xx-- ) 313 { 314 FT_UInt pixel = line[xx-1]; 315 316 317 end[-3] = (FT_Byte)pixel; 318 end[-2] = (FT_Byte)pixel; 319 end[-1] = (FT_Byte)pixel; 320 end -= 3; 321 } 322 } 323 } 324 325 /* expand it vertically */ 326 if ( vmul ) 327 { 328 FT_Byte* read = bitmap->buffer + ( height - height_org ) * pitch; 329 FT_Byte* write = bitmap->buffer; 330 FT_UInt hh; 331 332 333 for ( hh = height_org; hh > 0; hh-- ) 334 { 335 ft_memcpy( write, read, pitch ); 336 write += pitch; 337 338 ft_memcpy( write, read, pitch ); 339 write += pitch; 340 341 ft_memcpy( write, read, pitch ); 342 write += pitch; 343 read += pitch; 344 } 345 } 346 347 #endif /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ 348 349 FT_Outline_Translate( outline, x_shift, y_shift ); 350 351 /* 352 * XXX: on 16bit system, we return an error for huge bitmap 353 * to prevent an overflow. 354 */ 355 if ( x_left > FT_INT_MAX || y_top > FT_INT_MAX ) 356 return Smooth_Err_Invalid_Pixel_Size; 357 358 if ( error ) 359 goto Exit; 360 361 slot->format = FT_GLYPH_FORMAT_BITMAP; 362 slot->bitmap_left = (FT_Int)x_left; 363 slot->bitmap_top = (FT_Int)y_top; 364 365 Exit: 366 if ( outline && origin ) 367 FT_Outline_Translate( outline, -origin->x, -origin->y ); 368 369 return error; 370 } 371 372 373 /* convert a slot's glyph image into a bitmap */ 374 static FT_Error 375 ft_smooth_render( FT_Renderer render, 376 FT_GlyphSlot slot, 377 FT_Render_Mode mode, 378 const FT_Vector* origin ) 379 { 380 if ( mode == FT_RENDER_MODE_LIGHT ) 381 mode = FT_RENDER_MODE_NORMAL; 382 383 return ft_smooth_render_generic( render, slot, mode, origin, 384 FT_RENDER_MODE_NORMAL ); 385 } 386 387 388 /* convert a slot's glyph image into a horizontal LCD bitmap */ 389 static FT_Error 390 ft_smooth_render_lcd( FT_Renderer render, 391 FT_GlyphSlot slot, 392 FT_Render_Mode mode, 393 const FT_Vector* origin ) 394 { 395 FT_Error error; 396 397 error = ft_smooth_render_generic( render, slot, mode, origin, 398 FT_RENDER_MODE_LCD ); 399 if ( !error ) 400 slot->bitmap.pixel_mode = FT_PIXEL_MODE_LCD; 401 402 return error; 403 } 404 405 406 /* convert a slot's glyph image into a vertical LCD bitmap */ 407 static FT_Error 408 ft_smooth_render_lcd_v( FT_Renderer render, 409 FT_GlyphSlot slot, 410 FT_Render_Mode mode, 411 const FT_Vector* origin ) 412 { 413 FT_Error error; 414 415 error = ft_smooth_render_generic( render, slot, mode, origin, 416 FT_RENDER_MODE_LCD_V ); 417 if ( !error ) 418 slot->bitmap.pixel_mode = FT_PIXEL_MODE_LCD_V; 419 420 return error; 421 } 422 423 424 FT_DEFINE_RENDERER(ft_smooth_renderer_class, 425 426 FT_MODULE_RENDERER, 427 sizeof( FT_RendererRec ), 428 429 "smooth", 430 0x10000L, 431 0x20000L, 432 433 0, /* module specific interface */ 434 435 (FT_Module_Constructor)ft_smooth_init, 436 (FT_Module_Destructor) 0, 437 (FT_Module_Requester) 0 438 , 439 440 FT_GLYPH_FORMAT_OUTLINE, 441 442 (FT_Renderer_RenderFunc) ft_smooth_render, 443 (FT_Renderer_TransformFunc)ft_smooth_transform, 444 (FT_Renderer_GetCBoxFunc) ft_smooth_get_cbox, 445 (FT_Renderer_SetModeFunc) ft_smooth_set_mode, 446 447 (FT_Raster_Funcs*) &FT_GRAYS_RASTER_GET 448 ) 449 450 451 FT_DEFINE_RENDERER(ft_smooth_lcd_renderer_class, 452 453 FT_MODULE_RENDERER, 454 sizeof( FT_RendererRec ), 455 456 "smooth-lcd", 457 0x10000L, 458 0x20000L, 459 460 0, /* module specific interface */ 461 462 (FT_Module_Constructor)ft_smooth_init, 463 (FT_Module_Destructor) 0, 464 (FT_Module_Requester) 0 465 , 466 467 FT_GLYPH_FORMAT_OUTLINE, 468 469 (FT_Renderer_RenderFunc) ft_smooth_render_lcd, 470 (FT_Renderer_TransformFunc)ft_smooth_transform, 471 (FT_Renderer_GetCBoxFunc) ft_smooth_get_cbox, 472 (FT_Renderer_SetModeFunc) ft_smooth_set_mode, 473 474 (FT_Raster_Funcs*) &FT_GRAYS_RASTER_GET 475 ) 476 477 FT_DEFINE_RENDERER(ft_smooth_lcdv_renderer_class, 478 479 FT_MODULE_RENDERER, 480 sizeof( FT_RendererRec ), 481 482 "smooth-lcdv", 483 0x10000L, 484 0x20000L, 485 486 0, /* module specific interface */ 487 488 (FT_Module_Constructor)ft_smooth_init, 489 (FT_Module_Destructor) 0, 490 (FT_Module_Requester) 0 491 , 492 493 FT_GLYPH_FORMAT_OUTLINE, 494 495 (FT_Renderer_RenderFunc) ft_smooth_render_lcd_v, 496 (FT_Renderer_TransformFunc)ft_smooth_transform, 497 (FT_Renderer_GetCBoxFunc) ft_smooth_get_cbox, 498 (FT_Renderer_SetModeFunc) ft_smooth_set_mode, 499 500 (FT_Raster_Funcs*) &FT_GRAYS_RASTER_GET 501 ) 502 503 504 /* END */ 505