1 /**************************************************************************** 2 * 3 * pngshim.c 4 * 5 * PNG Bitmap glyph support. 6 * 7 * Copyright (C) 2013-2021 by 8 * Google, Inc. 9 * Written by Stuart Gill and Behdad Esfahbod. 10 * 11 * This file is part of the FreeType project, and may only be used, 12 * modified, and distributed under the terms of the FreeType project 13 * license, LICENSE.TXT. By continuing to use, modify, or distribute 14 * this file you indicate that you have read the license and 15 * understand and accept it fully. 16 * 17 */ 18 19 20 #include <freetype/internal/ftdebug.h> 21 #include <freetype/internal/ftstream.h> 22 #include <freetype/tttags.h> 23 #include FT_CONFIG_STANDARD_LIBRARY_H 24 25 26 #if defined( TT_CONFIG_OPTION_EMBEDDED_BITMAPS ) && \ 27 defined( FT_CONFIG_OPTION_USE_PNG ) 28 29 /* We always include <setjmp.h>, so make libpng shut up! */ 30 #define PNG_SKIP_SETJMP_CHECK 1 31 #include <png.h> 32 #include "pngshim.h" 33 34 #include "sferrors.h" 35 36 37 /* This code is freely based on cairo-png.c. There's so many ways */ 38 /* to call libpng, and the way cairo does it is defacto standard. */ 39 40 static unsigned int multiply_alpha(unsigned int alpha,unsigned int color)41 multiply_alpha( unsigned int alpha, 42 unsigned int color ) 43 { 44 unsigned int temp = alpha * color + 0x80; 45 46 47 return ( temp + ( temp >> 8 ) ) >> 8; 48 } 49 50 51 /* Premultiplies data and converts RGBA bytes => BGRA. */ 52 static void premultiply_data(png_structp png,png_row_infop row_info,png_bytep data)53 premultiply_data( png_structp png, 54 png_row_infop row_info, 55 png_bytep data ) 56 { 57 unsigned int i = 0, limit; 58 59 /* The `vector_size' attribute was introduced in gcc 3.1, which */ 60 /* predates clang; the `__BYTE_ORDER__' preprocessor symbol was */ 61 /* introduced in gcc 4.6 and clang 3.2, respectively. */ 62 /* `__builtin_shuffle' for gcc was introduced in gcc 4.7.0. */ 63 /* */ 64 /* Intel compilers do not currently support __builtin_shuffle; */ 65 66 /* The Intel check must be first. */ 67 #if !defined( __INTEL_COMPILER ) && \ 68 ( ( defined( __GNUC__ ) && \ 69 ( ( __GNUC__ >= 5 ) || \ 70 ( ( __GNUC__ == 4 ) && ( __GNUC_MINOR__ >= 7 ) ) ) ) || \ 71 ( defined( __clang__ ) && \ 72 ( ( __clang_major__ >= 4 ) || \ 73 ( ( __clang_major__ == 3 ) && ( __clang_minor__ >= 2 ) ) ) ) ) && \ 74 defined( __OPTIMIZE__ ) && \ 75 defined( __SSE__ ) && \ 76 __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 77 78 #ifdef __clang__ 79 /* the clang documentation doesn't cover the two-argument case of */ 80 /* `__builtin_shufflevector'; however, it is is implemented since */ 81 /* version 2.8 */ 82 #define vector_shuffle __builtin_shufflevector 83 #else 84 #define vector_shuffle __builtin_shuffle 85 #endif 86 87 typedef unsigned short v82 __attribute__(( vector_size( 16 ) )); 88 89 90 if ( row_info->rowbytes > 15 ) 91 { 92 /* process blocks of 16 bytes in one rush, which gives a nice speed-up */ 93 limit = row_info->rowbytes - 16 + 1; 94 for ( ; i < limit; i += 16 ) 95 { 96 unsigned char* base = &data[i]; 97 98 v82 s, s0, s1, a; 99 100 /* clang <= 3.9 can't apply scalar values to vectors */ 101 /* (or rather, it needs a different syntax) */ 102 v82 n0x80 = { 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 }; 103 v82 n0xFF = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; 104 v82 n8 = { 8, 8, 8, 8, 8, 8, 8, 8 }; 105 106 v82 ma = { 1, 1, 3, 3, 5, 5, 7, 7 }; 107 v82 o1 = { 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF }; 108 v82 m0 = { 1, 0, 3, 2, 5, 4, 7, 6 }; 109 110 111 ft_memcpy( &s, base, 16 ); /* RGBA RGBA RGBA RGBA */ 112 s0 = s & n0xFF; /* R B R B R B R B */ 113 s1 = s >> n8; /* G A G A G A G A */ 114 115 a = vector_shuffle( s1, ma ); /* A A A A A A A A */ 116 s1 |= o1; /* G 1 G 1 G 1 G 1 */ 117 s0 = vector_shuffle( s0, m0 ); /* B R B R B R B R */ 118 119 s0 *= a; 120 s1 *= a; 121 s0 += n0x80; 122 s1 += n0x80; 123 s0 = ( s0 + ( s0 >> n8 ) ) >> n8; 124 s1 = ( s1 + ( s1 >> n8 ) ) >> n8; 125 126 s = s0 | ( s1 << n8 ); 127 ft_memcpy( base, &s, 16 ); 128 } 129 } 130 #endif /* use `vector_size' */ 131 132 FT_UNUSED( png ); 133 134 limit = row_info->rowbytes; 135 for ( ; i < limit; i += 4 ) 136 { 137 unsigned char* base = &data[i]; 138 unsigned int alpha = base[3]; 139 140 141 if ( alpha == 0 ) 142 base[0] = base[1] = base[2] = base[3] = 0; 143 144 else 145 { 146 unsigned int red = base[0]; 147 unsigned int green = base[1]; 148 unsigned int blue = base[2]; 149 150 151 if ( alpha != 0xFF ) 152 { 153 red = multiply_alpha( alpha, red ); 154 green = multiply_alpha( alpha, green ); 155 blue = multiply_alpha( alpha, blue ); 156 } 157 158 base[0] = (unsigned char)blue; 159 base[1] = (unsigned char)green; 160 base[2] = (unsigned char)red; 161 base[3] = (unsigned char)alpha; 162 } 163 } 164 } 165 166 167 /* Converts RGBx bytes to BGRA. */ 168 static void convert_bytes_to_data(png_structp png,png_row_infop row_info,png_bytep data)169 convert_bytes_to_data( png_structp png, 170 png_row_infop row_info, 171 png_bytep data ) 172 { 173 unsigned int i; 174 175 FT_UNUSED( png ); 176 177 178 for ( i = 0; i < row_info->rowbytes; i += 4 ) 179 { 180 unsigned char* base = &data[i]; 181 unsigned int red = base[0]; 182 unsigned int green = base[1]; 183 unsigned int blue = base[2]; 184 185 186 base[0] = (unsigned char)blue; 187 base[1] = (unsigned char)green; 188 base[2] = (unsigned char)red; 189 base[3] = 0xFF; 190 } 191 } 192 193 194 /* Use error callback to avoid png writing to stderr. */ 195 static void error_callback(png_structp png,png_const_charp error_msg)196 error_callback( png_structp png, 197 png_const_charp error_msg ) 198 { 199 FT_Error* error = (FT_Error*)png_get_error_ptr( png ); 200 201 FT_UNUSED( error_msg ); 202 203 204 *error = FT_THROW( Out_Of_Memory ); 205 #ifdef PNG_SETJMP_SUPPORTED 206 ft_longjmp( png_jmpbuf( png ), 1 ); 207 #endif 208 /* if we get here, then we have no choice but to abort ... */ 209 } 210 211 212 /* Use warning callback to avoid png writing to stderr. */ 213 static void warning_callback(png_structp png,png_const_charp error_msg)214 warning_callback( png_structp png, 215 png_const_charp error_msg ) 216 { 217 FT_UNUSED( png ); 218 FT_UNUSED( error_msg ); 219 220 /* Just ignore warnings. */ 221 } 222 223 224 static void read_data_from_FT_Stream(png_structp png,png_bytep data,png_size_t length)225 read_data_from_FT_Stream( png_structp png, 226 png_bytep data, 227 png_size_t length ) 228 { 229 FT_Error error; 230 png_voidp p = png_get_io_ptr( png ); 231 FT_Stream stream = (FT_Stream)p; 232 233 234 if ( FT_FRAME_ENTER( length ) ) 235 { 236 FT_Error* e = (FT_Error*)png_get_error_ptr( png ); 237 238 239 *e = FT_THROW( Invalid_Stream_Read ); 240 png_error( png, NULL ); 241 242 return; 243 } 244 245 ft_memcpy( data, stream->cursor, length ); 246 247 FT_FRAME_EXIT(); 248 } 249 250 251 FT_LOCAL_DEF( FT_Error ) Load_SBit_Png(FT_GlyphSlot slot,FT_Int x_offset,FT_Int y_offset,FT_Int pix_bits,TT_SBit_Metrics metrics,FT_Memory memory,FT_Byte * data,FT_UInt png_len,FT_Bool populate_map_and_metrics,FT_Bool metrics_only)252 Load_SBit_Png( FT_GlyphSlot slot, 253 FT_Int x_offset, 254 FT_Int y_offset, 255 FT_Int pix_bits, 256 TT_SBit_Metrics metrics, 257 FT_Memory memory, 258 FT_Byte* data, 259 FT_UInt png_len, 260 FT_Bool populate_map_and_metrics, 261 FT_Bool metrics_only ) 262 { 263 FT_Bitmap *map = &slot->bitmap; 264 FT_Error error = FT_Err_Ok; 265 FT_StreamRec stream; 266 267 png_structp png; 268 png_infop info; 269 png_uint_32 imgWidth, imgHeight; 270 271 int bitdepth, color_type, interlace; 272 FT_Int i; 273 274 /* `rows` gets modified within a 'setjmp' scope; */ 275 /* we thus need the `volatile` keyword. */ 276 png_byte* *volatile rows = NULL; 277 278 279 if ( x_offset < 0 || 280 y_offset < 0 ) 281 { 282 error = FT_THROW( Invalid_Argument ); 283 goto Exit; 284 } 285 286 if ( !populate_map_and_metrics && 287 ( (FT_UInt)x_offset + metrics->width > map->width || 288 (FT_UInt)y_offset + metrics->height > map->rows || 289 pix_bits != 32 || 290 map->pixel_mode != FT_PIXEL_MODE_BGRA ) ) 291 { 292 error = FT_THROW( Invalid_Argument ); 293 goto Exit; 294 } 295 296 FT_Stream_OpenMemory( &stream, data, png_len ); 297 298 png = png_create_read_struct( PNG_LIBPNG_VER_STRING, 299 &error, 300 error_callback, 301 warning_callback ); 302 if ( !png ) 303 { 304 error = FT_THROW( Out_Of_Memory ); 305 goto Exit; 306 } 307 308 info = png_create_info_struct( png ); 309 if ( !info ) 310 { 311 error = FT_THROW( Out_Of_Memory ); 312 png_destroy_read_struct( &png, NULL, NULL ); 313 goto Exit; 314 } 315 316 if ( ft_setjmp( png_jmpbuf( png ) ) ) 317 { 318 error = FT_THROW( Invalid_File_Format ); 319 goto DestroyExit; 320 } 321 322 png_set_read_fn( png, &stream, read_data_from_FT_Stream ); 323 324 png_read_info( png, info ); 325 png_get_IHDR( png, info, 326 &imgWidth, &imgHeight, 327 &bitdepth, &color_type, &interlace, 328 NULL, NULL ); 329 330 if ( error || 331 ( !populate_map_and_metrics && 332 ( (FT_Int)imgWidth != metrics->width || 333 (FT_Int)imgHeight != metrics->height ) ) ) 334 goto DestroyExit; 335 336 if ( populate_map_and_metrics ) 337 { 338 /* reject too large bitmaps similarly to the rasterizer */ 339 if ( imgHeight > 0x7FFF || imgWidth > 0x7FFF ) 340 { 341 error = FT_THROW( Array_Too_Large ); 342 goto DestroyExit; 343 } 344 345 metrics->width = (FT_UShort)imgWidth; 346 metrics->height = (FT_UShort)imgHeight; 347 348 map->width = metrics->width; 349 map->rows = metrics->height; 350 map->pixel_mode = FT_PIXEL_MODE_BGRA; 351 map->pitch = (int)( map->width * 4 ); 352 map->num_grays = 256; 353 } 354 355 /* convert palette/gray image to rgb */ 356 if ( color_type == PNG_COLOR_TYPE_PALETTE ) 357 png_set_palette_to_rgb( png ); 358 359 /* expand gray bit depth if needed */ 360 if ( color_type == PNG_COLOR_TYPE_GRAY ) 361 { 362 #if PNG_LIBPNG_VER >= 10209 363 png_set_expand_gray_1_2_4_to_8( png ); 364 #else 365 png_set_gray_1_2_4_to_8( png ); 366 #endif 367 } 368 369 /* transform transparency to alpha */ 370 if ( png_get_valid(png, info, PNG_INFO_tRNS ) ) 371 png_set_tRNS_to_alpha( png ); 372 373 if ( bitdepth == 16 ) 374 png_set_strip_16( png ); 375 376 if ( bitdepth < 8 ) 377 png_set_packing( png ); 378 379 /* convert grayscale to RGB */ 380 if ( color_type == PNG_COLOR_TYPE_GRAY || 381 color_type == PNG_COLOR_TYPE_GRAY_ALPHA ) 382 png_set_gray_to_rgb( png ); 383 384 if ( interlace != PNG_INTERLACE_NONE ) 385 png_set_interlace_handling( png ); 386 387 png_set_filler( png, 0xFF, PNG_FILLER_AFTER ); 388 389 /* recheck header after setting EXPAND options */ 390 png_read_update_info(png, info ); 391 png_get_IHDR( png, info, 392 &imgWidth, &imgHeight, 393 &bitdepth, &color_type, &interlace, 394 NULL, NULL ); 395 396 if ( bitdepth != 8 || 397 !( color_type == PNG_COLOR_TYPE_RGB || 398 color_type == PNG_COLOR_TYPE_RGB_ALPHA ) ) 399 { 400 error = FT_THROW( Invalid_File_Format ); 401 goto DestroyExit; 402 } 403 404 if ( metrics_only ) 405 goto DestroyExit; 406 407 switch ( color_type ) 408 { 409 default: 410 /* Shouldn't happen, but fall through. */ 411 412 case PNG_COLOR_TYPE_RGB_ALPHA: 413 png_set_read_user_transform_fn( png, premultiply_data ); 414 break; 415 416 case PNG_COLOR_TYPE_RGB: 417 /* Humm, this smells. Carry on though. */ 418 png_set_read_user_transform_fn( png, convert_bytes_to_data ); 419 break; 420 } 421 422 if ( populate_map_and_metrics ) 423 { 424 /* this doesn't overflow: 0x7FFF * 0x7FFF * 4 < 2^32 */ 425 FT_ULong size = map->rows * (FT_ULong)map->pitch; 426 427 428 error = ft_glyphslot_alloc_bitmap( slot, size ); 429 if ( error ) 430 goto DestroyExit; 431 } 432 433 if ( FT_QNEW_ARRAY( rows, imgHeight ) ) 434 { 435 error = FT_THROW( Out_Of_Memory ); 436 goto DestroyExit; 437 } 438 439 for ( i = 0; i < (FT_Int)imgHeight; i++ ) 440 rows[i] = map->buffer + ( y_offset + i ) * map->pitch + x_offset * 4; 441 442 png_read_image( png, rows ); 443 444 png_read_end( png, info ); 445 446 DestroyExit: 447 /* even if reading fails with longjmp, rows must be freed */ 448 FT_FREE( rows ); 449 png_destroy_read_struct( &png, &info, NULL ); 450 FT_Stream_Close( &stream ); 451 452 Exit: 453 return error; 454 } 455 456 #else /* !(TT_CONFIG_OPTION_EMBEDDED_BITMAPS && FT_CONFIG_OPTION_USE_PNG) */ 457 458 /* ANSI C doesn't like empty source files */ 459 typedef int _pngshim_dummy; 460 461 #endif /* !(TT_CONFIG_OPTION_EMBEDDED_BITMAPS && FT_CONFIG_OPTION_USE_PNG) */ 462 463 464 /* END */ 465