[FREETYPE] Update to v2.5.5. CORE-8888
[reactos.git] / reactos / lib / 3rdparty / 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 */