]> git.saurik.com Git - wxWidgets.git/blob - src/freetype/sfnt/ttsbit.c
Mac-ify wxTreeCtrl further.
[wxWidgets.git] / src / freetype / sfnt / ttsbit.c
1 /***************************************************************************/
2 /* */
3 /* ttsbit.c */
4 /* */
5 /* TrueType and OpenType embedded bitmap support (body). */
6 /* */
7 /* Copyright 1996-2000 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 <freetype/internal/ftdebug.h>
20 #include <freetype/internal/tterrors.h>
21 #include <freetype/tttags.h>
22
23
24 #ifdef FT_FLAT_COMPILE
25
26 #include "ttsbit.h"
27
28 #else
29
30 #include <sfnt/ttsbit.h>
31
32 #endif
33
34
35 /*************************************************************************/
36 /* */
37 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
38 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
39 /* messages during execution. */
40 /* */
41 #undef FT_COMPONENT
42 #define FT_COMPONENT trace_ttsbit
43
44
45 /*************************************************************************/
46 /* */
47 /* <Function> */
48 /* blit_sbit */
49 /* */
50 /* <Description> */
51 /* Blits a bitmap from an input stream into a given target. Supports */
52 /* x and y offsets as well as byte padded lines. */
53 /* */
54 /* <Input> */
55 /* target :: The target bitmap/pixmap. */
56 /* */
57 /* source :: The input packed bitmap data. */
58 /* */
59 /* line_bits :: The number of bits per line. */
60 /* */
61 /* byte_padded :: A flag which is true if lines are byte-padded. */
62 /* */
63 /* x_offset :: The horizontal offset. */
64 /* */
65 /* y_offset :: The vertical offset. */
66 /* */
67 /* <Note> */
68 /* IMPORTANT: The x and y offsets are relative to the top corner of */
69 /* the target bitmap (unlike the normal TrueType */
70 /* convention). A positive y offset indicates a downwards */
71 /* direction! */
72 /* */
73 static
74 void blit_sbit( FT_Bitmap* target,
75 FT_Byte* source,
76 FT_Int line_bits,
77 FT_Bool byte_padded,
78 FT_Int x_offset,
79 FT_Int y_offset )
80 {
81 FT_Byte* line_buff;
82 FT_Int line_incr;
83 FT_Int height;
84
85 FT_UShort acc;
86 FT_Byte loaded;
87
88
89 /* first of all, compute starting write position */
90 line_incr = target->pitch;
91 line_buff = target->buffer;
92
93 if ( line_incr < 0 )
94 line_buff -= line_incr * ( target->rows - 1 );
95
96 line_buff += ( x_offset >> 3 ) + y_offset * line_incr;
97
98 /***********************************************************************/
99 /* */
100 /* We use the extra-classic `accumulator' trick to extract the bits */
101 /* from the source byte stream. */
102 /* */
103 /* Namely, the variable `acc' is a 16-bit accumulator containing the */
104 /* last `loaded' bits from the input stream. The bits are shifted to */
105 /* the upmost position in `acc'. */
106 /* */
107 /***********************************************************************/
108
109 acc = 0; /* clear accumulator */
110 loaded = 0; /* no bits were loaded */
111
112 for ( height = target->rows; height > 0; height-- )
113 {
114 FT_Byte* cur = line_buff; /* current write cursor */
115 FT_Int count = line_bits; /* # of bits to extract per line */
116 FT_Byte shift = x_offset & 7; /* current write shift */
117 FT_Byte space = 8 - shift;
118
119
120 /* first of all, read individual source bytes */
121 if ( count >= 8 )
122 {
123 count -= 8;
124 {
125 do
126 {
127 FT_Byte val;
128
129
130 /* ensure that there are at least 8 bits in the accumulator */
131 if ( loaded < 8 )
132 {
133 acc |= (FT_UShort)*source++ << ( 8 - loaded );
134 loaded += 8;
135 }
136
137 /* now write one byte */
138 val = (FT_Byte)( acc >> 8 );
139 if ( shift )
140 {
141 cur[0] |= val >> shift;
142 cur[1] |= val << space;
143 }
144 else
145 cur[0] |= val;
146
147 cur++;
148 acc <<= 8; /* remove bits from accumulator */
149 loaded -= 8;
150 count -= 8;
151
152 } while ( count >= 0 );
153 }
154
155 /* restore `count' to correct value */
156 count += 8;
157 }
158
159 /* now write remaining bits (count < 8) */
160 if ( count > 0 )
161 {
162 FT_Byte val;
163
164
165 /* ensure that there are at least `count' bits in the accumulator */
166 if ( loaded < count )
167 {
168 acc |= (FT_UShort)*source++ << ( 8 - loaded );
169 loaded += 8;
170 }
171
172 /* now write remaining bits */
173 val = ( (FT_Byte)( acc >> 8 ) ) & ~( 0xFF >> count );
174 cur[0] |= val >> shift;
175
176 if ( count > space )
177 cur[1] |= val << space;
178
179 acc <<= count;
180 loaded -= count;
181 }
182
183 /* now, skip to next line */
184 if ( byte_padded )
185 acc = loaded = 0; /* clear accumulator on byte-padded lines */
186
187 line_buff += line_incr;
188 }
189 }
190
191
192 const FT_Frame_Field sbit_metrics_fields[] =
193 {
194 FT_FRAME_START( 8 ),
195 FT_FRAME_BYTE( TT_SBit_Metrics, height ),
196 FT_FRAME_BYTE( TT_SBit_Metrics, width ),
197
198 FT_FRAME_CHAR( TT_SBit_Metrics, horiBearingX ),
199 FT_FRAME_CHAR( TT_SBit_Metrics, horiBearingY ),
200 FT_FRAME_BYTE( TT_SBit_Metrics, horiAdvance ),
201
202 FT_FRAME_CHAR( TT_SBit_Metrics, vertBearingX ),
203 FT_FRAME_CHAR( TT_SBit_Metrics, vertBearingY ),
204 FT_FRAME_BYTE( TT_SBit_Metrics, vertAdvance ),
205 FT_FRAME_END
206 };
207
208
209 /*************************************************************************/
210 /* */
211 /* <Function> */
212 /* TT_Load_SBit_Const_Metrics */
213 /* */
214 /* <Description> */
215 /* Loads the metrics for `EBLC' index tables format 2 and 5. */
216 /* */
217 /* <Input> */
218 /* range :: The target range. */
219 /* */
220 /* stream :: The input stream. */
221 /* */
222 /* <Return> */
223 /* FreeType error code. 0 means success. */
224 /* */
225 static
226 FT_Error Load_SBit_Const_Metrics( TT_SBit_Range* range,
227 FT_Stream stream )
228 {
229 FT_Error error;
230
231
232 if ( READ_ULong( range->image_size ) )
233 return error;
234
235 return READ_Fields( sbit_metrics_fields, &range->metrics );
236 }
237
238
239 /*************************************************************************/
240 /* */
241 /* <Function> */
242 /* TT_Load_SBit_Range_Codes */
243 /* */
244 /* <Description> */
245 /* Loads the range codes for `EBLC' index tables format 4 and 5. */
246 /* */
247 /* <Input> */
248 /* range :: The target range. */
249 /* */
250 /* stream :: The input stream. */
251 /* */
252 /* load_offsets :: A flag whether to load the glyph offset table. */
253 /* */
254 /* <Return> */
255 /* FreeType error code. 0 means success. */
256 /* */
257 static
258 FT_Error Load_SBit_Range_Codes( TT_SBit_Range* range,
259 FT_Stream stream,
260 FT_Bool load_offsets )
261 {
262 FT_Error error;
263 FT_ULong count, n, size;
264 FT_Memory memory = stream->memory;
265
266
267 if ( READ_ULong( count ) )
268 goto Exit;
269
270 range->num_glyphs = count;
271
272 /* Allocate glyph offsets table if needed */
273 if ( load_offsets )
274 {
275 if ( ALLOC_ARRAY( range->glyph_offsets, count, FT_ULong ) )
276 goto Exit;
277
278 size = count * 4L;
279 }
280 else
281 size = count * 2L;
282
283 /* Allocate glyph codes table and access frame */
284 if ( ALLOC_ARRAY ( range->glyph_codes, count, FT_UShort ) ||
285 ACCESS_Frame( size ) )
286 goto Exit;
287
288 for ( n = 0; n < count; n++ )
289 {
290 range->glyph_codes[n] = GET_UShort();
291
292 if ( load_offsets )
293 range->glyph_offsets[n] = (FT_ULong)range->image_offset +
294 GET_UShort();
295 }
296
297 FORGET_Frame();
298
299 Exit:
300 return error;
301 }
302
303
304 /*************************************************************************/
305 /* */
306 /* <Function> */
307 /* TT_Load_SBit_Range */
308 /* */
309 /* <Description> */
310 /* Loads a given `EBLC' index/range table. */
311 /* */
312 /* <Input> */
313 /* range :: The target range. */
314 /* */
315 /* stream :: The input stream. */
316 /* */
317 /* <Return> */
318 /* FreeType error code. 0 means success. */
319 /* */
320 static
321 FT_Error Load_SBit_Range( TT_SBit_Range* range,
322 FT_Stream stream )
323 {
324 FT_Error error;
325 FT_Memory memory = stream->memory;
326
327
328 switch( range->index_format )
329 {
330 case 1: /* variable metrics with 4-byte offsets */
331 case 3: /* variable metrics with 2-byte offsets */
332 {
333 FT_ULong num_glyphs, n;
334 FT_Int size_elem;
335 FT_Bool large = ( range->index_format == 1 );
336
337
338 num_glyphs = range->last_glyph - range->first_glyph + 1L;
339 range->num_glyphs = num_glyphs;
340 num_glyphs++; /* XXX: BEWARE - see spec */
341
342 size_elem = large ? 4 : 2;
343
344 if ( ALLOC_ARRAY( range->glyph_offsets,
345 num_glyphs, FT_ULong ) ||
346 ACCESS_Frame( num_glyphs * size_elem ) )
347 goto Exit;
348
349 for ( n = 0; n < num_glyphs; n++ )
350 range->glyph_offsets[n] = (FT_ULong)( range->image_offset +
351 ( large ? GET_ULong()
352 : GET_UShort() ) );
353 FORGET_Frame();
354 }
355 break;
356
357 case 2: /* all glyphs have identical metrics */
358 error = Load_SBit_Const_Metrics( range, stream );
359 break;
360
361 case 4:
362 error = Load_SBit_Range_Codes( range, stream, 1 );
363 break;
364
365 case 5:
366 error = Load_SBit_Const_Metrics( range, stream ) ||
367 Load_SBit_Range_Codes( range, stream, 0 );
368 break;
369
370 default:
371 error = TT_Err_Invalid_File_Format;
372 }
373
374 Exit:
375 return error;
376 }
377
378
379 /*************************************************************************/
380 /* */
381 /* <Function> */
382 /* TT_Load_SBit_Strikes */
383 /* */
384 /* <Description> */
385 /* Loads the table of embedded bitmap sizes for this face. */
386 /* */
387 /* <Input> */
388 /* face :: The target face object. */
389 /* */
390 /* stream :: The input stream. */
391 /* */
392 /* <Return> */
393 /* FreeType error code. 0 means success. */
394 /* */
395 LOCAL_FUNC
396 FT_Error TT_Load_SBit_Strikes( TT_Face face,
397 FT_Stream stream )
398 {
399 FT_Error error = 0;
400 FT_Memory memory = stream->memory;
401 FT_Fixed version;
402 FT_ULong num_strikes;
403 FT_ULong table_base;
404
405 const FT_Frame_Field sbit_line_metrics_fields[] =
406 {
407 /* no FT_FRAME_START */
408 FT_FRAME_CHAR( TT_SBit_Line_Metrics, ascender ),
409 FT_FRAME_CHAR( TT_SBit_Line_Metrics, descender ),
410 FT_FRAME_BYTE( TT_SBit_Line_Metrics, max_width ),
411
412 FT_FRAME_CHAR( TT_SBit_Line_Metrics, caret_slope_numerator ),
413 FT_FRAME_CHAR( TT_SBit_Line_Metrics, caret_slope_denominator ),
414 FT_FRAME_CHAR( TT_SBit_Line_Metrics, caret_offset ),
415
416 FT_FRAME_CHAR( TT_SBit_Line_Metrics, min_origin_SB ),
417 FT_FRAME_CHAR( TT_SBit_Line_Metrics, min_advance_SB ),
418 FT_FRAME_CHAR( TT_SBit_Line_Metrics, max_before_BL ),
419 FT_FRAME_CHAR( TT_SBit_Line_Metrics, min_after_BL ),
420 FT_FRAME_CHAR( TT_SBit_Line_Metrics, pads[0] ),
421 FT_FRAME_CHAR( TT_SBit_Line_Metrics, pads[1] ),
422 FT_FRAME_END
423 };
424
425 const FT_Frame_Field strike_start_fields[] =
426 {
427 /* no FT_FRAME_START */
428 FT_FRAME_ULONG( TT_SBit_Strike, ranges_offset ),
429 FT_FRAME_SKIP_LONG,
430 FT_FRAME_ULONG( TT_SBit_Strike, num_ranges ),
431 FT_FRAME_ULONG( TT_SBit_Strike, color_ref ),
432 FT_FRAME_END
433 };
434
435 const FT_Frame_Field strike_end_fields[] =
436 {
437 /* no FT_FRAME_START */
438 FT_FRAME_USHORT( TT_SBit_Strike, start_glyph ),
439 FT_FRAME_USHORT( TT_SBit_Strike, end_glyph ),
440 FT_FRAME_BYTE ( TT_SBit_Strike, x_ppem ),
441 FT_FRAME_BYTE ( TT_SBit_Strike, y_ppem ),
442 FT_FRAME_BYTE ( TT_SBit_Strike, bit_depth ),
443 FT_FRAME_CHAR ( TT_SBit_Strike, flags ),
444 FT_FRAME_END
445 };
446
447
448 face->num_sbit_strikes = 0;
449
450 /* this table is optional */
451 error = face->goto_table( face, TTAG_EBLC, stream, 0 );
452 if (error)
453 error = face->goto_table( face, TTAG_bloc, stream, 0 );
454 if ( error )
455 {
456 error = 0;
457 goto Exit;
458 }
459
460 table_base = FILE_Pos();
461 if ( ACCESS_Frame( 8L ) )
462 goto Exit;
463
464 version = GET_Long();
465 num_strikes = GET_ULong();
466
467 FORGET_Frame();
468
469 /* check version number and strike count */
470 if ( version != 0x00020000L ||
471 num_strikes >= 0x10000L )
472 {
473 FT_ERROR(( "TT_Load_SBit_Strikes: invalid table version!\n" ));
474 error = TT_Err_Invalid_File_Format;
475
476 goto Exit;
477 }
478
479 /* allocate the strikes table */
480 if ( ALLOC_ARRAY( face->sbit_strikes, num_strikes, TT_SBit_Strike ) )
481 goto Exit;
482
483 face->num_sbit_strikes = num_strikes;
484
485 /* now read each strike table separately */
486 {
487 TT_SBit_Strike* strike = face->sbit_strikes;
488 FT_ULong count = num_strikes;
489
490
491 if ( ACCESS_Frame( 48L * num_strikes ) )
492 goto Exit;
493
494 while ( count > 0 )
495 {
496 (void)READ_Fields( strike_start_fields, strike );
497
498 (void)READ_Fields( sbit_line_metrics_fields, &strike->hori );
499 (void)READ_Fields( sbit_line_metrics_fields, &strike->vert );
500
501 (void)READ_Fields( strike_end_fields, strike );
502
503 count--;
504 strike++;
505 }
506
507 FORGET_Frame();
508 }
509
510 /* allocate the index ranges for each strike table */
511 {
512 TT_SBit_Strike* strike = face->sbit_strikes;
513 FT_ULong count = num_strikes;
514
515
516 while ( count > 0 )
517 {
518 TT_SBit_Range* range;
519 FT_ULong count2 = strike->num_ranges;
520
521
522 if ( ALLOC_ARRAY( strike->sbit_ranges,
523 strike->num_ranges,
524 TT_SBit_Range ) )
525 goto Exit;
526
527 /* read each range */
528 if ( FILE_Seek( table_base + strike->ranges_offset ) ||
529 ACCESS_Frame( strike->num_ranges * 8L ) )
530 goto Exit;
531
532 range = strike->sbit_ranges;
533 while ( count2 > 0 )
534 {
535 range->first_glyph = GET_UShort();
536 range->last_glyph = GET_UShort();
537 range->table_offset = table_base + strike->ranges_offset
538 + GET_ULong();
539 count2--;
540 range++;
541 }
542
543 FORGET_Frame();
544
545 /* Now, read each index table */
546 count2 = strike->num_ranges;
547 range = strike->sbit_ranges;
548 while ( count2 > 0 )
549 {
550 /* Read the header */
551 if ( FILE_Seek( range->table_offset ) ||
552 ACCESS_Frame( 8L ) )
553 goto Exit;
554
555 range->index_format = GET_UShort();
556 range->image_format = GET_UShort();
557 range->image_offset = GET_ULong();
558
559 FORGET_Frame();
560
561 error = Load_SBit_Range( range, stream );
562 if ( error )
563 goto Exit;
564
565 count2--;
566 range++;
567 }
568
569 count--;
570 strike++;
571 }
572 }
573
574 Exit:
575 return error;
576 }
577
578
579 /*************************************************************************/
580 /* */
581 /* <Function> */
582 /* TT_Free_SBit_Strikes */
583 /* */
584 /* <Description> */
585 /* Releases the embedded bitmap tables. */
586 /* */
587 /* <Input> */
588 /* face :: The target face object. */
589 /* */
590 LOCAL_FUNC
591 void TT_Free_SBit_Strikes( TT_Face face )
592 {
593 FT_Memory memory = face->root.memory;
594 TT_SBit_Strike* strike = face->sbit_strikes;
595 TT_SBit_Strike* strike_limit = strike + face->num_sbit_strikes;
596
597
598 if ( strike )
599 {
600 for ( ; strike < strike_limit; strike++ )
601 {
602 TT_SBit_Range* range = strike->sbit_ranges;
603 TT_SBit_Range* range_limit = range + strike->num_ranges;
604
605
606 if ( range )
607 {
608 for ( ; range < range_limit; range++ )
609 {
610 /* release the glyph offsets and codes tables */
611 /* where appropriate */
612 FREE( range->glyph_offsets );
613 FREE( range->glyph_codes );
614 }
615 }
616 FREE( strike->sbit_ranges );
617 strike->num_ranges = 0;
618 }
619 FREE( face->sbit_strikes );
620 }
621 face->num_sbit_strikes = 0;
622 }
623
624
625 /*************************************************************************/
626 /* */
627 /* <Function> */
628 /* Find_SBit_Range */
629 /* */
630 /* <Description> */
631 /* Scans a given strike's ranges and return, for a given glyph */
632 /* index, the corresponding sbit range, and `EBDT' offset. */
633 /* */
634 /* <Input> */
635 /* glyph_index :: The glyph index. */
636 /* strike :: The source/current sbit strike. */
637 /* */
638 /* <Output> */
639 /* arange :: The sbit range containing the glyph index. */
640 /* aglyph_offset :: The offset of the glyph data in `EBDT' table. */
641 /* */
642 /* <Return> */
643 /* FreeType error code. 0 means the glyph index was found. */
644 /* */
645 static
646 FT_Error Find_SBit_Range( FT_UInt glyph_index,
647 TT_SBit_Strike* strike,
648 TT_SBit_Range** arange,
649 FT_ULong* aglyph_offset )
650 {
651 TT_SBit_Range *range, *range_limit;
652
653
654 /* check whether the glyph index is within this strike's */
655 /* glyph range */
656 if ( glyph_index < strike->start_glyph ||
657 glyph_index > strike->end_glyph )
658 goto Fail;
659
660 /* scan all ranges in strike */
661 range = strike->sbit_ranges;
662 range_limit = range + strike->num_ranges;
663 if ( !range )
664 goto Fail;
665
666 for ( ; range < range_limit; range++ )
667 {
668 if ( glyph_index >= range->first_glyph &&
669 glyph_index <= range->last_glyph )
670 {
671 FT_UShort delta = glyph_index - range->first_glyph;
672
673
674 switch ( range->index_format )
675 {
676 case 1:
677 case 3:
678 *aglyph_offset = range->glyph_offsets[delta];
679 break;
680
681 case 2:
682 *aglyph_offset = range->image_offset +
683 range->image_size * delta;
684 break;
685
686 case 4:
687 case 5:
688 {
689 FT_ULong n;
690
691
692 for ( n = 0; n < range->num_glyphs; n++ )
693 {
694 if ( range->glyph_codes[n] == glyph_index )
695 {
696 if ( range->index_format == 4 )
697 *aglyph_offset = range->glyph_offsets[n];
698 else
699 *aglyph_offset = range->image_offset +
700 n * range->image_size;
701 goto Found;
702 }
703 }
704 }
705
706 /* fall-through */
707 default:
708 goto Fail;
709 }
710
711 Found:
712 /* return successfully! */
713 *arange = range;
714 return 0;
715 }
716 }
717
718 Fail:
719 *arange = 0;
720 *aglyph_offset = 0;
721
722 return TT_Err_Invalid_Argument;
723 }
724
725
726 /*************************************************************************/
727 /* */
728 /* <Function> */
729 /* Find_SBit_Image */
730 /* */
731 /* <Description> */
732 /* Checks whether an embedded bitmap (an `sbit') exists for a given */
733 /* glyph, at given x and y ppems. */
734 /* */
735 /* <Input> */
736 /* face :: The target face object. */
737 /* glyph_index :: The glyph index. */
738 /* x_ppem :: The horizontal resolution in points per EM. */
739 /* y_ppem :: The vertical resolution in points per EM. */
740 /* */
741 /* <Output> */
742 /* arange :: The SBit range containing the glyph index. */
743 /* astrike :: The SBit strike containing the glyph index. */
744 /* aglyph_offset :: The offset of the glyph data in `EBDT' table. */
745 /* */
746 /* <Return> */
747 /* FreeType error code. 0 means success. Returns */
748 /* TT_Err_Invalid_Argument if no sbit exists for the requested glyph. */
749 /* */
750 static
751 FT_Error Find_SBit_Image( TT_Face face,
752 FT_UInt glyph_index,
753 FT_Int x_ppem,
754 FT_Int y_ppem,
755
756 TT_SBit_Range** arange,
757 TT_SBit_Strike** astrike,
758 FT_ULong* aglyph_offset )
759 {
760 TT_SBit_Strike* strike = face->sbit_strikes;
761 TT_SBit_Strike* strike_limit = strike + face->num_sbit_strikes;
762
763
764 if ( !strike )
765 goto Fail;
766
767 for ( ; strike < strike_limit; strike++ )
768 {
769 if ( strike->x_ppem == x_ppem && strike->y_ppem == y_ppem )
770 {
771 FT_Error error;
772
773
774 error = Find_SBit_Range( glyph_index, strike,
775 arange, aglyph_offset );
776 if ( error )
777 goto Fail;
778
779 *astrike = strike;
780
781 return TT_Err_Ok;
782 }
783 }
784
785 Fail:
786 /* no embedded bitmap for this glyph in face */
787 *arange = 0;
788 *astrike = 0;
789 *aglyph_offset = 0;
790
791 return TT_Err_Invalid_Argument;
792 }
793
794
795 /*************************************************************************/
796 /* */
797 /* <Function> */
798 /* Load_SBit_Metrics */
799 /* */
800 /* <Description> */
801 /* Gets the big metrics for a given SBit. */
802 /* */
803 /* <Input> */
804 /* stream :: The input stream. */
805 /* */
806 /* range :: The SBit range containing the glyph. */
807 /* */
808 /* <Output> */
809 /* big_metrics :: A big SBit metrics structure for the glyph. */
810 /* */
811 /* <Return> */
812 /* FreeType error code. 0 means success. */
813 /* */
814 /* <Note> */
815 /* The stream cursor must be positioned at the glyph's offset within */
816 /* the `EBDT' table before the call. */
817 /* */
818 /* If the image format uses variable metrics, the stream cursor is */
819 /* positioned just after the metrics header in the `EBDT' table on */
820 /* function exit. */
821 /* */
822 static
823 FT_Error Load_SBit_Metrics( FT_Stream stream,
824 TT_SBit_Range* range,
825 TT_SBit_Metrics* metrics )
826 {
827 FT_Error error = TT_Err_Ok;
828
829
830 switch ( range->image_format )
831 {
832 case 1:
833 case 2:
834 case 8:
835 /* variable small metrics */
836 {
837 TT_SBit_Small_Metrics smetrics;
838
839 const FT_Frame_Field sbit_small_metrics_fields[] =
840 {
841 FT_FRAME_START( 5 ),
842 FT_FRAME_BYTE( TT_SBit_Small_Metrics, height ),
843 FT_FRAME_BYTE( TT_SBit_Small_Metrics, width ),
844 FT_FRAME_CHAR( TT_SBit_Small_Metrics, bearingX ),
845 FT_FRAME_CHAR( TT_SBit_Small_Metrics, bearingY ),
846 FT_FRAME_BYTE( TT_SBit_Small_Metrics, advance ),
847 FT_FRAME_END
848 };
849
850
851 /* read small metrics */
852 if ( READ_Fields( sbit_small_metrics_fields, &smetrics ) )
853 goto Exit;
854
855 /* convert it to a big metrics */
856 metrics->height = smetrics.height;
857 metrics->width = smetrics.width;
858 metrics->horiBearingX = smetrics.bearingX;
859 metrics->horiBearingY = smetrics.bearingY;
860 metrics->horiAdvance = smetrics.advance;
861
862 /* these metrics are made up at a higher level when */
863 /* needed. */
864 metrics->vertBearingX = 0;
865 metrics->vertBearingY = 0;
866 metrics->vertAdvance = 0;
867 }
868 break;
869
870 case 6:
871 case 7:
872 case 9:
873 /* variable big metrics */
874 (void)READ_Fields( sbit_metrics_fields, metrics );
875 break;
876
877 case 5:
878 default: /* constant metrics */
879 if ( range->index_format == 2 || range->index_format == 5 )
880 *metrics = range->metrics;
881 else
882 return TT_Err_Invalid_File_Format;
883 }
884
885 Exit:
886 return error;
887 }
888
889
890 /*************************************************************************/
891 /* */
892 /* <Function> */
893 /* Crop_Bitmap */
894 /* */
895 /* <Description> */
896 /* Crops a bitmap to its tightest bounding box, and adjusts its */
897 /* metrics. */
898 /* */
899 /* <Input> */
900 /* image :: The input glyph slot. */
901 /* */
902 /* metrics :: The corresponding metrics structure. */
903 /* */
904 static
905 void Crop_Bitmap( FT_Bitmap* map,
906 TT_SBit_Metrics* metrics )
907 {
908 /***********************************************************************/
909 /* */
910 /* In this situation, some bounding boxes of embedded bitmaps are too */
911 /* large. We need to crop it to a reasonable size. */
912 /* */
913 /* --------- */
914 /* | | ----- */
915 /* | *** | |***| */
916 /* | * | | * | */
917 /* | * | ------> | * | */
918 /* | * | | * | */
919 /* | * | | * | */
920 /* | *** | |***| */
921 /* --------- ----- */
922 /* */
923 /***********************************************************************/
924
925 FT_Int rows, count;
926 FT_Long line_len;
927 FT_Byte* line;
928
929
930 /***********************************************************************/
931 /* */
932 /* first of all, check the top-most lines of the bitmap, and remove */
933 /* them if they're empty. */
934 /* */
935 {
936 line = (FT_Byte*)map->buffer;
937 rows = map->rows;
938 line_len = map->pitch;
939
940
941 for ( count = 0; count < rows; count++ )
942 {
943 FT_Byte* cur = line;
944 FT_Byte* limit = line + line_len;
945
946
947 for ( ; cur < limit; cur++ )
948 if ( cur[0] )
949 goto Found_Top;
950
951 /* the current line was empty - skip to next one */
952 line = limit;
953 }
954
955 Found_Top:
956 /* check that we have at least one filled line */
957 if ( count >= rows )
958 goto Empty_Bitmap;
959
960 /* now, crop the empty upper lines */
961 if ( count > 0 )
962 {
963 line = (FT_Byte*)map->buffer;
964
965 MEM_Move( line, line + count * line_len,
966 ( rows - count ) * line_len );
967
968 metrics->height -= count;
969 metrics->horiBearingY -= count;
970 metrics->vertBearingY -= count;
971
972 map->rows -= count;
973 rows -= count;
974 }
975 }
976
977 /***********************************************************************/
978 /* */
979 /* second, crop the lower lines */
980 /* */
981 {
982 line = (FT_Byte*)map->buffer + ( rows - 1 ) * line_len;
983
984 for ( count = 0; count < rows; count++ )
985 {
986 FT_Byte* cur = line;
987 FT_Byte* limit = line + line_len;
988
989
990 for ( ; cur < limit; cur++ )
991 if ( cur[0] )
992 goto Found_Bottom;
993
994 /* the current line was empty - skip to previous one */
995 line -= line_len;
996 }
997
998 Found_Bottom:
999 if ( count > 0 )
1000 {
1001 metrics->height -= count;
1002 rows -= count;
1003 map->rows -= count;
1004 }
1005 }
1006
1007 /***********************************************************************/
1008 /* */
1009 /* third, get rid of the space on the left side of the glyph */
1010 /* */
1011 do
1012 {
1013 FT_Byte* limit;
1014
1015
1016 line = (FT_Byte*)map->buffer;
1017 limit = line + rows * line_len;
1018
1019 for ( ; line < limit; line += line_len )
1020 if ( line[0] & 0x80 )
1021 goto Found_Left;
1022
1023 /* shift the whole glyph one pixel to the left */
1024 line = (FT_Byte*)map->buffer;
1025 limit = line + rows * line_len;
1026
1027 for ( ; line < limit; line += line_len )
1028 {
1029 FT_Int n, width = map->width;
1030 FT_Byte old;
1031 FT_Byte* cur = line;
1032
1033
1034 old = cur[0] << 1;
1035 for ( n = 8; n < width; n += 8 )
1036 {
1037 FT_Byte val;
1038
1039
1040 val = cur[1];
1041 cur[0] = old | ( val >> 7 );
1042 old = val << 1;
1043 cur++;
1044 }
1045 cur[0] = old;
1046 }
1047
1048 map->width--;
1049 metrics->horiBearingX++;
1050 metrics->vertBearingX++;
1051 metrics->width--;
1052
1053 } while ( map->width > 0 );
1054
1055 Found_Left:
1056
1057 /***********************************************************************/
1058 /* */
1059 /* finally, crop the bitmap width to get rid of the space on the right */
1060 /* side of the glyph. */
1061 /* */
1062 do
1063 {
1064 FT_Int right = map->width - 1;
1065 FT_Byte* limit;
1066 FT_Byte mask;
1067
1068
1069 line = (FT_Byte*)map->buffer + ( right >> 3 );
1070 limit = line + rows * line_len;
1071 mask = 0x80 >> ( right & 7 );
1072
1073 for ( ; line < limit; line += line_len )
1074 if ( line[0] & mask )
1075 goto Found_Right;
1076
1077 /* crop the whole glyph to the right */
1078 map->width--;
1079 metrics->width--;
1080
1081 } while ( map->width > 0 );
1082
1083 Found_Right:
1084 /* all right, the bitmap was cropped */
1085 return;
1086
1087 Empty_Bitmap:
1088 map->width = 0;
1089 map->rows = 0;
1090 map->pitch = 0;
1091 map->pixel_mode = ft_pixel_mode_mono;
1092 }
1093
1094
1095 static
1096 FT_Error Load_SBit_Single( FT_Bitmap* map,
1097 FT_Int x_offset,
1098 FT_Int y_offset,
1099 FT_Int pix_bits,
1100 FT_UShort image_format,
1101 TT_SBit_Metrics* metrics,
1102 FT_Stream stream )
1103 {
1104 FT_Error error;
1105
1106
1107 /* check that the source bitmap fits into the target pixmap */
1108 if ( x_offset < 0 || x_offset + metrics->width > map->width ||
1109 y_offset < 0 || y_offset + metrics->height > map->rows )
1110 {
1111 error = TT_Err_Invalid_Argument;
1112
1113 goto Exit;
1114 }
1115
1116 {
1117 FT_Int glyph_width = metrics->width;
1118 FT_Int glyph_height = metrics->height;
1119 FT_Int glyph_size;
1120 FT_Int line_bits = pix_bits * glyph_width;
1121 FT_Bool pad_bytes = 0;
1122
1123
1124 /* compute size of glyph image */
1125 switch ( image_format )
1126 {
1127 case 1: /* byte-padded formats */
1128 case 6:
1129 {
1130 FT_Int line_length;
1131
1132
1133 switch ( pix_bits )
1134 {
1135 case 1: line_length = ( glyph_width + 7 ) >> 3; break;
1136 case 2: line_length = ( glyph_width + 3 ) >> 2; break;
1137 case 4: line_length = ( glyph_width + 1 ) >> 1; break;
1138 default: line_length = glyph_width;
1139 }
1140
1141 glyph_size = glyph_height * line_length;
1142 pad_bytes = 1;
1143 }
1144 break;
1145
1146 case 2:
1147 case 5:
1148 case 7:
1149 line_bits = glyph_width * pix_bits;
1150 glyph_size = ( glyph_height * line_bits + 7 ) >> 3;
1151 break;
1152
1153 default: /* invalid format */
1154 return TT_Err_Invalid_File_Format;
1155 }
1156
1157 /* Now read data and draw glyph into target pixmap */
1158 if ( ACCESS_Frame( glyph_size ) )
1159 goto Exit;
1160
1161 /* don't forget to multiply `x_offset' by `map->pix_bits' as */
1162 /* the sbit blitter doesn't make a difference between pixmap */
1163 /* depths. */
1164 blit_sbit( map, (FT_Byte*)stream->cursor, line_bits, pad_bytes,
1165 x_offset * pix_bits, y_offset );
1166
1167 FORGET_Frame();
1168 }
1169
1170 Exit:
1171 return error;
1172 }
1173
1174
1175 static
1176 FT_Error Load_SBit_Image( TT_SBit_Strike* strike,
1177 TT_SBit_Range* range,
1178 FT_ULong ebdt_pos,
1179 FT_ULong glyph_offset,
1180 FT_Bitmap* map,
1181 FT_Int x_offset,
1182 FT_Int y_offset,
1183 FT_Stream stream,
1184 TT_SBit_Metrics* metrics )
1185 {
1186 FT_Memory memory = stream->memory;
1187 FT_Error error;
1188
1189
1190 /* place stream at beginning of glyph data and read metrics */
1191 if ( FILE_Seek( ebdt_pos + glyph_offset ) )
1192 goto Exit;
1193
1194 error = Load_SBit_Metrics( stream, range, metrics );
1195 if ( error )
1196 goto Exit;
1197
1198 /* this function is recursive. At the top-level call, the */
1199 /* field map.buffer is NULL. We thus begin by finding the */
1200 /* dimensions of the higher-level glyph to allocate the */
1201 /* final pixmap buffer */
1202 if ( map->buffer == 0 )
1203 {
1204 FT_Long size;
1205
1206
1207 map->width = metrics->width;
1208 map->rows = metrics->height;
1209
1210 switch ( strike->bit_depth )
1211 {
1212 case 1:
1213 map->pixel_mode = ft_pixel_mode_mono;
1214 map->pitch = ( map->width + 7 ) >> 3;
1215 break;
1216
1217 case 2:
1218 map->pixel_mode = ft_pixel_mode_pal2;
1219 map->pitch = ( map->width + 3 ) >> 2;
1220 break;
1221
1222 case 4:
1223 map->pixel_mode = ft_pixel_mode_pal4;
1224 map->pitch = ( map->width + 1 ) >> 1;
1225 break;
1226
1227 case 8:
1228 map->pixel_mode = ft_pixel_mode_grays;
1229 map->pitch = map->width;
1230 break;
1231
1232 default:
1233 return TT_Err_Invalid_File_Format;
1234 }
1235
1236 size = map->rows * map->pitch;
1237
1238 /* check that there is no empty image */
1239 if ( size == 0 )
1240 goto Exit; /* exit successfully! */
1241
1242 if ( ALLOC( map->buffer, size ) )
1243 goto Exit;
1244 }
1245
1246 switch ( range->image_format )
1247 {
1248 case 1: /* single sbit image - load it */
1249 case 2:
1250 case 5:
1251 case 6:
1252 case 7:
1253 return Load_SBit_Single( map, x_offset, y_offset, strike->bit_depth,
1254 range->image_format, metrics, stream );
1255
1256 case 8: /* compound format */
1257 FT_Skip_Stream( stream, 1L );
1258 /* fallthrough */
1259
1260 case 9:
1261 break;
1262
1263 default: /* invalid image format */
1264 return TT_Err_Invalid_File_Format;
1265 }
1266
1267 /* All right, we have a compound format. First of all, read */
1268 /* the array of elements. */
1269 {
1270 TT_SBit_Component* components;
1271 TT_SBit_Component* comp;
1272 FT_UShort num_components, count;
1273
1274
1275 if ( READ_UShort( num_components ) ||
1276 ALLOC_ARRAY( components, num_components, TT_SBit_Component ) )
1277 goto Exit;
1278
1279 count = num_components;
1280
1281 if ( ACCESS_Frame( 4L * num_components ) )
1282 goto Fail_Memory;
1283
1284 for ( comp = components; count > 0; count--, comp++ )
1285 {
1286 comp->glyph_code = GET_UShort();
1287 comp->x_offset = GET_Char();
1288 comp->y_offset = GET_Char();
1289 }
1290
1291 FORGET_Frame();
1292
1293 /* Now recursively load each element glyph */
1294 count = num_components;
1295 comp = components;
1296 for ( ; count > 0; count--, comp++ )
1297 {
1298 TT_SBit_Range* elem_range;
1299 TT_SBit_Metrics elem_metrics;
1300 FT_ULong elem_offset;
1301
1302
1303 /* find the range for this element */
1304 error = Find_SBit_Range( comp->glyph_code,
1305 strike,
1306 &elem_range,
1307 &elem_offset );
1308 if ( error )
1309 goto Fail_Memory;
1310
1311 /* now load the element, recursively */
1312 error = Load_SBit_Image( strike,
1313 elem_range,
1314 ebdt_pos,
1315 elem_offset,
1316 map,
1317 x_offset + comp->x_offset,
1318 y_offset + comp->y_offset,
1319 stream,
1320 &elem_metrics );
1321 if ( error )
1322 goto Fail_Memory;
1323 }
1324
1325 Fail_Memory:
1326 FREE( components );
1327 }
1328
1329 Exit:
1330 return error;
1331 }
1332
1333
1334 /*************************************************************************/
1335 /* */
1336 /* <Function> */
1337 /* TT_Load_SBit_Image */
1338 /* */
1339 /* <Description> */
1340 /* Loads a given glyph sbit image from the font resource. This also */
1341 /* returns its metrics. */
1342 /* */
1343 /* <Input> */
1344 /* face :: The target face object. */
1345 /* */
1346 /* x_ppem :: The horizontal resolution in points per EM. */
1347 /* */
1348 /* y_ppem :: The vertical resolution in points per EM. */
1349 /* */
1350 /* glyph_index :: The current glyph index. */
1351 /* */
1352 /* load_flags :: The glyph load flags (the code checks for the flag */
1353 /* FT_LOAD_CROP_BITMAP */
1354 /* */
1355 /* stream :: The input stream. */
1356 /* */
1357 /* <Output> */
1358 /* map :: The target pixmap. */
1359 /* */
1360 /* metrics :: A big sbit metrics structure for the glyph image. */
1361 /* */
1362 /* <Return> */
1363 /* FreeType error code. 0 means success. Returns an error if no */
1364 /* glyph sbit exists for the index. */
1365 /* */
1366 /* <Note> */
1367 /* The `map.buffer' field is always freed before the glyph is loaded. */
1368 /* */
1369 LOCAL_FUNC
1370 FT_Error TT_Load_SBit_Image( TT_Face face,
1371 FT_Int x_ppem,
1372 FT_Int y_ppem,
1373 FT_UInt glyph_index,
1374 FT_UInt load_flags,
1375 FT_Stream stream,
1376 FT_Bitmap* map,
1377 TT_SBit_Metrics* metrics )
1378 {
1379 FT_Error error;
1380 FT_Memory memory = stream->memory;
1381 FT_ULong ebdt_pos, glyph_offset;
1382
1383 TT_SBit_Strike* strike;
1384 TT_SBit_Range* range;
1385
1386
1387 /* Check whether there is a glyph sbit for the current index */
1388 error = Find_SBit_Image( face, glyph_index, x_ppem, y_ppem,
1389 &range, &strike, &glyph_offset );
1390 if ( error )
1391 goto Exit;
1392
1393 /* now, find the location of the `EBDT' table in */
1394 /* the font file */
1395 error = face->goto_table( face, TTAG_EBDT, stream, 0 );
1396 if ( error )
1397 error = face->goto_table( face, TTAG_bdat, stream, 0 );
1398 if (error)
1399 goto Exit;
1400
1401 ebdt_pos = FILE_Pos();
1402
1403 /* clear the bitmap & load the bitmap */
1404 if ( face->root.glyph->flags & ft_glyph_own_bitmap )
1405 FREE( map->buffer );
1406
1407 map->rows = map->pitch = map->width = 0;
1408
1409 error = Load_SBit_Image( strike, range, ebdt_pos, glyph_offset,
1410 map, 0, 0, stream, metrics );
1411 if ( error )
1412 goto Exit;
1413
1414 /* the glyph slot owns this bitmap buffer */
1415 face->root.glyph->flags |= ft_glyph_own_bitmap;
1416
1417 /* setup vertical metrics if needed */
1418 if ( strike->flags & 1 )
1419 {
1420 /* in case of a horizontal strike only */
1421 FT_Int advance;
1422 FT_Int top;
1423
1424
1425 advance = strike->hori.ascender - strike->hori.descender;
1426 top = advance / 10;
1427
1428 /* some heuristic values */
1429
1430 metrics->vertBearingX = -metrics->width / 2;
1431 metrics->vertBearingY = advance / 10;
1432 metrics->vertAdvance = advance * 12 / 10;
1433 }
1434
1435 /* Crop the bitmap now, unless specified otherwise */
1436 if ( load_flags & FT_LOAD_CROP_BITMAP )
1437 Crop_Bitmap( map, metrics );
1438
1439 Exit:
1440 return error;
1441 }
1442
1443
1444 /* END */