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