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