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