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