1 /****************************************************************************
   2  *
   3  * pngshim.c
   4  *
   5  *   PNG Bitmap glyph support.
   6  *
   7  * Copyright (C) 2013-2019 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 */