Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /***************************************************************************/
  2. /*                                                                         */
  3. /*  pngshim.c                                                              */
  4. /*                                                                         */
  5. /*    PNG Bitmap glyph support.                                            */
  6. /*                                                                         */
  7. /*  Copyright 2013 by Google, Inc.                                         */
  8. /*  Written by Stuart Gill and Behdad Esfahbod.                            */
  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_STREAM_H
  22. #include FT_TRUETYPE_TAGS_H
  23. #include FT_CONFIG_STANDARD_LIBRARY_H
  24.  
  25.  
  26. #ifdef FT_CONFIG_OPTION_USE_PNG
  27.  
  28.   /* We always include <stjmp.h>, so make libpng shut up! */
  29. #define PNG_SKIP_SETJMP_CHECK 1
  30. #include <png.h>
  31. #include "pngshim.h"
  32.  
  33. #include "sferrors.h"
  34.  
  35.  
  36.   /* This code is freely based on cairo-png.c.  There's so many ways */
  37.   /* to call libpng, and the way cairo does it is defacto standard.  */
  38.  
  39.   static int
  40.   multiply_alpha( int  alpha,
  41.                   int  color )
  42.   {
  43.     int  temp = ( alpha * color ) + 0x80;
  44.  
  45.  
  46.     return ( temp + ( temp >> 8 ) ) >> 8;
  47.   }
  48.  
  49.  
  50.   /* Premultiplies data and converts RGBA bytes => native endian. */
  51.   static void
  52.   premultiply_data( png_structp    png,
  53.                     png_row_infop  row_info,
  54.                     png_bytep      data )
  55.   {
  56.     unsigned int  i;
  57.  
  58.     FT_UNUSED( png );
  59.  
  60.  
  61.     for ( i = 0; i < row_info->rowbytes; i += 4 )
  62.     {
  63.       unsigned char*  base  = &data[i];
  64.       unsigned int    alpha = base[3];
  65.  
  66.  
  67.       if ( alpha == 0 )
  68.         base[0] = base[1] = base[2] = base[3] = 0;
  69.  
  70.       else
  71.       {
  72.         unsigned int  red   = base[0];
  73.         unsigned int  green = base[1];
  74.         unsigned int  blue  = base[2];
  75.  
  76.  
  77.         if ( alpha != 0xFF )
  78.         {
  79.           red   = multiply_alpha( alpha, red   );
  80.           green = multiply_alpha( alpha, green );
  81.           blue  = multiply_alpha( alpha, blue  );
  82.         }
  83.  
  84.         base[0] = blue;
  85.         base[1] = green;
  86.         base[2] = red;
  87.         base[3] = alpha;
  88.       }
  89.     }
  90.   }
  91.  
  92.  
  93.   /* Converts RGBx bytes to BGRA. */
  94.   static void
  95.   convert_bytes_to_data( png_structp    png,
  96.                          png_row_infop  row_info,
  97.                          png_bytep      data )
  98.   {
  99.     unsigned int  i;
  100.  
  101.     FT_UNUSED( png );
  102.  
  103.  
  104.     for ( i = 0; i < row_info->rowbytes; i += 4 )
  105.     {
  106.       unsigned char*  base  = &data[i];
  107.       unsigned int    red   = base[0];
  108.       unsigned int    green = base[1];
  109.       unsigned int    blue  = base[2];
  110.  
  111.  
  112.       base[0] = blue;
  113.       base[1] = green;
  114.       base[2] = red;
  115.       base[3] = 0xFF;
  116.     }
  117.   }
  118.  
  119.  
  120.   /* Use error callback to avoid png writing to stderr. */
  121.   static void
  122.   error_callback( png_structp      png,
  123.                   png_const_charp  error_msg )
  124.   {
  125.     FT_Error*  error = png_get_error_ptr( png );
  126.  
  127.     FT_UNUSED( error_msg );
  128.  
  129.  
  130.     *error = FT_THROW( Out_Of_Memory );
  131. #ifdef PNG_SETJMP_SUPPORTED
  132.     longjmp( png_jmpbuf( png ), 1 );
  133. #endif
  134.     /* if we get here, then we have no choice but to abort ... */
  135.   }
  136.  
  137.  
  138.   /* Use warning callback to avoid png writing to stderr. */
  139.   static void
  140.   warning_callback( png_structp      png,
  141.                     png_const_charp  error_msg )
  142.   {
  143.     FT_UNUSED( png );
  144.     FT_UNUSED( error_msg );
  145.  
  146.     /* Just ignore warnings. */
  147.   }
  148.  
  149.  
  150.   static void
  151.   read_data_from_FT_Stream( png_structp  png,
  152.                             png_bytep    data,
  153.                             png_size_t   length )
  154.   {
  155.     FT_Error   error;
  156.     png_voidp  p      = png_get_io_ptr( png );
  157.     FT_Stream  stream = (FT_Stream)p;
  158.  
  159.  
  160.     if ( FT_FRAME_ENTER( length ) )
  161.     {
  162.       FT_Error*  e = png_get_error_ptr( png );
  163.  
  164.  
  165.       *e = FT_THROW( Invalid_Stream_Read );
  166.       png_error( png, NULL );
  167.  
  168.       return;
  169.     }
  170.  
  171.     memcpy( data, stream->cursor, length );
  172.  
  173.     FT_FRAME_EXIT();
  174.   }
  175.  
  176.  
  177.   static FT_Error
  178.   Load_SBit_Png( FT_Bitmap*       map,
  179.                  FT_Int           x_offset,
  180.                  FT_Int           y_offset,
  181.                  FT_Int           pix_bits,
  182.                  TT_SBit_Metrics  metrics,
  183.                  FT_Memory        memory,
  184.                  FT_Byte*         data,
  185.                  FT_UInt          png_len )
  186.   {
  187.     FT_Error      error = FT_Err_Ok;
  188.     FT_StreamRec  stream;
  189.  
  190.     png_structp  png;
  191.     png_infop    info;
  192.     png_uint_32  imgWidth, imgHeight;
  193.  
  194.     int         bitdepth, color_type, interlace;
  195.     FT_Int      i;
  196.     png_byte*  *rows;
  197.  
  198.  
  199.     if ( x_offset < 0 || x_offset + metrics->width  > map->width ||
  200.          y_offset < 0 || y_offset + metrics->height > map->rows  ||
  201.          pix_bits != 32 || map->pixel_mode != FT_PIXEL_MODE_BGRA )
  202.     {
  203.       error = FT_THROW( Invalid_Argument );
  204.       goto Exit;
  205.     }
  206.  
  207.     FT_Stream_OpenMemory( &stream, data, png_len );
  208.  
  209.     png = png_create_read_struct( PNG_LIBPNG_VER_STRING,
  210.                                   &error,
  211.                                   error_callback,
  212.                                   warning_callback );
  213.     if ( !png )
  214.     {
  215.       error = FT_THROW( Out_Of_Memory );
  216.       goto Exit;
  217.     }
  218.  
  219.     info = png_create_info_struct( png );
  220.     if ( !info )
  221.     {
  222.       error = FT_THROW( Out_Of_Memory );
  223.       png_destroy_read_struct( &png, NULL, NULL );
  224.       goto Exit;
  225.     }
  226.  
  227.     if ( ft_setjmp( png_jmpbuf( png ) ) )
  228.     {
  229.       error = FT_THROW( Invalid_File_Format );
  230.       goto DestroyExit;
  231.     }
  232.  
  233.     png_set_read_fn( png, &stream, read_data_from_FT_Stream );
  234.  
  235.     png_read_info( png, info );
  236.     png_get_IHDR( png, info,
  237.                   &imgWidth, &imgHeight,
  238.                   &bitdepth, &color_type, &interlace,
  239.                   NULL, NULL );
  240.  
  241.     if ( error != FT_Err_Ok                   ||
  242.          (FT_Int)imgWidth  != metrics->width  ||
  243.          (FT_Int)imgHeight != metrics->height )
  244.       goto DestroyExit;
  245.  
  246.     /* convert palette/gray image to rgb */
  247.     if ( color_type == PNG_COLOR_TYPE_PALETTE )
  248.       png_set_palette_to_rgb( png );
  249.  
  250.     /* expand gray bit depth if needed */
  251.     if ( color_type == PNG_COLOR_TYPE_GRAY )
  252.     {
  253. #if PNG_LIBPNG_VER >= 10209
  254.       png_set_expand_gray_1_2_4_to_8( png );
  255. #else
  256.       png_set_gray_1_2_4_to_8( png );
  257. #endif
  258.     }
  259.  
  260.     /* transform transparency to alpha */
  261.     if ( png_get_valid(png, info, PNG_INFO_tRNS ) )
  262.       png_set_tRNS_to_alpha( png );
  263.  
  264.     if ( bitdepth == 16 )
  265.       png_set_strip_16( png );
  266.  
  267.     if ( bitdepth < 8 )
  268.       png_set_packing( png );
  269.  
  270.     /* convert grayscale to RGB */
  271.     if ( color_type == PNG_COLOR_TYPE_GRAY       ||
  272.          color_type == PNG_COLOR_TYPE_GRAY_ALPHA )
  273.       png_set_gray_to_rgb( png );
  274.  
  275.     if ( interlace != PNG_INTERLACE_NONE )
  276.       png_set_interlace_handling( png );
  277.  
  278.     png_set_filler( png, 0xFF, PNG_FILLER_AFTER );
  279.  
  280.     /* recheck header after setting EXPAND options */
  281.     png_read_update_info(png, info );
  282.     png_get_IHDR( png, info,
  283.                   &imgWidth, &imgHeight,
  284.                   &bitdepth, &color_type, &interlace,
  285.                   NULL, NULL );
  286.  
  287.     if ( bitdepth != 8                              ||
  288.         !( color_type == PNG_COLOR_TYPE_RGB       ||
  289.            color_type == PNG_COLOR_TYPE_RGB_ALPHA ) )
  290.     {
  291.       error = FT_THROW( Invalid_File_Format );
  292.       goto DestroyExit;
  293.     }
  294.  
  295.     switch ( color_type )
  296.     {
  297.     default:
  298.       /* Shouldn't happen, but fall through. */
  299.  
  300.     case PNG_COLOR_TYPE_RGB_ALPHA:
  301.       png_set_read_user_transform_fn( png, premultiply_data );
  302.       break;
  303.  
  304.     case PNG_COLOR_TYPE_RGB:
  305.       /* Humm, this smells.  Carry on though. */
  306.       png_set_read_user_transform_fn( png, convert_bytes_to_data );
  307.       break;
  308.     }
  309.  
  310.     if ( FT_NEW_ARRAY( rows, imgHeight ) )
  311.     {
  312.       error = FT_THROW( Out_Of_Memory );
  313.       goto DestroyExit;
  314.     }
  315.  
  316.     for ( i = 0; i < (FT_Int)imgHeight; i++ )
  317.       rows[i] = map->buffer + ( y_offset + i ) * map->pitch + x_offset * 4;
  318.  
  319.     png_read_image( png, rows );
  320.  
  321.     FT_FREE( rows );
  322.  
  323.     png_read_end( png, info );
  324.  
  325.   DestroyExit:
  326.     png_destroy_read_struct( &png, &info, NULL );
  327.     FT_Stream_Close( &stream );
  328.  
  329.   Exit:
  330.     return error;
  331.   }
  332.  
  333. #endif /* FT_CONFIG_OPTION_USE_PNG */
  334.  
  335.  
  336. /* END */
  337.