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 */
457