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