1 | /**************************************************************************** |
2 | * |
3 | * pfrsbit.c |
4 | * |
5 | * FreeType PFR bitmap loader (body). |
6 | * |
7 | * Copyright (C) 2002-2023 by |
8 | * David Turner, Robert Wilhelm, and Werner Lemberg. |
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 "pfrsbit.h" |
20 | #include "pfrload.h" |
21 | #include <freetype/internal/ftdebug.h> |
22 | #include <freetype/internal/ftstream.h> |
23 | |
24 | #include "pfrerror.h" |
25 | |
26 | #undef FT_COMPONENT |
27 | #define FT_COMPONENT pfr |
28 | |
29 | |
30 | /*************************************************************************/ |
31 | /*************************************************************************/ |
32 | /***** *****/ |
33 | /***** PFR BIT WRITER *****/ |
34 | /***** *****/ |
35 | /*************************************************************************/ |
36 | /*************************************************************************/ |
37 | |
38 | typedef struct PFR_BitWriter_ |
39 | { |
40 | FT_Byte* line; /* current line start */ |
41 | FT_Int pitch; /* line size in bytes */ |
42 | FT_UInt width; /* width in pixels/bits */ |
43 | FT_UInt rows; /* number of remaining rows to scan */ |
44 | FT_UInt total; /* total number of bits to draw */ |
45 | |
46 | } PFR_BitWriterRec, *PFR_BitWriter; |
47 | |
48 | |
49 | static void |
50 | pfr_bitwriter_init( PFR_BitWriter writer, |
51 | FT_Bitmap* target, |
52 | FT_Bool decreasing ) |
53 | { |
54 | writer->line = target->buffer; |
55 | writer->pitch = target->pitch; |
56 | writer->width = target->width; |
57 | writer->rows = target->rows; |
58 | writer->total = writer->width * writer->rows; |
59 | |
60 | if ( !decreasing ) |
61 | { |
62 | writer->line += writer->pitch * (FT_Int)( target->rows - 1 ); |
63 | writer->pitch = -writer->pitch; |
64 | } |
65 | } |
66 | |
67 | |
68 | static void |
69 | pfr_bitwriter_decode_bytes( PFR_BitWriter writer, |
70 | FT_Byte* p, |
71 | FT_Byte* limit ) |
72 | { |
73 | FT_UInt n, reload; |
74 | FT_UInt left = writer->width; |
75 | FT_Byte* cur = writer->line; |
76 | FT_UInt mask = 0x80; |
77 | FT_UInt val = 0; |
78 | FT_UInt c = 0; |
79 | |
80 | |
81 | n = (FT_UInt)( limit - p ) * 8; |
82 | if ( n > writer->total ) |
83 | n = writer->total; |
84 | |
85 | reload = n & 7; |
86 | |
87 | for ( ; n > 0; n-- ) |
88 | { |
89 | if ( ( n & 7 ) == reload ) |
90 | val = *p++; |
91 | |
92 | if ( val & 0x80 ) |
93 | c |= mask; |
94 | |
95 | val <<= 1; |
96 | mask >>= 1; |
97 | |
98 | if ( --left <= 0 ) |
99 | { |
100 | cur[0] = (FT_Byte)c; |
101 | left = writer->width; |
102 | mask = 0x80; |
103 | |
104 | writer->line += writer->pitch; |
105 | cur = writer->line; |
106 | c = 0; |
107 | } |
108 | else if ( mask == 0 ) |
109 | { |
110 | cur[0] = (FT_Byte)c; |
111 | mask = 0x80; |
112 | c = 0; |
113 | cur++; |
114 | } |
115 | } |
116 | |
117 | if ( mask != 0x80 ) |
118 | cur[0] = (FT_Byte)c; |
119 | } |
120 | |
121 | |
122 | static void |
123 | pfr_bitwriter_decode_rle1( PFR_BitWriter writer, |
124 | FT_Byte* p, |
125 | FT_Byte* limit ) |
126 | { |
127 | FT_Int phase, count, counts[2]; |
128 | FT_UInt n, reload; |
129 | FT_UInt left = writer->width; |
130 | FT_Byte* cur = writer->line; |
131 | FT_UInt mask = 0x80; |
132 | FT_UInt c = 0; |
133 | |
134 | |
135 | n = writer->total; |
136 | |
137 | phase = 1; |
138 | counts[0] = 0; |
139 | counts[1] = 0; |
140 | count = 0; |
141 | reload = 1; |
142 | |
143 | for ( ; n > 0; n-- ) |
144 | { |
145 | if ( reload ) |
146 | { |
147 | do |
148 | { |
149 | if ( phase ) |
150 | { |
151 | FT_Int v; |
152 | |
153 | |
154 | if ( p >= limit ) |
155 | break; |
156 | |
157 | v = *p++; |
158 | counts[0] = v >> 4; |
159 | counts[1] = v & 15; |
160 | phase = 0; |
161 | count = counts[0]; |
162 | } |
163 | else |
164 | { |
165 | phase = 1; |
166 | count = counts[1]; |
167 | } |
168 | |
169 | } while ( count == 0 ); |
170 | } |
171 | |
172 | if ( phase ) |
173 | c |= mask; |
174 | |
175 | mask >>= 1; |
176 | |
177 | if ( --left <= 0 ) |
178 | { |
179 | cur[0] = (FT_Byte)c; |
180 | left = writer->width; |
181 | mask = 0x80; |
182 | |
183 | writer->line += writer->pitch; |
184 | cur = writer->line; |
185 | c = 0; |
186 | } |
187 | else if ( mask == 0 ) |
188 | { |
189 | cur[0] = (FT_Byte)c; |
190 | mask = 0x80; |
191 | c = 0; |
192 | cur++; |
193 | } |
194 | |
195 | reload = ( --count <= 0 ); |
196 | } |
197 | |
198 | if ( mask != 0x80 ) |
199 | cur[0] = (FT_Byte) c; |
200 | } |
201 | |
202 | |
203 | static void |
204 | pfr_bitwriter_decode_rle2( PFR_BitWriter writer, |
205 | FT_Byte* p, |
206 | FT_Byte* limit ) |
207 | { |
208 | FT_Int phase, count; |
209 | FT_UInt n, reload; |
210 | FT_UInt left = writer->width; |
211 | FT_Byte* cur = writer->line; |
212 | FT_UInt mask = 0x80; |
213 | FT_UInt c = 0; |
214 | |
215 | |
216 | n = writer->total; |
217 | |
218 | phase = 1; |
219 | count = 0; |
220 | reload = 1; |
221 | |
222 | for ( ; n > 0; n-- ) |
223 | { |
224 | if ( reload ) |
225 | { |
226 | do |
227 | { |
228 | if ( p >= limit ) |
229 | break; |
230 | |
231 | count = *p++; |
232 | phase = phase ^ 1; |
233 | |
234 | } while ( count == 0 ); |
235 | } |
236 | |
237 | if ( phase ) |
238 | c |= mask; |
239 | |
240 | mask >>= 1; |
241 | |
242 | if ( --left <= 0 ) |
243 | { |
244 | cur[0] = (FT_Byte)c; |
245 | c = 0; |
246 | mask = 0x80; |
247 | left = writer->width; |
248 | |
249 | writer->line += writer->pitch; |
250 | cur = writer->line; |
251 | } |
252 | else if ( mask == 0 ) |
253 | { |
254 | cur[0] = (FT_Byte)c; |
255 | c = 0; |
256 | mask = 0x80; |
257 | cur++; |
258 | } |
259 | |
260 | reload = ( --count <= 0 ); |
261 | } |
262 | |
263 | if ( mask != 0x80 ) |
264 | cur[0] = (FT_Byte) c; |
265 | } |
266 | |
267 | |
268 | /*************************************************************************/ |
269 | /*************************************************************************/ |
270 | /***** *****/ |
271 | /***** BITMAP DATA DECODING *****/ |
272 | /***** *****/ |
273 | /*************************************************************************/ |
274 | /*************************************************************************/ |
275 | |
276 | static void |
277 | pfr_lookup_bitmap_data( FT_Byte* base, |
278 | FT_Byte* limit, |
279 | FT_UInt count, |
280 | FT_UInt* flags, |
281 | FT_UInt char_code, |
282 | FT_ULong* found_offset, |
283 | FT_ULong* found_size ) |
284 | { |
285 | FT_UInt min, max, mid, char_len; |
286 | FT_Bool two = FT_BOOL( *flags & PFR_BITMAP_2BYTE_CHARCODE ); |
287 | FT_Byte* buff; |
288 | |
289 | |
290 | char_len = 4; |
291 | if ( two ) |
292 | char_len += 1; |
293 | if ( *flags & PFR_BITMAP_2BYTE_SIZE ) |
294 | char_len += 1; |
295 | if ( *flags & PFR_BITMAP_3BYTE_OFFSET ) |
296 | char_len += 1; |
297 | |
298 | if ( !( *flags & PFR_BITMAP_CHARCODES_VALIDATED ) ) |
299 | { |
300 | FT_Byte* p; |
301 | FT_Byte* lim; |
302 | FT_UInt code; |
303 | FT_Long prev_code; |
304 | |
305 | |
306 | *flags |= PFR_BITMAP_VALID_CHARCODES; |
307 | prev_code = -1; |
308 | lim = base + count * char_len; |
309 | |
310 | if ( lim > limit ) |
311 | { |
312 | FT_TRACE0(( "pfr_lookup_bitmap_data:" |
313 | " number of bitmap records too large,\n" )); |
314 | FT_TRACE0(( " " |
315 | " thus ignoring all bitmaps in this strike\n" )); |
316 | *flags &= ~PFR_BITMAP_VALID_CHARCODES; |
317 | } |
318 | else |
319 | { |
320 | /* check whether records are sorted by code */ |
321 | for ( p = base; p < lim; p += char_len ) |
322 | { |
323 | if ( two ) |
324 | code = FT_PEEK_USHORT( p ); |
325 | else |
326 | code = *p; |
327 | |
328 | if ( (FT_Long)code <= prev_code ) |
329 | { |
330 | FT_TRACE0(( "pfr_lookup_bitmap_data:" |
331 | " bitmap records are not sorted,\n" )); |
332 | FT_TRACE0(( " " |
333 | " thus ignoring all bitmaps in this strike\n" )); |
334 | *flags &= ~PFR_BITMAP_VALID_CHARCODES; |
335 | break; |
336 | } |
337 | |
338 | prev_code = code; |
339 | } |
340 | } |
341 | |
342 | *flags |= PFR_BITMAP_CHARCODES_VALIDATED; |
343 | } |
344 | |
345 | /* ignore bitmaps in case table is not valid */ |
346 | /* (this might be sanitized, but PFR is dead...) */ |
347 | if ( !( *flags & PFR_BITMAP_VALID_CHARCODES ) ) |
348 | goto Fail; |
349 | |
350 | min = 0; |
351 | max = count; |
352 | mid = min + ( max - min ) / 2; |
353 | |
354 | /* binary search */ |
355 | while ( min < max ) |
356 | { |
357 | FT_UInt code; |
358 | |
359 | |
360 | buff = base + mid * char_len; |
361 | |
362 | if ( two ) |
363 | code = PFR_NEXT_USHORT( buff ); |
364 | else |
365 | code = PFR_NEXT_BYTE( buff ); |
366 | |
367 | if ( char_code < code ) |
368 | max = mid; |
369 | else if ( char_code > code ) |
370 | min = mid + 1; |
371 | else |
372 | goto Found_It; |
373 | |
374 | /* reasonable prediction in a continuous block */ |
375 | mid += char_code - code; |
376 | if ( mid >= max || mid < min ) |
377 | mid = min + ( max - min ) / 2; |
378 | } |
379 | |
380 | Fail: |
381 | /* Not found */ |
382 | *found_size = 0; |
383 | *found_offset = 0; |
384 | return; |
385 | |
386 | Found_It: |
387 | if ( *flags & PFR_BITMAP_2BYTE_SIZE ) |
388 | *found_size = PFR_NEXT_USHORT( buff ); |
389 | else |
390 | *found_size = PFR_NEXT_BYTE( buff ); |
391 | |
392 | if ( *flags & PFR_BITMAP_3BYTE_OFFSET ) |
393 | *found_offset = PFR_NEXT_ULONG( buff ); |
394 | else |
395 | *found_offset = PFR_NEXT_USHORT( buff ); |
396 | } |
397 | |
398 | |
399 | /* load bitmap metrics. `*aadvance' must be set to the default value */ |
400 | /* before calling this function */ |
401 | /* */ |
402 | static FT_Error |
403 | pfr_load_bitmap_metrics( FT_Byte** pdata, |
404 | FT_Byte* limit, |
405 | FT_Long scaled_advance, |
406 | FT_Long *axpos, |
407 | FT_Long *aypos, |
408 | FT_UInt *axsize, |
409 | FT_UInt *aysize, |
410 | FT_Long *aadvance, |
411 | FT_UInt *aformat ) |
412 | { |
413 | FT_Error error = FT_Err_Ok; |
414 | FT_Byte flags; |
415 | FT_Byte b; |
416 | FT_Byte* p = *pdata; |
417 | FT_Long xpos, ypos, advance; |
418 | FT_UInt xsize, ysize; |
419 | |
420 | |
421 | PFR_CHECK( 1 ); |
422 | flags = PFR_NEXT_BYTE( p ); |
423 | |
424 | xpos = 0; |
425 | ypos = 0; |
426 | xsize = 0; |
427 | ysize = 0; |
428 | advance = 0; |
429 | |
430 | switch ( flags & 3 ) |
431 | { |
432 | case 0: |
433 | PFR_CHECK( 1 ); |
434 | b = PFR_NEXT_BYTE( p ); |
435 | xpos = (FT_Char)b >> 4; |
436 | ypos = ( (FT_Char)( b << 4 ) ) >> 4; |
437 | break; |
438 | |
439 | case 1: |
440 | PFR_CHECK( 2 ); |
441 | xpos = PFR_NEXT_INT8( p ); |
442 | ypos = PFR_NEXT_INT8( p ); |
443 | break; |
444 | |
445 | case 2: |
446 | PFR_CHECK( 4 ); |
447 | xpos = PFR_NEXT_SHORT( p ); |
448 | ypos = PFR_NEXT_SHORT( p ); |
449 | break; |
450 | |
451 | case 3: |
452 | PFR_CHECK( 6 ); |
453 | xpos = PFR_NEXT_LONG( p ); |
454 | ypos = PFR_NEXT_LONG( p ); |
455 | break; |
456 | |
457 | default: |
458 | ; |
459 | } |
460 | |
461 | flags >>= 2; |
462 | switch ( flags & 3 ) |
463 | { |
464 | case 0: |
465 | /* blank image */ |
466 | xsize = 0; |
467 | ysize = 0; |
468 | break; |
469 | |
470 | case 1: |
471 | PFR_CHECK( 1 ); |
472 | b = PFR_NEXT_BYTE( p ); |
473 | xsize = ( b >> 4 ) & 0xF; |
474 | ysize = b & 0xF; |
475 | break; |
476 | |
477 | case 2: |
478 | PFR_CHECK( 2 ); |
479 | xsize = PFR_NEXT_BYTE( p ); |
480 | ysize = PFR_NEXT_BYTE( p ); |
481 | break; |
482 | |
483 | case 3: |
484 | PFR_CHECK( 4 ); |
485 | xsize = PFR_NEXT_USHORT( p ); |
486 | ysize = PFR_NEXT_USHORT( p ); |
487 | break; |
488 | |
489 | default: |
490 | ; |
491 | } |
492 | |
493 | flags >>= 2; |
494 | switch ( flags & 3 ) |
495 | { |
496 | case 0: |
497 | advance = scaled_advance; |
498 | break; |
499 | |
500 | case 1: |
501 | PFR_CHECK( 1 ); |
502 | advance = PFR_NEXT_INT8( p ) * 256; |
503 | break; |
504 | |
505 | case 2: |
506 | PFR_CHECK( 2 ); |
507 | advance = PFR_NEXT_SHORT( p ); |
508 | break; |
509 | |
510 | case 3: |
511 | PFR_CHECK( 3 ); |
512 | advance = PFR_NEXT_LONG( p ); |
513 | break; |
514 | |
515 | default: |
516 | ; |
517 | } |
518 | |
519 | *axpos = xpos; |
520 | *aypos = ypos; |
521 | *axsize = xsize; |
522 | *aysize = ysize; |
523 | *aadvance = advance; |
524 | *aformat = flags >> 2; |
525 | *pdata = p; |
526 | |
527 | Exit: |
528 | return error; |
529 | |
530 | Too_Short: |
531 | error = FT_THROW( Invalid_Table ); |
532 | FT_ERROR(( "pfr_load_bitmap_metrics: invalid glyph data\n" )); |
533 | goto Exit; |
534 | } |
535 | |
536 | |
537 | static FT_Error |
538 | pfr_load_bitmap_bits( FT_Byte* p, |
539 | FT_Byte* limit, |
540 | FT_UInt format, |
541 | FT_Bool decreasing, |
542 | FT_Bitmap* target ) |
543 | { |
544 | FT_Error error = FT_Err_Ok; |
545 | PFR_BitWriterRec writer; |
546 | |
547 | |
548 | if ( target->rows > 0 && target->width > 0 ) |
549 | { |
550 | pfr_bitwriter_init( &writer, target, decreasing ); |
551 | |
552 | switch ( format ) |
553 | { |
554 | case 0: /* packed bits */ |
555 | pfr_bitwriter_decode_bytes( &writer, p, limit ); |
556 | break; |
557 | |
558 | case 1: /* RLE1 */ |
559 | pfr_bitwriter_decode_rle1( &writer, p, limit ); |
560 | break; |
561 | |
562 | case 2: /* RLE2 */ |
563 | pfr_bitwriter_decode_rle2( &writer, p, limit ); |
564 | break; |
565 | |
566 | default: |
567 | ; |
568 | } |
569 | } |
570 | |
571 | return error; |
572 | } |
573 | |
574 | |
575 | /*************************************************************************/ |
576 | /*************************************************************************/ |
577 | /***** *****/ |
578 | /***** BITMAP LOADING *****/ |
579 | /***** *****/ |
580 | /*************************************************************************/ |
581 | /*************************************************************************/ |
582 | |
583 | FT_LOCAL_DEF( FT_Error ) |
584 | pfr_slot_load_bitmap( PFR_Slot glyph, |
585 | PFR_Size size, |
586 | FT_UInt glyph_index, |
587 | FT_Bool metrics_only ) |
588 | { |
589 | FT_Error error; |
590 | PFR_Face face = (PFR_Face) glyph->root.face; |
591 | FT_Stream stream = face->root.stream; |
592 | PFR_PhyFont phys = &face->phy_font; |
593 | FT_ULong gps_offset; |
594 | FT_ULong gps_size; |
595 | PFR_Char character; |
596 | PFR_Strike strike; |
597 | |
598 | |
599 | character = &phys->chars[glyph_index]; |
600 | |
601 | /* look up a bitmap strike corresponding to the current */ |
602 | /* character dimensions */ |
603 | { |
604 | FT_UInt n; |
605 | |
606 | |
607 | strike = phys->strikes; |
608 | for ( n = 0; n < phys->num_strikes; n++ ) |
609 | { |
610 | if ( strike->x_ppm == (FT_UInt)size->root.metrics.x_ppem && |
611 | strike->y_ppm == (FT_UInt)size->root.metrics.y_ppem ) |
612 | goto Found_Strike; |
613 | |
614 | strike++; |
615 | } |
616 | |
617 | /* couldn't find it */ |
618 | return FT_THROW( Invalid_Argument ); |
619 | } |
620 | |
621 | Found_Strike: |
622 | |
623 | /* now look up the glyph's position within the file */ |
624 | { |
625 | FT_UInt char_len; |
626 | |
627 | |
628 | char_len = 4; |
629 | if ( strike->flags & PFR_BITMAP_2BYTE_CHARCODE ) |
630 | char_len += 1; |
631 | if ( strike->flags & PFR_BITMAP_2BYTE_SIZE ) |
632 | char_len += 1; |
633 | if ( strike->flags & PFR_BITMAP_3BYTE_OFFSET ) |
634 | char_len += 1; |
635 | |
636 | /* access data directly in the frame to speed up lookups */ |
637 | if ( FT_STREAM_SEEK( phys->bct_offset + strike->bct_offset ) || |
638 | FT_FRAME_ENTER( char_len * strike->num_bitmaps ) ) |
639 | goto Exit; |
640 | |
641 | pfr_lookup_bitmap_data( stream->cursor, |
642 | stream->limit, |
643 | strike->num_bitmaps, |
644 | &strike->flags, |
645 | character->char_code, |
646 | &gps_offset, |
647 | &gps_size ); |
648 | |
649 | FT_FRAME_EXIT(); |
650 | |
651 | if ( gps_size == 0 ) |
652 | { |
653 | /* could not find a bitmap program string for this glyph */ |
654 | error = FT_THROW( Invalid_Argument ); |
655 | goto Exit; |
656 | } |
657 | } |
658 | |
659 | /* get the bitmap metrics */ |
660 | { |
661 | FT_Long xpos = 0, ypos = 0, advance = 0; |
662 | FT_UInt xsize = 0, ysize = 0, format = 0; |
663 | FT_Byte* p; |
664 | |
665 | |
666 | /* compute linear advance */ |
667 | advance = character->advance; |
668 | if ( phys->metrics_resolution != phys->outline_resolution ) |
669 | advance = FT_MulDiv( advance, |
670 | (FT_Long)phys->outline_resolution, |
671 | (FT_Long)phys->metrics_resolution ); |
672 | |
673 | glyph->root.linearHoriAdvance = advance; |
674 | |
675 | /* compute default advance, i.e., scaled advance; this can be */ |
676 | /* overridden in the bitmap header of certain glyphs */ |
677 | advance = FT_MulDiv( (FT_Fixed)size->root.metrics.x_ppem << 8, |
678 | character->advance, |
679 | (FT_Long)phys->metrics_resolution ); |
680 | |
681 | if ( FT_STREAM_SEEK( face->header.gps_section_offset + gps_offset ) || |
682 | FT_FRAME_ENTER( gps_size ) ) |
683 | goto Exit; |
684 | |
685 | p = stream->cursor; |
686 | error = pfr_load_bitmap_metrics( &p, stream->limit, |
687 | advance, |
688 | &xpos, &ypos, |
689 | &xsize, &ysize, |
690 | &advance, &format ); |
691 | if ( error ) |
692 | goto Exit1; |
693 | |
694 | /* |
695 | * Before allocating the target bitmap, we check whether the given |
696 | * bitmap dimensions are valid, depending on the image format. |
697 | * |
698 | * Format 0: We have a stream of pixels (with 8 pixels per byte). |
699 | * |
700 | * (xsize * ysize + 7) / 8 <= gps_size |
701 | * |
702 | * Format 1: Run-length encoding; the high nibble holds the number of |
703 | * white bits, the low nibble the number of black bits. In |
704 | * other words, a single byte can represent at most 15 |
705 | * pixels. |
706 | * |
707 | * xsize * ysize <= 15 * gps_size |
708 | * |
709 | * Format 2: Run-length encoding; the high byte holds the number of |
710 | * white bits, the low byte the number of black bits. In |
711 | * other words, two bytes can represent at most 255 pixels. |
712 | * |
713 | * xsize * ysize <= 255 * (gps_size + 1) / 2 |
714 | */ |
715 | switch ( format ) |
716 | { |
717 | case 0: |
718 | if ( ( (FT_ULong)xsize * ysize + 7 ) / 8 > gps_size ) |
719 | error = FT_THROW( Invalid_Table ); |
720 | break; |
721 | case 1: |
722 | if ( (FT_ULong)xsize * ysize > 15 * gps_size ) |
723 | error = FT_THROW( Invalid_Table ); |
724 | break; |
725 | case 2: |
726 | if ( (FT_ULong)xsize * ysize > 255 * ( ( gps_size + 1 ) / 2 ) ) |
727 | error = FT_THROW( Invalid_Table ); |
728 | break; |
729 | default: |
730 | FT_ERROR(( "pfr_slot_load_bitmap: invalid image type\n" )); |
731 | error = FT_THROW( Invalid_Table ); |
732 | } |
733 | |
734 | if ( error ) |
735 | { |
736 | if ( FT_ERR_EQ( error, Invalid_Table ) ) |
737 | FT_ERROR(( "pfr_slot_load_bitmap: invalid bitmap dimensions\n" )); |
738 | goto Exit1; |
739 | } |
740 | |
741 | /* |
742 | * XXX: on 16bit systems we return an error for huge bitmaps |
743 | * that cause size truncation, because truncated |
744 | * size properties make bitmap glyphs broken. |
745 | */ |
746 | if ( xpos > FT_INT_MAX || |
747 | xpos < FT_INT_MIN || |
748 | ysize > FT_INT_MAX || |
749 | ypos > FT_INT_MAX - (FT_Long)ysize || |
750 | ypos + (FT_Long)ysize < FT_INT_MIN ) |
751 | { |
752 | FT_TRACE1(( "pfr_slot_load_bitmap:" |
753 | " huge bitmap glyph %ldx%ld over FT_GlyphSlot\n" , |
754 | xpos, ypos )); |
755 | error = FT_THROW( Invalid_Pixel_Size ); |
756 | } |
757 | |
758 | if ( !error ) |
759 | { |
760 | glyph->root.format = FT_GLYPH_FORMAT_BITMAP; |
761 | |
762 | /* Set up glyph bitmap and metrics */ |
763 | |
764 | /* XXX: needs casts to fit FT_Bitmap.{width|rows|pitch} */ |
765 | glyph->root.bitmap.width = xsize; |
766 | glyph->root.bitmap.rows = ysize; |
767 | glyph->root.bitmap.pitch = (FT_Int)( xsize + 7 ) >> 3; |
768 | glyph->root.bitmap.pixel_mode = FT_PIXEL_MODE_MONO; |
769 | |
770 | /* XXX: needs casts to fit FT_Glyph_Metrics.{width|height} */ |
771 | glyph->root.metrics.width = (FT_Pos)xsize << 6; |
772 | glyph->root.metrics.height = (FT_Pos)ysize << 6; |
773 | glyph->root.metrics.horiBearingX = xpos * 64; |
774 | glyph->root.metrics.horiBearingY = ypos * 64; |
775 | glyph->root.metrics.horiAdvance = FT_PIX_ROUND( ( advance >> 2 ) ); |
776 | glyph->root.metrics.vertBearingX = - glyph->root.metrics.width >> 1; |
777 | glyph->root.metrics.vertBearingY = 0; |
778 | glyph->root.metrics.vertAdvance = size->root.metrics.height; |
779 | |
780 | /* XXX: needs casts fit FT_GlyphSlotRec.bitmap_{left|top} */ |
781 | glyph->root.bitmap_left = (FT_Int)xpos; |
782 | glyph->root.bitmap_top = (FT_Int)( ypos + (FT_Long)ysize ); |
783 | |
784 | if ( metrics_only ) |
785 | goto Exit1; |
786 | |
787 | /* Allocate and read bitmap data */ |
788 | { |
789 | FT_ULong len = (FT_ULong)glyph->root.bitmap.pitch * ysize; |
790 | |
791 | |
792 | error = ft_glyphslot_alloc_bitmap( &glyph->root, len ); |
793 | if ( !error ) |
794 | error = pfr_load_bitmap_bits( |
795 | p, |
796 | stream->limit, |
797 | format, |
798 | FT_BOOL( face->header.color_flags & |
799 | PFR_FLAG_INVERT_BITMAP ), |
800 | &glyph->root.bitmap ); |
801 | } |
802 | } |
803 | |
804 | Exit1: |
805 | FT_FRAME_EXIT(); |
806 | } |
807 | |
808 | Exit: |
809 | return error; |
810 | } |
811 | |
812 | |
813 | /* END */ |
814 | |