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