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