XFA: merge patch from CL 815103002
[pdfium.git] / third_party / freetype / src / sfnt / pngshim.c
1 /***************************************************************************/
2 /*                                                                         */
3 /*  pngshim.c                                                              */
4 /*                                                                         */
5 /*    PNG Bitmap glyph support.                                            */
6 /*                                                                         */
7 /*  Copyright 2013, 2014 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 = (FT_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     ft_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 = (FT_Error*)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   FT_LOCAL_DEF( FT_Error )
178   Load_SBit_Png( FT_GlyphSlot     slot,
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                  FT_Bool          populate_map_and_metrics )
187   {
188     FT_Bitmap    *map   = &slot->bitmap;
189     FT_Error      error = FT_Err_Ok;
190     FT_StreamRec  stream;
191
192     png_structp  png;
193     png_infop    info;
194     png_uint_32  imgWidth, imgHeight;
195
196     int         bitdepth, color_type, interlace;
197     FT_Int      i;
198     png_byte*  *rows = NULL; /* pacify compiler */
199
200
201     if ( x_offset < 0 ||
202          y_offset < 0 )
203     {
204       error = FT_THROW( Invalid_Argument );
205       goto Exit;
206     }
207
208     if ( !populate_map_and_metrics                            &&
209          ( (FT_UInt)x_offset + metrics->width  > map->width ||
210            (FT_UInt)y_offset + metrics->height > map->rows  ||
211            pix_bits != 32                                   ||
212            map->pixel_mode != FT_PIXEL_MODE_BGRA            ) )
213     {
214       error = FT_THROW( Invalid_Argument );
215       goto Exit;
216     }
217
218     FT_Stream_OpenMemory( &stream, data, png_len );
219
220     png = png_create_read_struct( PNG_LIBPNG_VER_STRING,
221                                   &error,
222                                   error_callback,
223                                   warning_callback );
224     if ( !png )
225     {
226       error = FT_THROW( Out_Of_Memory );
227       goto Exit;
228     }
229
230     info = png_create_info_struct( png );
231     if ( !info )
232     {
233       error = FT_THROW( Out_Of_Memory );
234       png_destroy_read_struct( &png, NULL, NULL );
235       goto Exit;
236     }
237
238     if ( ft_setjmp( png_jmpbuf( png ) ) )
239     {
240       error = FT_THROW( Invalid_File_Format );
241       goto DestroyExit;
242     }
243
244     png_set_read_fn( png, &stream, read_data_from_FT_Stream );
245
246     png_read_info( png, info );
247     png_get_IHDR( png, info,
248                   &imgWidth, &imgHeight,
249                   &bitdepth, &color_type, &interlace,
250                   NULL, NULL );
251
252     if ( error                                        ||
253          ( !populate_map_and_metrics                &&
254            ( (FT_Int)imgWidth  != metrics->width  ||
255              (FT_Int)imgHeight != metrics->height ) ) )
256       goto DestroyExit;
257
258     if ( populate_map_and_metrics )
259     {
260       FT_Long  size;
261
262
263       metrics->width  = (FT_Int)imgWidth;
264       metrics->height = (FT_Int)imgHeight;
265
266       map->width      = metrics->width;
267       map->rows       = metrics->height;
268       map->pixel_mode = FT_PIXEL_MODE_BGRA;
269       map->pitch      = map->width * 4;
270       map->num_grays  = 256;
271
272       /* reject too large bitmaps similarly to the rasterizer */
273       if ( map->rows > 0x7FFF || map->width > 0x7FFF )
274       {
275         error = FT_THROW( Array_Too_Large );
276         goto DestroyExit;
277       }
278
279       /* this doesn't overflow: 0x7FFF * 0x7FFF * 4 < 2^32 */
280       size = map->rows * map->pitch;
281
282       error = ft_glyphslot_alloc_bitmap( slot, size );
283       if ( error )
284         goto DestroyExit;
285     }
286
287     /* convert palette/gray image to rgb */
288     if ( color_type == PNG_COLOR_TYPE_PALETTE )
289       png_set_palette_to_rgb( png );
290
291     /* expand gray bit depth if needed */
292     if ( color_type == PNG_COLOR_TYPE_GRAY )
293     {
294 #if PNG_LIBPNG_VER >= 10209
295       png_set_expand_gray_1_2_4_to_8( png );
296 #else
297       png_set_gray_1_2_4_to_8( png );
298 #endif
299     }
300
301     /* transform transparency to alpha */
302     if ( png_get_valid(png, info, PNG_INFO_tRNS ) )
303       png_set_tRNS_to_alpha( png );
304
305     if ( bitdepth == 16 )
306       png_set_strip_16( png );
307
308     if ( bitdepth < 8 )
309       png_set_packing( png );
310
311     /* convert grayscale to RGB */
312     if ( color_type == PNG_COLOR_TYPE_GRAY       ||
313          color_type == PNG_COLOR_TYPE_GRAY_ALPHA )
314       png_set_gray_to_rgb( png );
315
316     if ( interlace != PNG_INTERLACE_NONE )
317       png_set_interlace_handling( png );
318
319     png_set_filler( png, 0xFF, PNG_FILLER_AFTER );
320
321     /* recheck header after setting EXPAND options */
322     png_read_update_info(png, info );
323     png_get_IHDR( png, info,
324                   &imgWidth, &imgHeight,
325                   &bitdepth, &color_type, &interlace,
326                   NULL, NULL );
327
328     if ( bitdepth != 8                              ||
329         !( color_type == PNG_COLOR_TYPE_RGB       ||
330            color_type == PNG_COLOR_TYPE_RGB_ALPHA ) )
331     {
332       error = FT_THROW( Invalid_File_Format );
333       goto DestroyExit;
334     }
335
336     switch ( color_type )
337     {
338     default:
339       /* Shouldn't happen, but fall through. */
340
341     case PNG_COLOR_TYPE_RGB_ALPHA:
342       png_set_read_user_transform_fn( png, premultiply_data );
343       break;
344
345     case PNG_COLOR_TYPE_RGB:
346       /* Humm, this smells.  Carry on though. */
347       png_set_read_user_transform_fn( png, convert_bytes_to_data );
348       break;
349     }
350
351     if ( FT_NEW_ARRAY( rows, imgHeight ) )
352     {
353       error = FT_THROW( Out_Of_Memory );
354       goto DestroyExit;
355     }
356
357     for ( i = 0; i < (FT_Int)imgHeight; i++ )
358       rows[i] = map->buffer + ( y_offset + i ) * map->pitch + x_offset * 4;
359
360     png_read_image( png, rows );
361
362     FT_FREE( rows );
363
364     png_read_end( png, info );
365
366   DestroyExit:
367     png_destroy_read_struct( &png, &info, NULL );
368     FT_Stream_Close( &stream );
369
370   Exit:
371     return error;
372   }
373
374 #endif /* FT_CONFIG_OPTION_USE_PNG */
375
376
377 /* END */