]>
Commit | Line | Data |
---|---|---|
1 | /***************************************************************************/ | |
2 | /* */ | |
3 | /* t1gload.c */ | |
4 | /* */ | |
5 | /* Type 1 Glyph Loader (body). */ | |
6 | /* */ | |
7 | /* Copyright 1996-2000 by */ | |
8 | /* David Turner, Robert Wilhelm, and Werner Lemberg. */ | |
9 | /* */ | |
10 | /* This file is part of the FreeType project, and may only be used, */ | |
11 | /* modified, and distributed under the terms of the FreeType project */ | |
12 | /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ | |
13 | /* this file you indicate that you have read the license and */ | |
14 | /* understand and accept it fully. */ | |
15 | /* */ | |
16 | /***************************************************************************/ | |
17 | ||
18 | ||
19 | #ifdef FT_FLAT_COMPILE | |
20 | ||
21 | #include "t1gload.h" | |
22 | ||
23 | #ifndef T1_CONFIG_OPTION_DISABLE_HINTER | |
24 | #include "t1hinter.h" | |
25 | #endif | |
26 | ||
27 | #else /* FT_FLAT_COMPILE */ | |
28 | ||
29 | #include <type1/t1gload.h> | |
30 | ||
31 | #ifndef T1_CONFIG_OPTION_DISABLE_HINTER | |
32 | #include <type1/t1hinter.h> | |
33 | #endif | |
34 | ||
35 | #endif /* FT_FLAT_COMPILE */ | |
36 | ||
37 | ||
38 | #include <freetype/internal/ftdebug.h> | |
39 | #include <freetype/internal/ftstream.h> | |
40 | #include <freetype/ftoutln.h> | |
41 | ||
42 | #include <string.h> /* for strcmp() */ | |
43 | ||
44 | ||
45 | /*************************************************************************/ | |
46 | /* */ | |
47 | /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ | |
48 | /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ | |
49 | /* messages during execution. */ | |
50 | /* */ | |
51 | #undef FT_COMPONENT | |
52 | #define FT_COMPONENT trace_t1gload | |
53 | ||
54 | ||
55 | /*************************************************************************/ | |
56 | /*************************************************************************/ | |
57 | /*************************************************************************/ | |
58 | /********** *********/ | |
59 | /********** *********/ | |
60 | /********** GENERIC CHARSTRING PARSING *********/ | |
61 | /********** *********/ | |
62 | /********** *********/ | |
63 | /*************************************************************************/ | |
64 | /*************************************************************************/ | |
65 | /*************************************************************************/ | |
66 | ||
67 | ||
68 | static | |
69 | void T1_Reset_Builder( T1_Builder* builder, | |
70 | FT_Bool reset_base ) | |
71 | { | |
72 | builder->pos_x = 0; | |
73 | builder->pos_y = 0; | |
74 | ||
75 | builder->left_bearing.x = 0; | |
76 | builder->left_bearing.y = 0; | |
77 | builder->advance.x = 0; | |
78 | builder->advance.y = 0; | |
79 | ||
80 | builder->pass = 0; | |
81 | builder->hint_point = 0; | |
82 | ||
83 | if ( builder->loader ) | |
84 | { | |
85 | if ( reset_base ) | |
86 | FT_GlyphLoader_Rewind( builder->loader ); | |
87 | ||
88 | FT_GlyphLoader_Prepare( builder->loader ); | |
89 | } | |
90 | } | |
91 | ||
92 | ||
93 | /*************************************************************************/ | |
94 | /* */ | |
95 | /* <Function> */ | |
96 | /* T1_Init_Builder */ | |
97 | /* */ | |
98 | /* <Description> */ | |
99 | /* Initializes a given glyph builder. */ | |
100 | /* */ | |
101 | /* <InOut> */ | |
102 | /* builder :: A pointer to the glyph builder to initialize. */ | |
103 | /* */ | |
104 | /* <Input> */ | |
105 | /* face :: The current face object. */ | |
106 | /* */ | |
107 | /* size :: The current size object. */ | |
108 | /* */ | |
109 | /* glyph :: The current glyph object. */ | |
110 | /* */ | |
111 | /* funcs :: Glyph builder functions (or `methods'). */ | |
112 | /* */ | |
113 | LOCAL_FUNC | |
114 | void T1_Init_Builder( T1_Builder* builder, | |
115 | T1_Face face, | |
116 | T1_Size size, | |
117 | T1_GlyphSlot glyph, | |
118 | const T1_Builder_Funcs* funcs ) | |
119 | { | |
120 | builder->funcs = *funcs; | |
121 | builder->path_begun = 0; | |
122 | builder->load_points = 1; | |
123 | ||
124 | builder->face = face; | |
125 | builder->size = size; | |
126 | builder->glyph = glyph; | |
127 | builder->memory = face->root.memory; | |
128 | ||
129 | if ( glyph ) | |
130 | { | |
131 | FT_GlyphLoader* loader = FT_SLOT( glyph )->loader; | |
132 | ||
133 | ||
134 | builder->loader = loader; | |
135 | builder->base = &loader->base.outline; | |
136 | builder->current = &loader->current.outline; | |
137 | } | |
138 | ||
139 | if ( size ) | |
140 | { | |
141 | builder->scale_x = size->root.metrics.x_scale; | |
142 | builder->scale_y = size->root.metrics.y_scale; | |
143 | } | |
144 | ||
145 | T1_Reset_Builder( builder, 1 ); | |
146 | } | |
147 | ||
148 | ||
149 | /*************************************************************************/ | |
150 | /* */ | |
151 | /* <Function> */ | |
152 | /* T1_Done_Builder */ | |
153 | /* */ | |
154 | /* <Description> */ | |
155 | /* Finalizes a given glyph builder. Its contents can still be used */ | |
156 | /* after the call, but the function saves important information */ | |
157 | /* within the corresponding glyph slot. */ | |
158 | /* */ | |
159 | /* <Input> */ | |
160 | /* builder :: A pointer to the glyph builder to finalize. */ | |
161 | /* */ | |
162 | LOCAL_FUNC | |
163 | void T1_Done_Builder( T1_Builder* builder ) | |
164 | { | |
165 | T1_GlyphSlot glyph = builder->glyph; | |
166 | ||
167 | ||
168 | if ( glyph ) | |
169 | glyph->root.outline = *builder->base; | |
170 | } | |
171 | ||
172 | ||
173 | /*************************************************************************/ | |
174 | /* */ | |
175 | /* <Function> */ | |
176 | /* T1_Init_Decoder */ | |
177 | /* */ | |
178 | /* <Description> */ | |
179 | /* Initializes a given glyph decoder. */ | |
180 | /* */ | |
181 | /* <InOut> */ | |
182 | /* decoder :: A pointer to the glyph builder to initialize. */ | |
183 | /* */ | |
184 | /* <Input> */ | |
185 | /* funcs :: The hinting functions interface. */ | |
186 | /* */ | |
187 | LOCAL_FUNC | |
188 | void T1_Init_Decoder( T1_Decoder* decoder, | |
189 | const T1_Hinter_Funcs* funcs ) | |
190 | { | |
191 | decoder->hinter = *funcs; /* copy hinter interface */ | |
192 | decoder->top = 0; | |
193 | decoder->zone = 0; | |
194 | ||
195 | decoder->flex_state = 0; | |
196 | decoder->num_flex_vectors = 0; | |
197 | ||
198 | /* Clear loader */ | |
199 | MEM_Set( &decoder->builder, 0, sizeof ( decoder->builder ) ); | |
200 | } | |
201 | ||
202 | ||
203 | /*************************************************************************/ | |
204 | /* */ | |
205 | /* <Function> */ | |
206 | /* lookup_glyph_by_stdcharcode */ | |
207 | /* */ | |
208 | /* <Description> */ | |
209 | /* Looks up a given glyph by its StandardEncoding charcode. Used */ | |
210 | /* to implement the SEAC Type 1 operator. */ | |
211 | /* */ | |
212 | /* <Input> */ | |
213 | /* face :: The current face object. */ | |
214 | /* */ | |
215 | /* charcode :: The character code to look for. */ | |
216 | /* */ | |
217 | /* <Return> */ | |
218 | /* A glyph index in the font face. Returns -1 if the corresponding */ | |
219 | /* glyph wasn't found. */ | |
220 | /* */ | |
221 | static | |
222 | FT_Int lookup_glyph_by_stdcharcode( T1_Face face, | |
223 | FT_Int charcode ) | |
224 | { | |
225 | FT_Int n; | |
226 | const FT_String* glyph_name; | |
227 | PSNames_Interface* psnames = (PSNames_Interface*)face->psnames; | |
228 | ||
229 | ||
230 | /* check range of standard char code */ | |
231 | if ( charcode < 0 || charcode > 255 ) | |
232 | return -1; | |
233 | ||
234 | glyph_name = psnames->adobe_std_strings( | |
235 | psnames->adobe_std_encoding[charcode] ); | |
236 | ||
237 | for ( n = 0; n < face->type1.num_glyphs; n++ ) | |
238 | { | |
239 | FT_String* name = (FT_String*)face->type1.glyph_names[n]; | |
240 | ||
241 | ||
242 | if ( name && strcmp( name, glyph_name ) == 0 ) | |
243 | return n; | |
244 | } | |
245 | ||
246 | return -1; | |
247 | } | |
248 | ||
249 | ||
250 | /*************************************************************************/ | |
251 | /* */ | |
252 | /* <Function> */ | |
253 | /* t1operator_seac */ | |
254 | /* */ | |
255 | /* <Description> */ | |
256 | /* Implements the `seac' Type 1 operator for a Type 1 decoder. */ | |
257 | /* */ | |
258 | /* <Input> */ | |
259 | /* decoder :: The current CID decoder. */ | |
260 | /* */ | |
261 | /* asb :: The accent's side bearing. */ | |
262 | /* */ | |
263 | /* adx :: The horizontal offset of the accent. */ | |
264 | /* */ | |
265 | /* ady :: The vertical offset of the accent. */ | |
266 | /* */ | |
267 | /* bchar :: The base character's StandardEncoding charcode. */ | |
268 | /* */ | |
269 | /* achar :: The accent character's StandardEncoding charcode. */ | |
270 | /* */ | |
271 | /* <Return> */ | |
272 | /* FreeType error code. 0 means success. */ | |
273 | /* */ | |
274 | static | |
275 | FT_Error t1operator_seac( T1_Decoder* decoder, | |
276 | FT_Pos asb, | |
277 | FT_Pos adx, | |
278 | FT_Pos ady, | |
279 | FT_Int bchar, | |
280 | FT_Int achar ) | |
281 | { | |
282 | FT_Error error; | |
283 | FT_Int bchar_index, achar_index, n_base_points; | |
284 | FT_Outline* base = decoder->builder.base; | |
285 | FT_Vector left_bearing, advance; | |
286 | T1_Face face = decoder->builder.face; | |
287 | T1_Font* type1 = &face->type1; | |
288 | ||
289 | ||
290 | bchar_index = lookup_glyph_by_stdcharcode( face, bchar ); | |
291 | achar_index = lookup_glyph_by_stdcharcode( face, achar ); | |
292 | ||
293 | if ( bchar_index < 0 || achar_index < 0 ) | |
294 | { | |
295 | FT_ERROR(( "t1operator_seac:" )); | |
296 | FT_ERROR(( " invalid seac character code arguments\n" )); | |
297 | return T1_Err_Syntax_Error; | |
298 | } | |
299 | ||
300 | /* if we are trying to load a composite glyph, do not load the */ | |
301 | /* accent character and return the array of subglyphs. */ | |
302 | if ( decoder->builder.no_recurse ) | |
303 | { | |
304 | FT_GlyphSlot glyph = (FT_GlyphSlot)decoder->builder.glyph; | |
305 | FT_GlyphLoader* loader = glyph->loader; | |
306 | FT_SubGlyph* subg; | |
307 | ||
308 | ||
309 | /* reallocate subglyph array if necessary */ | |
310 | error = FT_GlyphLoader_Check_Subglyphs( loader, 2 ); | |
311 | if ( error ) | |
312 | goto Exit; | |
313 | ||
314 | subg = loader->current.subglyphs; | |
315 | ||
316 | /* subglyph 0 = base character */ | |
317 | subg->index = bchar_index; | |
318 | subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES | | |
319 | FT_SUBGLYPH_FLAG_USE_MY_METRICS; | |
320 | subg->arg1 = 0; | |
321 | subg->arg2 = 0; | |
322 | subg++; | |
323 | ||
324 | /* subglyph 1 = accent character */ | |
325 | subg->index = achar_index; | |
326 | subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES; | |
327 | subg->arg1 = adx - asb; | |
328 | subg->arg2 = ady; | |
329 | ||
330 | /* set up remaining glyph fields */ | |
331 | glyph->num_subglyphs = 2; | |
332 | glyph->subglyphs = loader->current.subglyphs; | |
333 | glyph->format = ft_glyph_format_composite; | |
334 | ||
335 | loader->current.num_subglyphs = 2; | |
336 | goto Exit; | |
337 | } | |
338 | ||
339 | /* First load `bchar' in builder */ | |
340 | /* now load the unscaled outline */ | |
341 | ||
342 | if ( decoder->builder.loader ) | |
343 | FT_GlyphLoader_Prepare( decoder->builder.loader ); /* prepare loader */ | |
344 | ||
345 | error = T1_Parse_CharStrings( decoder, | |
346 | type1->charstrings [bchar_index], | |
347 | type1->charstrings_len[bchar_index], | |
348 | type1->num_subrs, | |
349 | type1->subrs, | |
350 | type1->subrs_len ); | |
351 | if ( error ) | |
352 | goto Exit; | |
353 | ||
354 | n_base_points = base->n_points; | |
355 | ||
356 | /* save the left bearing and width of the base character */ | |
357 | /* as they will be erased by the next load. */ | |
358 | ||
359 | left_bearing = decoder->builder.left_bearing; | |
360 | advance = decoder->builder.advance; | |
361 | ||
362 | decoder->builder.left_bearing.x = 0; | |
363 | decoder->builder.left_bearing.y = 0; | |
364 | ||
365 | /* Now load `achar' on top of the base outline */ | |
366 | error = T1_Parse_CharStrings( decoder, | |
367 | type1->charstrings [achar_index], | |
368 | type1->charstrings_len[achar_index], | |
369 | type1->num_subrs, | |
370 | type1->subrs, | |
371 | type1->subrs_len ); | |
372 | if ( error ) | |
373 | return error; | |
374 | ||
375 | /* restore the left side bearing and */ | |
376 | /* advance width of the base character */ | |
377 | ||
378 | decoder->builder.left_bearing = left_bearing; | |
379 | decoder->builder.advance = advance; | |
380 | ||
381 | /* Finally, move the accent */ | |
382 | if ( decoder->builder.load_points ) | |
383 | { | |
384 | FT_Outline dummy; | |
385 | ||
386 | ||
387 | dummy.n_points = base->n_points - n_base_points; | |
388 | dummy.points = base->points + n_base_points; | |
389 | ||
390 | FT_Outline_Translate( &dummy, adx - asb, ady ); | |
391 | } | |
392 | ||
393 | Exit: | |
394 | return error; | |
395 | } | |
396 | ||
397 | ||
398 | /*************************************************************************/ | |
399 | /* */ | |
400 | /* <Function> */ | |
401 | /* t1operator_flex */ | |
402 | /* */ | |
403 | /* <Description> */ | |
404 | /* Implements the `flex' Type 1 operator for a Type 1 decoder. */ | |
405 | /* */ | |
406 | /* <Input> */ | |
407 | /* decoder :: The current Type 1 decoder. */ | |
408 | /* threshold :: The threshold. */ | |
409 | /* end_x :: The horizontal position of the final flex point. */ | |
410 | /* end_y :: The vertical position of the final flex point. */ | |
411 | /* */ | |
412 | /* <Return> */ | |
413 | /* FreeType error code. 0 means success. */ | |
414 | /* */ | |
415 | static | |
416 | FT_Error t1operator_flex( T1_Decoder* decoder, | |
417 | FT_Pos threshold, | |
418 | FT_Pos end_x, | |
419 | FT_Pos end_y ) | |
420 | { | |
421 | FT_Vector vec; | |
422 | FT_Vector* flex = decoder->flex_vectors; | |
423 | FT_Int n; | |
424 | ||
425 | FT_UNUSED( threshold ); | |
426 | FT_UNUSED( end_x ); | |
427 | FT_UNUSED( end_y ); | |
428 | ||
429 | ||
430 | /* we don't even try to test the threshold in the non-hinting */ | |
431 | /* builder, even if the flex operator is said to be a path */ | |
432 | /* construction statement in the specification. This is better */ | |
433 | /* left to the hinter. */ | |
434 | ||
435 | flex = decoder->flex_vectors; | |
436 | vec = *flex++; | |
437 | ||
438 | for ( n = 0; n < 6; n++ ) | |
439 | { | |
440 | flex->x += vec.x; | |
441 | flex->y += vec.y; | |
442 | ||
443 | vec = *flex++; | |
444 | } | |
445 | ||
446 | flex = decoder->flex_vectors; | |
447 | ||
448 | return decoder->builder.funcs.rcurve_to( &decoder->builder, | |
449 | flex[0].x, flex[0].y, | |
450 | flex[1].x, flex[1].y, | |
451 | flex[2].x, flex[2].y ) || | |
452 | ||
453 | decoder->builder.funcs.rcurve_to( &decoder->builder, | |
454 | flex[3].x, flex[3].y, | |
455 | flex[4].x, flex[4].y, | |
456 | flex[5].x, flex[5].y ); | |
457 | } | |
458 | ||
459 | ||
460 | /*************************************************************************/ | |
461 | /* */ | |
462 | /* <Function> */ | |
463 | /* T1_Parse_CharStrings */ | |
464 | /* */ | |
465 | /* <Description> */ | |
466 | /* Parses a given Type 1 charstrings program. */ | |
467 | /* */ | |
468 | /* <Input> */ | |
469 | /* decoder :: The current Type 1 decoder. */ | |
470 | /* */ | |
471 | /* charstring_base :: The base address of the charstring stream. */ | |
472 | /* */ | |
473 | /* charstring_len :: The length in bytes of the charstring stream. */ | |
474 | /* */ | |
475 | /* num_subrs :: The number of sub-routines. */ | |
476 | /* */ | |
477 | /* subrs_base :: An array of sub-routines addresses. */ | |
478 | /* */ | |
479 | /* subrs_len :: An array of sub-routines lengths. */ | |
480 | /* */ | |
481 | /* <Return> */ | |
482 | /* Free error code. 0 means success. */ | |
483 | /* */ | |
484 | LOCAL_FUNC | |
485 | FT_Error T1_Parse_CharStrings( T1_Decoder* decoder, | |
486 | FT_Byte* charstring_base, | |
487 | FT_Int charstring_len, | |
488 | FT_Int num_subrs, | |
489 | FT_Byte** subrs_base, | |
490 | FT_Int* subrs_len ) | |
491 | { | |
492 | FT_Error error; | |
493 | T1_Decoder_Zone* zone; | |
494 | FT_Byte* ip; | |
495 | FT_Byte* limit; | |
496 | T1_Builder* builder = &decoder->builder; | |
497 | T1_Builder_Funcs* builds = &builder->funcs; | |
498 | T1_Hinter_Funcs* hints = &decoder->hinter; | |
499 | ||
500 | static | |
501 | const FT_Int args_count[op_max] = | |
502 | { | |
503 | 0, /* none */ | |
504 | 0, /* endchar */ | |
505 | 2, /* hsbw */ | |
506 | 5, /* seac */ | |
507 | 4, /* sbw */ | |
508 | 0, /* closepath */ | |
509 | 1, /* hlineto */ | |
510 | 1, /* hmoveto */ | |
511 | 4, /* hvcurveto */ | |
512 | 2, /* rlineto */ | |
513 | 2, /* rmoveto */ | |
514 | 6, /* rrcurveto */ | |
515 | 4, /* vhcurveto */ | |
516 | 1, /* vlineto */ | |
517 | 1, /* vmoveto */ | |
518 | 0, /* dotsection */ | |
519 | 2, /* hstem */ | |
520 | 6, /* hstem3 */ | |
521 | 2, /* vstem */ | |
522 | 6, /* vstem3 */ | |
523 | 2, /* div */ | |
524 | -1, /* callothersubr */ | |
525 | 1, /* callsubr */ | |
526 | 0, /* pop */ | |
527 | 0, /* return */ | |
528 | 2 /* setcurrentpoint */ | |
529 | }; | |
530 | ||
531 | ||
532 | /* First of all, initialize the decoder */ | |
533 | decoder->top = decoder->stack; | |
534 | decoder->zone = decoder->zones; | |
535 | zone = decoder->zones; | |
536 | ||
537 | builder->path_begun = 0; | |
538 | ||
539 | zone->base = charstring_base; | |
540 | limit = zone->limit = charstring_base + charstring_len; | |
541 | ip = zone->cursor = zone->base; | |
542 | ||
543 | error = T1_Err_Ok; | |
544 | ||
545 | /* now, execute loop */ | |
546 | while ( ip < limit ) | |
547 | { | |
548 | FT_Int* top = decoder->top; | |
549 | T1_Operator op = op_none; | |
550 | FT_Long value = 0; | |
551 | ||
552 | ||
553 | /* Start with the decompression of operator or value */ | |
554 | switch ( *ip++ ) | |
555 | { | |
556 | case 1: | |
557 | op = op_hstem; | |
558 | break; | |
559 | ||
560 | case 3: | |
561 | op = op_vstem; | |
562 | break; | |
563 | case 4: | |
564 | op = op_vmoveto; | |
565 | break; | |
566 | case 5: | |
567 | op = op_rlineto; | |
568 | break; | |
569 | case 6: | |
570 | op = op_hlineto; | |
571 | break; | |
572 | case 7: | |
573 | op = op_vlineto; | |
574 | break; | |
575 | case 8: | |
576 | op = op_rrcurveto; | |
577 | break; | |
578 | case 9: | |
579 | op = op_closepath; | |
580 | break; | |
581 | case 10: | |
582 | op = op_callsubr; | |
583 | break; | |
584 | case 11: | |
585 | op = op_return; | |
586 | break; | |
587 | ||
588 | case 13: | |
589 | op = op_hsbw; | |
590 | break; | |
591 | case 14: | |
592 | op = op_endchar; | |
593 | break; | |
594 | ||
595 | case 21: | |
596 | op = op_rmoveto; | |
597 | break; | |
598 | case 22: | |
599 | op = op_hmoveto; | |
600 | break; | |
601 | ||
602 | case 30: | |
603 | op = op_vhcurveto; | |
604 | break; | |
605 | case 31: | |
606 | op = op_hvcurveto; | |
607 | break; | |
608 | ||
609 | case 12: | |
610 | if ( ip > limit ) | |
611 | { | |
612 | FT_ERROR(( "T1_Parse_CharStrings: invalid escape (12+EOF)\n" )); | |
613 | goto Syntax_Error; | |
614 | } | |
615 | ||
616 | switch ( *ip++ ) | |
617 | { | |
618 | case 0: | |
619 | op = op_dotsection; | |
620 | break; | |
621 | case 1: | |
622 | op = op_vstem3; | |
623 | break; | |
624 | case 2: | |
625 | op = op_hstem3; | |
626 | break; | |
627 | case 6: | |
628 | op = op_seac; | |
629 | break; | |
630 | case 7: | |
631 | op = op_sbw; | |
632 | break; | |
633 | case 12: | |
634 | op = op_div; | |
635 | break; | |
636 | case 16: | |
637 | op = op_callothersubr; | |
638 | break; | |
639 | case 17: | |
640 | op = op_pop; | |
641 | break; | |
642 | case 33: | |
643 | op = op_setcurrentpoint; | |
644 | break; | |
645 | ||
646 | default: | |
647 | FT_ERROR(( "T1_Parse_CharStrings: invalid escape (12+%d)\n", | |
648 | ip[-1] )); | |
649 | goto Syntax_Error; | |
650 | } | |
651 | break; | |
652 | ||
653 | case 255: /* four bytes integer */ | |
654 | if ( ip + 4 > limit ) | |
655 | { | |
656 | FT_ERROR(( "T1_Parse_CharStrings: unexpected EOF in integer\n" )); | |
657 | goto Syntax_Error; | |
658 | } | |
659 | ||
660 | value = ( (FT_Long)ip[0] << 24 ) | | |
661 | ( (FT_Long)ip[1] << 16 ) | | |
662 | ( (FT_Long)ip[2] << 8 ) | | |
663 | ip[3]; | |
664 | ip += 4; | |
665 | break; | |
666 | ||
667 | default: | |
668 | if ( ip[-1] >= 32 ) | |
669 | { | |
670 | if ( ip[-1] < 247 ) | |
671 | value = (FT_Long)ip[-1] - 139; | |
672 | else | |
673 | { | |
674 | if ( ++ip > limit ) | |
675 | { | |
676 | FT_ERROR(( "T1_Parse_CharStrings:" )); | |
677 | FT_ERROR(( " unexpected EOF in integer\n" )); | |
678 | goto Syntax_Error; | |
679 | } | |
680 | ||
681 | if ( ip[-2] < 251 ) | |
682 | value = ((FT_Long)( ip[-2] - 247 ) << 8 ) + ip[-1] + 108; | |
683 | else | |
684 | value = -( ( ( (FT_Long)ip[-2] - 251 ) << 8 ) + ip[-1] + 108 ); | |
685 | } | |
686 | } | |
687 | else | |
688 | { | |
689 | FT_ERROR(( "T1_Parse_CharStrings: invalid byte (%d)\n", | |
690 | ip[-1] )); | |
691 | goto Syntax_Error; | |
692 | } | |
693 | } | |
694 | ||
695 | /* push value if necessary */ | |
696 | if ( op == op_none ) | |
697 | { | |
698 | if ( top - decoder->stack >= T1_MAX_CHARSTRINGS_OPERANDS ) | |
699 | { | |
700 | FT_ERROR(( "T1_Parse_CharStrings: stack overflow!\n" )); | |
701 | goto Syntax_Error; | |
702 | } | |
703 | ||
704 | *top++ = value; | |
705 | decoder->top = top; | |
706 | } | |
707 | ||
708 | else if ( op == op_callothersubr ) /* check arguments differently */ | |
709 | { | |
710 | if ( top - decoder->stack < 2 ) | |
711 | goto Stack_Underflow; | |
712 | ||
713 | top -= 2; | |
714 | ||
715 | switch ( top[1] ) | |
716 | { | |
717 | case 1: /* start flex feature */ | |
718 | if ( top[0] != 0 ) | |
719 | goto Unexpected_OtherSubr; | |
720 | ||
721 | decoder->flex_state = 1; | |
722 | decoder->num_flex_vectors = 0; | |
723 | decoder->flex_vectors[0].x = 0; | |
724 | decoder->flex_vectors[0].y = 0; | |
725 | break; | |
726 | ||
727 | case 2: /* add flex vector */ | |
728 | { | |
729 | FT_Int index; | |
730 | FT_Vector* flex; | |
731 | ||
732 | ||
733 | if ( top[0] != 0 ) | |
734 | goto Unexpected_OtherSubr; | |
735 | ||
736 | top -= 2; | |
737 | if ( top < decoder->stack ) | |
738 | goto Stack_Underflow; | |
739 | ||
740 | index = decoder->num_flex_vectors++; | |
741 | if ( index >= 7 ) | |
742 | { | |
743 | FT_ERROR(( "T1_Parse_CharStrings: too many flex vectors!\n" )); | |
744 | goto Syntax_Error; | |
745 | } | |
746 | ||
747 | flex = decoder->flex_vectors + index; | |
748 | flex->x += top[0]; | |
749 | flex->y += top[1]; | |
750 | } | |
751 | break; | |
752 | ||
753 | case 0: /* end flex feature */ | |
754 | if ( decoder->flex_state == 0 || | |
755 | decoder->num_flex_vectors != 7 ) | |
756 | { | |
757 | FT_ERROR(( "T1_Parse_CharStrings: unexpected flex end\n" )); | |
758 | goto Syntax_Error; | |
759 | } | |
760 | ||
761 | if ( top[0] != 3 ) | |
762 | goto Unexpected_OtherSubr; | |
763 | ||
764 | top -= 3; | |
765 | if ( top < decoder->stack ) | |
766 | goto Stack_Underflow; | |
767 | ||
768 | /* now consume the remaining `pop pop setcurrentpoint' */ | |
769 | if ( ip + 6 > limit || | |
770 | ip[0] != 12 || ip[1] != 17 || /* pop */ | |
771 | ip[2] != 12 || ip[3] != 17 || /* pop */ | |
772 | ip[4] != 12 || ip[5] != 33 ) /* setcurrentpoint */ | |
773 | { | |
774 | FT_ERROR(( "T1_Parse_CharStrings: invalid flex charstring\n" )); | |
775 | goto Syntax_Error; | |
776 | } | |
777 | ||
778 | decoder->flex_state = 0; | |
779 | decoder->top = top; | |
780 | ||
781 | error = t1operator_flex( decoder, top[0], top[1], top[2] ); | |
782 | break; | |
783 | ||
784 | case 3: /* change hints */ | |
785 | if ( top[0] != 1 ) | |
786 | goto Unexpected_OtherSubr; | |
787 | ||
788 | /* eat the following `pop' */ | |
789 | if ( ip + 2 > limit ) | |
790 | { | |
791 | FT_ERROR(( "T1_Parse_CharStrings: invalid escape (12+%d)\n", | |
792 | ip[-1] )); | |
793 | goto Syntax_Error; | |
794 | } | |
795 | ||
796 | if ( ip[0] != 12 || ip[1] != 17 ) | |
797 | { | |
798 | FT_ERROR(( "T1_Parse_CharStrings:" )); | |
799 | FT_ERROR(( " `pop' expected, found (%d %d)\n", ip[0], ip[1] )); | |
800 | goto Syntax_Error; | |
801 | } | |
802 | ||
803 | ip += 2; | |
804 | ||
805 | error = hints->change_hints( builder ); | |
806 | break; | |
807 | ||
808 | default: | |
809 | /* invalid OtherSubrs call */ | |
810 | Unexpected_OtherSubr: | |
811 | FT_ERROR(( "T1_Parse_CharStrings: unexpected OtherSubrs [%d %d]\n", | |
812 | top[0], top[1] )); | |
813 | goto Syntax_Error; | |
814 | } | |
815 | decoder->top = top; | |
816 | } | |
817 | else | |
818 | { | |
819 | FT_Int num_args = args_count[op]; | |
820 | ||
821 | ||
822 | if ( top - decoder->stack < num_args ) | |
823 | goto Stack_Underflow; | |
824 | ||
825 | top -= num_args; | |
826 | ||
827 | switch ( op ) | |
828 | { | |
829 | case op_endchar: | |
830 | error = builds->end_char( builder ); | |
831 | break; | |
832 | ||
833 | case op_hsbw: | |
834 | error = builds->set_bearing_point( builder, top[0], 0, | |
835 | top[1], 0 ); | |
836 | break; | |
837 | ||
838 | case op_seac: | |
839 | /* return immediately after the processing */ | |
840 | return t1operator_seac( decoder, top[0], top[1], | |
841 | top[2], top[3], top[4] ); | |
842 | ||
843 | case op_sbw: | |
844 | error = builds->set_bearing_point( builder, top[0], top[1], | |
845 | top[2], top[3] ); | |
846 | break; | |
847 | ||
848 | case op_closepath: | |
849 | error = builds->close_path( builder ); | |
850 | break; | |
851 | ||
852 | case op_hlineto: | |
853 | error = builds->rline_to( builder, top[0], 0 ); | |
854 | break; | |
855 | ||
856 | case op_hmoveto: | |
857 | error = builds->rmove_to( builder, top[0], 0 ); | |
858 | break; | |
859 | ||
860 | case op_hvcurveto: | |
861 | error = builds->rcurve_to( builder, top[0], 0, | |
862 | top[1], top[2], | |
863 | 0, top[3] ); | |
864 | break; | |
865 | ||
866 | case op_rlineto: | |
867 | error = builds->rline_to( builder, top[0], top[1] ); | |
868 | break; | |
869 | ||
870 | case op_rmoveto: | |
871 | /* ignore operator when in flex mode */ | |
872 | if ( decoder->flex_state == 0 ) | |
873 | error = builds->rmove_to( builder, top[0], top[1] ); | |
874 | else | |
875 | top += 2; | |
876 | break; | |
877 | ||
878 | case op_rrcurveto: | |
879 | error = builds->rcurve_to( builder, top[0], top[1], | |
880 | top[2], top[3], | |
881 | top[4], top[5] ); | |
882 | break; | |
883 | ||
884 | case op_vhcurveto: | |
885 | error = builds->rcurve_to( builder, 0, top[0], | |
886 | top[1], top[2], | |
887 | top[3], 0 ); | |
888 | break; | |
889 | ||
890 | case op_vlineto: | |
891 | error = builds->rline_to( builder, 0, top[0] ); | |
892 | break; | |
893 | ||
894 | case op_vmoveto: | |
895 | error = builds->rmove_to( builder, 0, top[0] ); | |
896 | break; | |
897 | ||
898 | case op_dotsection: | |
899 | error = hints->dot_section( builder ); | |
900 | break; | |
901 | ||
902 | case op_hstem: | |
903 | error = hints->stem( builder, top[0], top[1], 0 ); | |
904 | break; | |
905 | ||
906 | case op_hstem3: | |
907 | error = hints->stem3( builder, top[0], top[1], top[2], | |
908 | top[3], top[4], top[5], 0 ); | |
909 | break; | |
910 | ||
911 | case op_vstem: | |
912 | error = hints->stem( builder, top[0], top[1], 1 ); | |
913 | break; | |
914 | ||
915 | case op_vstem3: | |
916 | error = hints->stem3( builder, top[0], top[1], top[2], | |
917 | top[3], top[4], top[5], 1 ); | |
918 | break; | |
919 | ||
920 | case op_div: | |
921 | if ( top[1] ) | |
922 | { | |
923 | *top = top[0] / top[1]; | |
924 | ++top; | |
925 | } | |
926 | else | |
927 | { | |
928 | FT_ERROR(( "T1_Parse_CHarStrings: division by 0\n" )); | |
929 | goto Syntax_Error; | |
930 | } | |
931 | break; | |
932 | ||
933 | case op_callsubr: | |
934 | { | |
935 | FT_Int index = top[0]; | |
936 | ||
937 | ||
938 | if ( index < 0 || index >= num_subrs ) | |
939 | { | |
940 | FT_ERROR(( "T1_Parse_CharStrings: invalid subrs index\n" )); | |
941 | goto Syntax_Error; | |
942 | } | |
943 | ||
944 | if ( zone - decoder->zones >= T1_MAX_SUBRS_CALLS ) | |
945 | { | |
946 | FT_ERROR(( "T1_Parse_CharStrings: too many nested subrs\n" )); | |
947 | goto Syntax_Error; | |
948 | } | |
949 | ||
950 | zone->cursor = ip; /* save current instruction pointer */ | |
951 | ||
952 | zone++; | |
953 | zone->base = subrs_base[index]; | |
954 | zone->limit = zone->base + subrs_len[index]; | |
955 | zone->cursor = zone->base; | |
956 | ||
957 | if ( !zone->base ) | |
958 | { | |
959 | FT_ERROR(( "T1_Parse_CharStrings: invoking empty subrs!\n" )); | |
960 | goto Syntax_Error; | |
961 | } | |
962 | ||
963 | decoder->zone = zone; | |
964 | ip = zone->base; | |
965 | limit = zone->limit; | |
966 | } | |
967 | break; | |
968 | ||
969 | case op_pop: | |
970 | FT_ERROR(( "T1_Parse_CharStrings: unexpected POP\n" )); | |
971 | goto Syntax_Error; | |
972 | ||
973 | case op_return: | |
974 | if ( zone <= decoder->zones ) | |
975 | { | |
976 | FT_ERROR(( "T1_Parse_CharStrings: unexpected return\n" )); | |
977 | goto Syntax_Error; | |
978 | } | |
979 | ||
980 | zone--; | |
981 | ip = zone->cursor; | |
982 | limit = zone->limit; | |
983 | decoder->zone = zone; | |
984 | break; | |
985 | ||
986 | case op_setcurrentpoint: | |
987 | FT_ERROR(( "T1_Parse_CharStrings:" )); | |
988 | FT_ERROR(( " unexpected `setcurrentpoint'\n" )); | |
989 | goto Syntax_Error; | |
990 | break; | |
991 | ||
992 | default: | |
993 | FT_ERROR(( "T1_Parse_CharStrings: unhandled opcode %d\n", op )); | |
994 | goto Syntax_Error; | |
995 | } | |
996 | ||
997 | decoder->top = top; | |
998 | } | |
999 | } | |
1000 | ||
1001 | return error; | |
1002 | ||
1003 | Syntax_Error: | |
1004 | return T1_Err_Syntax_Error; | |
1005 | ||
1006 | Stack_Underflow: | |
1007 | return T1_Err_Stack_Underflow; | |
1008 | } | |
1009 | ||
1010 | ||
1011 | /*************************************************************************/ | |
1012 | /* */ | |
1013 | /* <Function> */ | |
1014 | /* T1_Add_Points */ | |
1015 | /* */ | |
1016 | /* <Description> */ | |
1017 | /* Checks that there is enough room in the current load glyph outline */ | |
1018 | /* to accept `num_points' additional outline points. If not, this */ | |
1019 | /* function grows the load outline's arrays accordingly. */ | |
1020 | /* */ | |
1021 | /* <Input> */ | |
1022 | /* builder :: A pointer to the glyph builder object. */ | |
1023 | /* */ | |
1024 | /* num_points :: The number of points that will be added later. */ | |
1025 | /* */ | |
1026 | /* <Return> */ | |
1027 | /* FreeType error code. 0 means success. */ | |
1028 | /* */ | |
1029 | /* <Note> */ | |
1030 | /* This function does NOT update the points count in the glyph */ | |
1031 | /* builder. This must be done by the caller itself, after this */ | |
1032 | /* function has been invoked. */ | |
1033 | /* */ | |
1034 | LOCAL_FUNC | |
1035 | FT_Error T1_Add_Points( T1_Builder* builder, | |
1036 | FT_Int num_points ) | |
1037 | { | |
1038 | return FT_GlyphLoader_Check_Points( builder->loader, num_points, 0 ); | |
1039 | } | |
1040 | ||
1041 | ||
1042 | /*************************************************************************/ | |
1043 | /* */ | |
1044 | /* <Function> */ | |
1045 | /* T1_Add_Contours */ | |
1046 | /* */ | |
1047 | /* <Description> */ | |
1048 | /* Checks that there is enough room in the current load glyph outline */ | |
1049 | /* to accept `num_contours' additional contours. If not, this */ | |
1050 | /* function grows the load outline's arrays accordingly. */ | |
1051 | /* */ | |
1052 | /* <Input> */ | |
1053 | /* builder :: A pointer to the glyph builder object. */ | |
1054 | /* */ | |
1055 | /* num_contours :: The number of contours that will be added later. */ | |
1056 | /* */ | |
1057 | /* <Return> */ | |
1058 | /* FreeType error code. 0 means success. */ | |
1059 | /* */ | |
1060 | /* <Note> */ | |
1061 | /* This function does NOT update the contours count in the load glyph */ | |
1062 | /* This must be done by the caller itself, after this function is */ | |
1063 | /* invoked. */ | |
1064 | /* */ | |
1065 | LOCAL_FUNC | |
1066 | FT_Error T1_Add_Contours( T1_Builder* builder, | |
1067 | FT_Int num_contours ) | |
1068 | { | |
1069 | return FT_GlyphLoader_Check_Points( builder->loader, 0, num_contours ); | |
1070 | } | |
1071 | ||
1072 | ||
1073 | /*************************************************************************/ | |
1074 | /*************************************************************************/ | |
1075 | /*************************************************************************/ | |
1076 | /********** *********/ | |
1077 | /********** COMPUTE THE MAXIMUM ADVANCE WIDTH *********/ | |
1078 | /********** *********/ | |
1079 | /********** The following code is in charge of computing *********/ | |
1080 | /********** the maximum advance width of the font. It *********/ | |
1081 | /********** quickly processes each glyph charstring to *********/ | |
1082 | /********** extract the value from either a `sbw' or `seac' *********/ | |
1083 | /********** operator. *********/ | |
1084 | /********** *********/ | |
1085 | /*************************************************************************/ | |
1086 | /*************************************************************************/ | |
1087 | /*************************************************************************/ | |
1088 | ||
1089 | ||
1090 | static | |
1091 | FT_Error maxadv_sbw( T1_Decoder* decoder, | |
1092 | FT_Pos sbx, | |
1093 | FT_Pos sby, | |
1094 | FT_Pos wx, | |
1095 | FT_Pos wy ) | |
1096 | { | |
1097 | FT_UNUSED( sbx ); | |
1098 | FT_UNUSED( sby ); | |
1099 | FT_UNUSED( wy ); | |
1100 | ||
1101 | if ( wx > decoder->builder.advance.x ) | |
1102 | decoder->builder.advance.x = wx; | |
1103 | ||
1104 | return -1; /* return an error code to exit the Type 1 parser */ | |
1105 | /* immediately. */ | |
1106 | } | |
1107 | ||
1108 | ||
1109 | static | |
1110 | FT_Int maxadv_error( void ) | |
1111 | { | |
1112 | /* we should never reach this code, unless with a buggy font */ | |
1113 | return -2; | |
1114 | } | |
1115 | ||
1116 | ||
1117 | /* the maxadv_gbuilder_interface is used when computing the maximum */ | |
1118 | /* advance width of all glyphs in a given font. We only process the */ | |
1119 | /* `sbw' operator here, and return an error for all others. */ | |
1120 | ||
1121 | /* Note that `seac' is processed by the T1_Decoder. */ | |
1122 | static | |
1123 | const T1_Builder_Funcs maxadv_builder_interface = | |
1124 | { | |
1125 | (T1_Builder_EndChar) maxadv_error, | |
1126 | (T1_Builder_Sbw) maxadv_sbw, | |
1127 | (T1_Builder_ClosePath)maxadv_error, | |
1128 | (T1_Builder_RLineTo) maxadv_error, | |
1129 | (T1_Builder_RMoveTo) maxadv_error, | |
1130 | (T1_Builder_RCurveTo) maxadv_error | |
1131 | }; | |
1132 | ||
1133 | ||
1134 | /* the maxadv_hinter_interface always return an error. */ | |
1135 | static | |
1136 | const T1_Hinter_Funcs maxadv_hinter_interface = | |
1137 | { | |
1138 | (T1_Hinter_DotSection) maxadv_error, | |
1139 | (T1_Hinter_ChangeHints)maxadv_error, | |
1140 | (T1_Hinter_Stem) maxadv_error, | |
1141 | (T1_Hinter_Stem3) maxadv_error, | |
1142 | }; | |
1143 | ||
1144 | ||
1145 | LOCAL_FUNC | |
1146 | FT_Error T1_Compute_Max_Advance( T1_Face face, | |
1147 | FT_Int* max_advance ) | |
1148 | { | |
1149 | FT_Error error; | |
1150 | T1_Decoder decoder; | |
1151 | FT_Int glyph_index; | |
1152 | T1_Font* type1 = &face->type1; | |
1153 | ||
1154 | ||
1155 | *max_advance = 0; | |
1156 | ||
1157 | /* Initialize load decoder */ | |
1158 | T1_Init_Decoder( &decoder, &maxadv_hinter_interface ); | |
1159 | ||
1160 | T1_Init_Builder( &decoder.builder, face, 0, 0, | |
1161 | &maxadv_builder_interface ); | |
1162 | ||
1163 | /* For each glyph, parse the glyph charstring and extract */ | |
1164 | /* the advance width. */ | |
1165 | for ( glyph_index = 0; glyph_index < type1->num_glyphs; glyph_index++ ) | |
1166 | { | |
1167 | /* now get load the unscaled outline */ | |
1168 | error = T1_Parse_CharStrings( &decoder, | |
1169 | type1->charstrings [glyph_index], | |
1170 | type1->charstrings_len[glyph_index], | |
1171 | type1->num_subrs, | |
1172 | type1->subrs, | |
1173 | type1->subrs_len ); | |
1174 | /* ignore the error if one occured - skip to next glyph */ | |
1175 | } | |
1176 | ||
1177 | *max_advance = decoder.builder.advance.x; | |
1178 | return T1_Err_Ok; | |
1179 | } | |
1180 | ||
1181 | ||
1182 | /*************************************************************************/ | |
1183 | /*************************************************************************/ | |
1184 | /*************************************************************************/ | |
1185 | /********** *********/ | |
1186 | /********** UNHINTED GLYPH LOADER *********/ | |
1187 | /********** *********/ | |
1188 | /********** The following code is in charge of loading a *********/ | |
1189 | /********** single outline. It completely ignores hinting *********/ | |
1190 | /********** and is used when FT_LOAD_NO_HINTING is set. *********/ | |
1191 | /********** *********/ | |
1192 | /********** The Type 1 hinter is located in `t1hint.c' *********/ | |
1193 | /********** *********/ | |
1194 | /*************************************************************************/ | |
1195 | /*************************************************************************/ | |
1196 | /*************************************************************************/ | |
1197 | ||
1198 | ||
1199 | static | |
1200 | FT_Error close_open_path( T1_Builder* builder ) | |
1201 | { | |
1202 | FT_Error error; | |
1203 | FT_Outline* cur = builder->current; | |
1204 | FT_Int num_points; | |
1205 | FT_Int first_point; | |
1206 | ||
1207 | ||
1208 | /* Some fonts, like Hershey, are made of `open paths' which are */ | |
1209 | /* now managed directly by FreeType. In this case, it is necessary */ | |
1210 | /* to close the path by duplicating its points in reverse order, */ | |
1211 | /* which is precisely the purpose of this function. */ | |
1212 | ||
1213 | /* first compute the number of points to duplicate */ | |
1214 | if ( cur->n_contours > 1 ) | |
1215 | first_point = cur->contours[cur->n_contours - 2] + 1; | |
1216 | else | |
1217 | first_point = 0; | |
1218 | ||
1219 | num_points = cur->n_points - first_point - 2; | |
1220 | if ( num_points > 0 ) | |
1221 | { | |
1222 | FT_Vector* source_point; | |
1223 | char* source_tags; | |
1224 | FT_Vector* point; | |
1225 | char* tags; | |
1226 | ||
1227 | ||
1228 | error = T1_Add_Points( builder, num_points ); | |
1229 | if ( error ) | |
1230 | return error; | |
1231 | ||
1232 | point = cur->points + cur->n_points; | |
1233 | tags = cur->tags + cur->n_points; | |
1234 | ||
1235 | source_point = point - 2; | |
1236 | source_tags = tags - 2; | |
1237 | ||
1238 | cur->n_points += num_points; | |
1239 | ||
1240 | if ( builder->load_points ) | |
1241 | do | |
1242 | { | |
1243 | *point++ = *source_point--; | |
1244 | *tags++ = *source_tags--; | |
1245 | num_points--; | |
1246 | ||
1247 | } while ( num_points > 0 ); | |
1248 | } | |
1249 | ||
1250 | builder->path_begun = 0; | |
1251 | return T1_Err_Ok; | |
1252 | } | |
1253 | ||
1254 | ||
1255 | static | |
1256 | FT_Error gload_closepath( T1_Builder* builder ) | |
1257 | { | |
1258 | FT_Outline* cur = builder->current; | |
1259 | ||
1260 | ||
1261 | /* XXXX: We must not include the last point in the path if it */ | |
1262 | /* is located on the first point. */ | |
1263 | if ( cur->n_points > 1 ) | |
1264 | { | |
1265 | FT_Int first = 0; | |
1266 | FT_Vector* p1 = cur->points + first; | |
1267 | FT_Vector* p2 = cur->points + cur->n_points - 1; | |
1268 | ||
1269 | ||
1270 | if ( cur->n_contours > 1 ) | |
1271 | { | |
1272 | first = cur->contours[cur->n_contours - 2] + 1; | |
1273 | p1 = cur->points + first; | |
1274 | } | |
1275 | ||
1276 | if ( p1->x == p2->x && p1->y == p2->y ) | |
1277 | cur->n_points--; | |
1278 | } | |
1279 | ||
1280 | /* save current contour, if any */ | |
1281 | if ( cur->n_contours > 0 ) | |
1282 | cur->contours[cur->n_contours - 1] = cur->n_points - 1; | |
1283 | ||
1284 | #ifndef T1_CONFIG_OPTION_DISABLE_HINTER | |
1285 | /* hint last points if necessary -- this is not strictly required */ | |
1286 | /* there, but it helps for debugging, and doesn't affect performance */ | |
1287 | if ( builder->pass == 1 ) | |
1288 | T1_Hint_Points( builder ); | |
1289 | #endif | |
1290 | ||
1291 | builder->path_begun = 0; | |
1292 | return T1_Err_Ok; | |
1293 | } | |
1294 | ||
1295 | ||
1296 | static | |
1297 | FT_Error gload_endchar( T1_Builder* builder ) | |
1298 | { | |
1299 | FT_Error error; | |
1300 | ||
1301 | ||
1302 | /* close path if needed */ | |
1303 | if ( builder->path_begun ) | |
1304 | { | |
1305 | error = close_open_path( builder ); | |
1306 | if ( error ) | |
1307 | return error; | |
1308 | } | |
1309 | ||
1310 | error = gload_closepath( builder ); | |
1311 | ||
1312 | FT_GlyphLoader_Add( builder->loader ); | |
1313 | ||
1314 | return error; | |
1315 | } | |
1316 | ||
1317 | ||
1318 | static | |
1319 | FT_Error gload_sbw( T1_Builder* builder, | |
1320 | FT_Pos sbx, | |
1321 | FT_Pos sby, | |
1322 | FT_Pos wx, | |
1323 | FT_Pos wy ) | |
1324 | { | |
1325 | builder->left_bearing.x += sbx; | |
1326 | builder->left_bearing.y += sby; | |
1327 | builder->advance.x = wx; | |
1328 | builder->advance.y = wy; | |
1329 | ||
1330 | builder->last.x = sbx; | |
1331 | builder->last.y = sby; | |
1332 | ||
1333 | return 0; | |
1334 | } | |
1335 | ||
1336 | ||
1337 | static | |
1338 | FT_Error gload_rlineto( T1_Builder* builder, | |
1339 | FT_Pos dx, | |
1340 | FT_Pos dy ) | |
1341 | { | |
1342 | FT_Error error; | |
1343 | FT_Outline* cur = builder->current; | |
1344 | FT_Vector vec; | |
1345 | ||
1346 | ||
1347 | /* grow buffer if necessary */ | |
1348 | error = T1_Add_Points( builder, 1 ); | |
1349 | if ( error ) | |
1350 | return error; | |
1351 | ||
1352 | if ( builder->load_points ) | |
1353 | { | |
1354 | /* save point */ | |
1355 | vec.x = builder->last.x + dx; | |
1356 | vec.y = builder->last.y + dy; | |
1357 | ||
1358 | cur->points[cur->n_points] = vec; | |
1359 | cur->tags [cur->n_points] = FT_Curve_Tag_On; | |
1360 | ||
1361 | builder->last = vec; | |
1362 | } | |
1363 | cur->n_points++; | |
1364 | ||
1365 | builder->path_begun = 1; | |
1366 | ||
1367 | return T1_Err_Ok; | |
1368 | } | |
1369 | ||
1370 | ||
1371 | static | |
1372 | FT_Error gload_rmoveto( T1_Builder* builder, | |
1373 | FT_Pos dx, | |
1374 | FT_Pos dy ) | |
1375 | { | |
1376 | FT_Error error; | |
1377 | FT_Outline* cur = builder->current; | |
1378 | FT_Vector vec; | |
1379 | ||
1380 | ||
1381 | /* in the case where `path_begun' is set, we have an `rmoveto' */ | |
1382 | /* after some normal path definition. If the face's paint type */ | |
1383 | /* is set to 1, this means that we have an `open path', also */ | |
1384 | /* called a `stroke'. The FreeType raster doesn't support */ | |
1385 | /* opened paths, so we'll close it explicitely there. */ | |
1386 | ||
1387 | if ( builder->path_begun && builder->face->type1.paint_type == 1 ) | |
1388 | { | |
1389 | if ( builder->face->type1.paint_type == 1 ) | |
1390 | { | |
1391 | error = close_open_path( builder ); | |
1392 | if ( error ) | |
1393 | return error; | |
1394 | } | |
1395 | } | |
1396 | ||
1397 | /* grow buffer if necessary */ | |
1398 | error = T1_Add_Contours( builder, 1 ) || | |
1399 | T1_Add_Points ( builder, 1 ); | |
1400 | if ( error ) | |
1401 | return error; | |
1402 | ||
1403 | /* save current contour, if any */ | |
1404 | if ( cur->n_contours > 0 ) | |
1405 | cur->contours[cur->n_contours - 1] = cur->n_points - 1; | |
1406 | ||
1407 | if ( builder->load_points ) | |
1408 | { | |
1409 | /* save point */ | |
1410 | vec.x = builder->last.x + dx; | |
1411 | vec.y = builder->last.y + dy; | |
1412 | cur->points[cur->n_points] = vec; | |
1413 | cur->tags [cur->n_points] = FT_Curve_Tag_On; | |
1414 | ||
1415 | builder->last = vec; | |
1416 | } | |
1417 | ||
1418 | cur->n_contours++; | |
1419 | cur->n_points++; | |
1420 | ||
1421 | return T1_Err_Ok; | |
1422 | } | |
1423 | ||
1424 | ||
1425 | static | |
1426 | FT_Error gload_rrcurveto( T1_Builder* builder, | |
1427 | FT_Pos dx1, | |
1428 | FT_Pos dy1, | |
1429 | FT_Pos dx2, | |
1430 | FT_Pos dy2, | |
1431 | FT_Pos dx3, | |
1432 | FT_Pos dy3 ) | |
1433 | { | |
1434 | FT_Error error; | |
1435 | FT_Outline* cur = builder->current; | |
1436 | FT_Vector vec; | |
1437 | FT_Vector* points; | |
1438 | char* tags; | |
1439 | ||
1440 | ||
1441 | /* grow buffer if necessary */ | |
1442 | error = T1_Add_Points( builder, 3 ); | |
1443 | if ( error ) | |
1444 | return error; | |
1445 | ||
1446 | if ( builder->load_points ) | |
1447 | { | |
1448 | /* save point */ | |
1449 | points = cur->points + cur->n_points; | |
1450 | tags = cur->tags + cur->n_points; | |
1451 | ||
1452 | vec.x = builder->last.x + dx1; | |
1453 | vec.y = builder->last.y + dy1; | |
1454 | points[0] = vec; | |
1455 | tags[0] = FT_Curve_Tag_Cubic; | |
1456 | ||
1457 | vec.x += dx2; | |
1458 | vec.y += dy2; | |
1459 | points[1] = vec; | |
1460 | tags[1] = FT_Curve_Tag_Cubic; | |
1461 | ||
1462 | vec.x += dx3; | |
1463 | vec.y += dy3; | |
1464 | points[2] = vec; | |
1465 | tags[2] = FT_Curve_Tag_On; | |
1466 | ||
1467 | builder->last = vec; | |
1468 | } | |
1469 | ||
1470 | cur->n_points += 3; | |
1471 | builder->path_begun = 1; | |
1472 | ||
1473 | return T1_Err_Ok; | |
1474 | } | |
1475 | ||
1476 | ||
1477 | static | |
1478 | FT_Error gload_ignore( void ) | |
1479 | { | |
1480 | return 0; | |
1481 | } | |
1482 | ||
1483 | ||
1484 | static | |
1485 | const T1_Builder_Funcs gload_builder_interface = | |
1486 | { | |
1487 | gload_endchar, | |
1488 | gload_sbw, | |
1489 | gload_closepath, | |
1490 | gload_rlineto, | |
1491 | gload_rmoveto, | |
1492 | gload_rrcurveto | |
1493 | }; | |
1494 | ||
1495 | ||
1496 | static | |
1497 | const T1_Builder_Funcs gload_builder_interface_null = | |
1498 | { | |
1499 | (T1_Builder_EndChar) gload_ignore, | |
1500 | (T1_Builder_Sbw) gload_sbw, /* record left bearing */ | |
1501 | (T1_Builder_ClosePath)gload_ignore, | |
1502 | (T1_Builder_RLineTo) gload_ignore, | |
1503 | (T1_Builder_RMoveTo) gload_ignore, | |
1504 | (T1_Builder_RCurveTo) gload_ignore | |
1505 | }; | |
1506 | ||
1507 | ||
1508 | static | |
1509 | const T1_Hinter_Funcs gload_hinter_interface = | |
1510 | { | |
1511 | (T1_Hinter_DotSection) gload_ignore, /* dotsection */ | |
1512 | (T1_Hinter_ChangeHints)gload_ignore, /* changehints */ | |
1513 | (T1_Hinter_Stem) gload_ignore, /* hstem & vstem */ | |
1514 | (T1_Hinter_Stem3) gload_ignore, /* hstem3 & vestem3 */ | |
1515 | }; | |
1516 | ||
1517 | ||
1518 | #ifndef T1_CONFIG_OPTION_DISABLE_HINTER | |
1519 | ||
1520 | ||
1521 | /*************************************************************************/ | |
1522 | /* */ | |
1523 | /* Hinter overview: */ | |
1524 | /* */ | |
1525 | /* This is a two-pass hinter. On the first pass, the hints are all */ | |
1526 | /* recorded by the hinter, and no point is loaded in the outline. */ | |
1527 | /* */ | |
1528 | /* When the first pass is finished, all stems hints are grid-fitted */ | |
1529 | /* at once. */ | |
1530 | /* */ | |
1531 | /* Then, a second pass is performed to load the outline points as */ | |
1532 | /* well as hint/scale them correctly. */ | |
1533 | /* */ | |
1534 | /*************************************************************************/ | |
1535 | ||
1536 | ||
1537 | static | |
1538 | FT_Error t1_load_hinted_glyph( T1_Decoder* decoder, | |
1539 | FT_UInt glyph_index, | |
1540 | FT_Bool recurse ) | |
1541 | { | |
1542 | T1_Builder* builder = &decoder->builder; | |
1543 | T1_GlyphSlot glyph = builder->glyph; | |
1544 | T1_Font* type1 = &builder->face->type1; | |
1545 | FT_UInt old_points, old_contours; | |
1546 | FT_GlyphLoader* loader = decoder->builder.loader; | |
1547 | FT_Error error; | |
1548 | ||
1549 | ||
1550 | /* Pass 1 -- try to load first glyph, simply recording points */ | |
1551 | old_points = loader->base.outline.n_points; | |
1552 | old_contours = loader->base.outline.n_contours; | |
1553 | ||
1554 | FT_GlyphLoader_Prepare( decoder->builder.loader ); | |
1555 | ||
1556 | T1_Reset_Builder( builder, 0 ); | |
1557 | ||
1558 | builder->no_recurse = recurse; | |
1559 | builder->pass = 0; | |
1560 | glyph->hints->hori_stems.num_stems = 0; | |
1561 | glyph->hints->vert_stems.num_stems = 0; | |
1562 | ||
1563 | error = T1_Parse_CharStrings( decoder, | |
1564 | type1->charstrings [glyph_index], | |
1565 | type1->charstrings_len[glyph_index], | |
1566 | type1->num_subrs, | |
1567 | type1->subrs, | |
1568 | type1->subrs_len ); | |
1569 | if ( error ) | |
1570 | goto Exit; | |
1571 | ||
1572 | /* check for composite (i.e. `seac' operator) */ | |
1573 | if ( glyph->root.format == ft_glyph_format_composite ) | |
1574 | { | |
1575 | /* this is a composite glyph, we must then load the first one, */ | |
1576 | /* then load the second one on top of it and translate it by a */ | |
1577 | /* fixed amount. */ | |
1578 | FT_UInt n_base_points; | |
1579 | FT_SubGlyph* subglyph = loader->base.subglyphs; | |
1580 | T1_Size size = builder->size; | |
1581 | FT_Pos dx, dy; | |
1582 | FT_Vector left_bearing, advance; | |
1583 | ||
1584 | ||
1585 | /* clean glyph format */ | |
1586 | glyph->root.format = ft_glyph_format_none; | |
1587 | ||
1588 | /* First load `bchar' in builder */ | |
1589 | builder->no_recurse = 0; | |
1590 | error = t1_load_hinted_glyph( decoder, subglyph->index, 0 ); | |
1591 | if ( error ) | |
1592 | goto Exit; | |
1593 | ||
1594 | /* save the left bearing and width of the base character */ | |
1595 | /* as they will be erased by the next load */ | |
1596 | left_bearing = builder->left_bearing; | |
1597 | advance = builder->advance; | |
1598 | ||
1599 | /* Then load `achar' in builder */ | |
1600 | n_base_points = builder->base->n_points; | |
1601 | subglyph++; | |
1602 | error = t1_load_hinted_glyph( decoder, subglyph->index, 0 ); | |
1603 | if ( error ) | |
1604 | goto Exit; | |
1605 | ||
1606 | /* Finally, move the accent */ | |
1607 | dx = FT_MulFix( subglyph->arg1, size->root.metrics.x_scale ); | |
1608 | dy = FT_MulFix( subglyph->arg2, size->root.metrics.y_scale ); | |
1609 | dx = ( dx + 32 ) & -64; | |
1610 | dy = ( dy + 32 ) & -64; | |
1611 | { | |
1612 | FT_Outline dummy; | |
1613 | ||
1614 | ||
1615 | dummy.n_points = loader->base.outline.n_points - n_base_points; | |
1616 | dummy.points = loader->base.outline.points + n_base_points; | |
1617 | ||
1618 | FT_Outline_Translate( &dummy, dx, dy ); | |
1619 | } | |
1620 | ||
1621 | /* restore the left side bearing and */ | |
1622 | /* advance width of the base character */ | |
1623 | builder->left_bearing = left_bearing; | |
1624 | builder->advance = advance; | |
1625 | } | |
1626 | else | |
1627 | { | |
1628 | /* All right, pass 1 is finished, now grid-fit all stem hints */ | |
1629 | T1_Hint_Stems( &decoder->builder ); | |
1630 | ||
1631 | /* undo the end-char */ | |
1632 | builder->base->n_points = old_points; | |
1633 | builder->base->n_contours = old_contours; | |
1634 | ||
1635 | /* Pass 2 -- record and scale/hint the points */ | |
1636 | T1_Reset_Builder( builder, 0 ); | |
1637 | ||
1638 | builder->pass = 1; | |
1639 | builder->no_recurse = 0; | |
1640 | ||
1641 | error = T1_Parse_CharStrings( decoder, | |
1642 | type1->charstrings [glyph_index], | |
1643 | type1->charstrings_len[glyph_index], | |
1644 | type1->num_subrs, | |
1645 | type1->subrs, | |
1646 | type1->subrs_len ); | |
1647 | } | |
1648 | ||
1649 | /* save new glyph tables */ | |
1650 | if ( recurse ) | |
1651 | T1_Done_Builder( builder ); | |
1652 | ||
1653 | Exit: | |
1654 | return error; | |
1655 | } | |
1656 | ||
1657 | ||
1658 | #endif /* !T1_CONFIG_OPTION_DISABLE_HINTER */ | |
1659 | ||
1660 | ||
1661 | LOCAL_FUNC | |
1662 | FT_Error T1_Load_Glyph( T1_GlyphSlot glyph, | |
1663 | T1_Size size, | |
1664 | FT_Int glyph_index, | |
1665 | FT_Int load_flags ) | |
1666 | { | |
1667 | FT_Error error; | |
1668 | T1_Decoder decoder; | |
1669 | T1_Face face = (T1_Face)glyph->root.face; | |
1670 | FT_Bool hinting; | |
1671 | T1_Font* type1 = &face->type1; | |
1672 | ||
1673 | ||
1674 | if ( load_flags & FT_LOAD_NO_RECURSE ) | |
1675 | load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING; | |
1676 | ||
1677 | glyph->x_scale = size->root.metrics.x_scale; | |
1678 | glyph->y_scale = size->root.metrics.y_scale; | |
1679 | ||
1680 | glyph->root.outline.n_points = 0; | |
1681 | glyph->root.outline.n_contours = 0; | |
1682 | ||
1683 | glyph->root.format = ft_glyph_format_outline; /* by default */ | |
1684 | ||
1685 | hinting = 0; | |
1686 | ||
1687 | #ifndef T1_CONFIG_OPTION_DISABLE_HINTER | |
1688 | ||
1689 | hinting = ( load_flags & ( FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING ) ) == 0; | |
1690 | ||
1691 | if ( hinting ) | |
1692 | { | |
1693 | T1_Init_Decoder( &decoder, &t1_hinter_funcs ); | |
1694 | T1_Init_Builder( &decoder.builder, face, size, glyph, | |
1695 | &gload_builder_interface ); | |
1696 | ||
1697 | error = t1_load_hinted_glyph( &decoder, glyph_index, 1 ); | |
1698 | } | |
1699 | else | |
1700 | ||
1701 | #endif /* !T1_CONFIG_OPTION_DISABLE_HINTER */ | |
1702 | ||
1703 | { | |
1704 | T1_Init_Decoder( &decoder, &gload_hinter_interface ); | |
1705 | ||
1706 | T1_Init_Builder( &decoder.builder, face, size, glyph, | |
1707 | &gload_builder_interface ); | |
1708 | ||
1709 | decoder.builder.no_recurse = ( load_flags & FT_LOAD_NO_RECURSE ) != 0; | |
1710 | ||
1711 | /* now load the unscaled outline */ | |
1712 | error = T1_Parse_CharStrings( &decoder, | |
1713 | type1->charstrings [glyph_index], | |
1714 | type1->charstrings_len[glyph_index], | |
1715 | type1->num_subrs, | |
1716 | type1->subrs, | |
1717 | type1->subrs_len ); | |
1718 | ||
1719 | /* save new glyph tables */ | |
1720 | T1_Done_Builder( &decoder.builder ); | |
1721 | } | |
1722 | ||
1723 | /* Now, set the metrics -- this is rather simple, as */ | |
1724 | /* the left side bearing is the xMin, and the top side */ | |
1725 | /* bearing the yMax */ | |
1726 | if ( !error ) | |
1727 | { | |
1728 | /* for composite glyphs, return only the left side bearing and the */ | |
1729 | /* advance width */ | |
1730 | if ( glyph->root.format == ft_glyph_format_composite ) | |
1731 | { | |
1732 | glyph->root.metrics.horiBearingX = decoder.builder.left_bearing.x; | |
1733 | glyph->root.metrics.horiAdvance = decoder.builder.advance.x; | |
1734 | } | |
1735 | else | |
1736 | { | |
1737 | FT_BBox cbox; | |
1738 | FT_Glyph_Metrics* metrics = &glyph->root.metrics; | |
1739 | ||
1740 | ||
1741 | /* apply the font matrix */ | |
1742 | FT_Outline_Transform( &glyph->root.outline, | |
1743 | &face->type1.font_matrix ); | |
1744 | ||
1745 | FT_Outline_Get_CBox( &glyph->root.outline, &cbox ); | |
1746 | ||
1747 | /* grid fit the bounding box if necessary */ | |
1748 | if ( hinting ) | |
1749 | { | |
1750 | cbox.xMin &= -64; | |
1751 | cbox.yMin &= -64; | |
1752 | cbox.xMax = ( cbox.xMax + 63 ) & -64; | |
1753 | cbox.yMax = ( cbox.yMax + 63 ) & -64; | |
1754 | } | |
1755 | ||
1756 | metrics->width = cbox.xMax - cbox.xMin; | |
1757 | metrics->height = cbox.yMax - cbox.yMin; | |
1758 | ||
1759 | metrics->horiBearingX = cbox.xMin; | |
1760 | metrics->horiBearingY = cbox.yMax; | |
1761 | ||
1762 | /* copy the _unscaled_ advance width */ | |
1763 | metrics->horiAdvance = decoder.builder.advance.x; | |
1764 | ||
1765 | /* make up vertical metrics */ | |
1766 | metrics->vertBearingX = 0; | |
1767 | metrics->vertBearingY = 0; | |
1768 | metrics->vertAdvance = 0; | |
1769 | ||
1770 | glyph->root.format = ft_glyph_format_outline; | |
1771 | ||
1772 | glyph->root.outline.flags = 0; | |
1773 | ||
1774 | if ( size->root.metrics.y_ppem < 24 ) | |
1775 | glyph->root.outline.flags |= ft_outline_high_precision; | |
1776 | ||
1777 | glyph->root.outline.flags |= ft_outline_reverse_fill; | |
1778 | ||
1779 | if ( hinting ) | |
1780 | { | |
1781 | /* adjust the advance width */ | |
1782 | /* XXX TODO: consider stem hints grid-fit */ | |
1783 | metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, | |
1784 | glyph->x_scale ); | |
1785 | } | |
1786 | else if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 ) | |
1787 | { | |
1788 | /* scale the outline and the metrics */ | |
1789 | FT_Int n; | |
1790 | FT_Outline* cur = decoder.builder.base; | |
1791 | FT_Vector* vec = cur->points; | |
1792 | FT_Fixed x_scale = glyph->x_scale; | |
1793 | FT_Fixed y_scale = glyph->y_scale; | |
1794 | ||
1795 | ||
1796 | /* First of all, scale the points */ | |
1797 | for ( n = cur->n_points; n > 0; n--, vec++ ) | |
1798 | { | |
1799 | vec->x = FT_MulFix( vec->x, x_scale ); | |
1800 | vec->y = FT_MulFix( vec->y, y_scale ); | |
1801 | } | |
1802 | ||
1803 | /* Then scale the metrics */ | |
1804 | metrics->width = FT_MulFix( metrics->width, x_scale ); | |
1805 | metrics->height = FT_MulFix( metrics->height, y_scale ); | |
1806 | ||
1807 | metrics->horiBearingX = FT_MulFix( metrics->horiBearingX, x_scale ); | |
1808 | metrics->horiBearingY = FT_MulFix( metrics->horiBearingY, y_scale ); | |
1809 | ||
1810 | metrics->vertBearingX = FT_MulFix( metrics->vertBearingX, x_scale ); | |
1811 | metrics->vertBearingY = FT_MulFix( metrics->vertBearingY, y_scale ); | |
1812 | ||
1813 | metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale ); | |
1814 | metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale ); | |
1815 | } | |
1816 | } | |
1817 | } | |
1818 | ||
1819 | return error; | |
1820 | } | |
1821 | ||
1822 | ||
1823 | /* END */ |