]>
Commit | Line | Data |
---|---|---|
cabec872 RR |
1 | /***************************************************************************/ |
2 | /* */ | |
3 | /* z1gload.c */ | |
4 | /* */ | |
5 | /* Experimental 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 "z1gload.h" | |
22 | ||
23 | #else | |
24 | ||
25 | #include <type1z/z1gload.h> | |
26 | ||
27 | #endif | |
28 | ||
29 | ||
30 | #include <freetype/internal/ftdebug.h> | |
31 | #include <freetype/internal/ftstream.h> | |
32 | #include <freetype/ftoutln.h> | |
33 | ||
34 | #include <string.h> /* for strcmp() */ | |
35 | ||
36 | ||
37 | /*************************************************************************/ | |
38 | /* */ | |
39 | /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ | |
40 | /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ | |
41 | /* messages during execution. */ | |
42 | /* */ | |
43 | #undef FT_COMPONENT | |
44 | #define FT_COMPONENT trace_z1gload | |
45 | ||
46 | ||
47 | typedef enum Z1_Operator_ | |
48 | { | |
49 | op_none = 0, | |
50 | op_endchar, | |
51 | op_hsbw, | |
52 | op_seac, | |
53 | op_sbw, | |
54 | op_closepath, | |
55 | op_hlineto, | |
56 | op_hmoveto, | |
57 | op_hvcurveto, | |
58 | op_rlineto, | |
59 | op_rmoveto, | |
60 | op_rrcurveto, | |
61 | op_vhcurveto, | |
62 | op_vlineto, | |
63 | op_vmoveto, | |
64 | op_dotsection, | |
65 | op_hstem, | |
66 | op_hstem3, | |
67 | op_vstem, | |
68 | op_vstem3, | |
69 | op_div, | |
70 | op_callothersubr, | |
71 | op_callsubr, | |
72 | op_pop, | |
73 | op_return, | |
74 | op_setcurrentpoint, | |
75 | ||
76 | op_max /* never remove this one */ | |
77 | ||
78 | } Z1_Operator; | |
79 | ||
80 | static | |
81 | const FT_Int t1_args_count[op_max] = | |
82 | { | |
83 | 0, /* none */ | |
84 | 0, /* endchar */ | |
85 | 2, /* hsbw */ | |
86 | 5, /* seac */ | |
87 | 4, /* sbw */ | |
88 | 0, /* closepath */ | |
89 | 1, /* hlineto */ | |
90 | 1, /* hmoveto */ | |
91 | 4, /* hvcurveto */ | |
92 | 2, /* rlineto */ | |
93 | 2, /* rmoveto */ | |
94 | 6, /* rrcurveto */ | |
95 | 4, /* vhcurveto */ | |
96 | 1, /* vlineto */ | |
97 | 1, /* vmoveto */ | |
98 | 0, /* dotsection */ | |
99 | 2, /* hstem */ | |
100 | 6, /* hstem3 */ | |
101 | 2, /* vstem */ | |
102 | 6, /* vstem3 */ | |
103 | 2, /* div */ | |
104 | -1, /* callothersubr */ | |
105 | 1, /* callsubr */ | |
106 | 0, /* pop */ | |
107 | 0, /* return */ | |
108 | 2 /* setcurrentpoint */ | |
109 | }; | |
110 | ||
111 | ||
112 | /*************************************************************************/ | |
113 | /*************************************************************************/ | |
114 | /*************************************************************************/ | |
115 | /********** *********/ | |
116 | /********** *********/ | |
117 | /********** GENERIC CHARSTRING PARSING *********/ | |
118 | /********** *********/ | |
119 | /********** *********/ | |
120 | /*************************************************************************/ | |
121 | /*************************************************************************/ | |
122 | /*************************************************************************/ | |
123 | ||
124 | ||
125 | /*************************************************************************/ | |
126 | /* */ | |
127 | /* <Function> */ | |
128 | /* Z1_Init_Builder */ | |
129 | /* */ | |
130 | /* <Description> */ | |
131 | /* Initializes a given glyph builder. */ | |
132 | /* */ | |
133 | /* <InOut> */ | |
134 | /* builder :: A pointer to the glyph builder to initialize. */ | |
135 | /* */ | |
136 | /* <Input> */ | |
137 | /* face :: The current face object. */ | |
138 | /* */ | |
139 | /* size :: The current size object. */ | |
140 | /* */ | |
141 | /* glyph :: The current glyph object. */ | |
142 | /* */ | |
143 | LOCAL_FUNC | |
144 | void Z1_Init_Builder( Z1_Builder* builder, | |
145 | T1_Face face, | |
146 | Z1_Size size, | |
147 | Z1_GlyphSlot glyph ) | |
148 | { | |
149 | builder->path_begun = 0; | |
150 | builder->load_points = 1; | |
151 | ||
152 | builder->face = face; | |
153 | builder->glyph = glyph; | |
154 | builder->memory = face->root.memory; | |
155 | ||
156 | if ( glyph ) | |
157 | { | |
158 | FT_GlyphLoader* loader = glyph->root.loader; | |
159 | ||
160 | ||
161 | builder->loader = loader; | |
162 | builder->current = &loader->current.outline; | |
163 | builder->base = &loader->base.outline; | |
164 | ||
165 | FT_GlyphLoader_Rewind( loader ); | |
166 | } | |
167 | ||
168 | if ( size ) | |
169 | { | |
170 | builder->scale_x = size->root.metrics.x_scale; | |
171 | builder->scale_y = size->root.metrics.y_scale; | |
172 | } | |
173 | ||
174 | builder->pos_x = 0; | |
175 | builder->pos_y = 0; | |
176 | ||
177 | builder->left_bearing.x = 0; | |
178 | builder->left_bearing.y = 0; | |
179 | builder->advance.x = 0; | |
180 | builder->advance.y = 0; | |
181 | } | |
182 | ||
183 | ||
184 | /*************************************************************************/ | |
185 | /* */ | |
186 | /* <Function> */ | |
187 | /* Z1_Done_Builder */ | |
188 | /* */ | |
189 | /* <Description> */ | |
190 | /* Finalizes a given glyph builder. Its contents can still be used */ | |
191 | /* after the call, but the function saves important information */ | |
192 | /* within the corresponding glyph slot. */ | |
193 | /* */ | |
194 | /* <Input> */ | |
195 | /* builder :: A pointer to the glyph builder to finalize. */ | |
196 | /* */ | |
197 | LOCAL_FUNC | |
198 | void Z1_Done_Builder( Z1_Builder* builder ) | |
199 | { | |
200 | Z1_GlyphSlot glyph = builder->glyph; | |
201 | ||
202 | ||
203 | if ( glyph ) | |
204 | glyph->root.outline = *builder->base; | |
205 | } | |
206 | ||
207 | ||
208 | /*************************************************************************/ | |
209 | /* */ | |
210 | /* <Function> */ | |
211 | /* Z1_Init_Decoder */ | |
212 | /* */ | |
213 | /* <Description> */ | |
214 | /* Initializes a given glyph decoder. */ | |
215 | /* */ | |
216 | /* <InOut> */ | |
217 | /* decoder :: A pointer to the glyph builder to initialize. */ | |
218 | /* */ | |
219 | LOCAL_FUNC | |
220 | void Z1_Init_Decoder( Z1_Decoder* decoder ) | |
221 | { | |
222 | decoder->top = 0; | |
223 | decoder->zone = 0; | |
224 | decoder->flex_state = 0; | |
225 | decoder->num_flex_vectors = 0; | |
226 | decoder->blend = 0; | |
227 | ||
228 | /* Clear loader */ | |
229 | MEM_Set( &decoder->builder, 0, sizeof ( decoder->builder ) ); | |
230 | } | |
231 | ||
232 | ||
233 | /* check that there is enough space for `count' more points */ | |
234 | static | |
235 | FT_Error check_points( Z1_Builder* builder, | |
236 | FT_Int count ) | |
237 | { | |
238 | return FT_GlyphLoader_Check_Points( builder->loader, count, 0 ); | |
239 | } | |
240 | ||
241 | ||
242 | /* add a new point; do not check space */ | |
243 | static | |
244 | void add_point( Z1_Builder* builder, | |
245 | FT_Pos x, | |
246 | FT_Pos y, | |
247 | FT_Byte flag ) | |
248 | { | |
249 | FT_Outline* outline = builder->current; | |
250 | ||
251 | ||
252 | if ( builder->load_points ) | |
253 | { | |
254 | FT_Vector* point = outline->points + outline->n_points; | |
255 | FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points; | |
256 | ||
257 | ||
258 | point->x = x; | |
259 | point->y = y; | |
260 | *control = flag ? FT_Curve_Tag_On : FT_Curve_Tag_Cubic; | |
261 | ||
262 | builder->last = *point; | |
263 | } | |
264 | ||
265 | outline->n_points++; | |
266 | } | |
267 | ||
268 | ||
269 | /* check space for a new on-curve point, then add it */ | |
270 | static | |
271 | FT_Error add_point1( Z1_Builder* builder, | |
272 | FT_Pos x, | |
273 | FT_Pos y ) | |
274 | { | |
275 | FT_Error error; | |
276 | ||
277 | ||
278 | error = check_points( builder, 1 ); | |
279 | if ( !error ) | |
280 | add_point( builder, x, y, 1 ); | |
281 | ||
282 | return error; | |
283 | } | |
284 | ||
285 | ||
286 | /* check space for a new contour, then add it */ | |
287 | static | |
288 | FT_Error add_contour( Z1_Builder* builder ) | |
289 | { | |
290 | FT_Outline* outline = builder->current; | |
291 | FT_Error error; | |
292 | ||
293 | ||
294 | if ( !builder->load_points ) | |
295 | { | |
296 | outline->n_contours++; | |
297 | return FT_Err_Ok; | |
298 | } | |
299 | ||
300 | /* reallocate contours array if necessary */ | |
301 | error = FT_GlyphLoader_Check_Points( builder->loader, 0, 1 ); | |
302 | if ( !error ) | |
303 | { | |
304 | if ( outline->n_contours > 0 ) | |
305 | outline->contours[outline->n_contours - 1] = outline->n_points - 1; | |
306 | ||
307 | outline->n_contours++; | |
308 | } | |
309 | ||
310 | return error; | |
311 | } | |
312 | ||
313 | ||
314 | /* if a path was begun, add its first on-curve point */ | |
315 | static | |
316 | FT_Error start_point( Z1_Builder* builder, | |
317 | FT_Pos x, | |
318 | FT_Pos y ) | |
319 | { | |
320 | /* test whether we are building a new contour */ | |
321 | if ( !builder->path_begun ) | |
322 | { | |
323 | FT_Error error; | |
324 | ||
325 | ||
326 | builder->path_begun = 1; | |
327 | error = add_contour( builder ); | |
328 | if ( error ) | |
329 | return error; | |
330 | } | |
331 | return add_point1( builder, x, y ); | |
332 | } | |
333 | ||
334 | ||
335 | /* close the current contour */ | |
336 | static | |
337 | void close_contour( Z1_Builder* builder ) | |
338 | { | |
339 | FT_Outline* outline = builder->current; | |
340 | ||
341 | ||
342 | /* XXX: we must not include the last point in the path if it */ | |
343 | /* is located on the first point */ | |
344 | if ( outline->n_points > 1 ) | |
345 | { | |
346 | FT_Int first = 0; | |
347 | FT_Vector* p1 = outline->points + first; | |
348 | FT_Vector* p2 = outline->points + outline->n_points-1; | |
349 | ||
350 | ||
351 | if ( outline->n_contours > 1 ) | |
352 | { | |
353 | first = outline->contours[outline->n_contours - 2] + 1; | |
354 | p1 = outline->points + first; | |
355 | } | |
356 | ||
357 | if ( p1->x == p2->x && p1->y == p2->y ) | |
358 | outline->n_points--; | |
359 | } | |
360 | ||
361 | if ( outline->n_contours > 0 ) | |
362 | outline->contours[outline->n_contours - 1] = outline->n_points - 1; | |
363 | } | |
364 | ||
365 | ||
366 | /*************************************************************************/ | |
367 | /* */ | |
368 | /* <Function> */ | |
369 | /* lookup_glyph_by_stdcharcode */ | |
370 | /* */ | |
371 | /* <Description> */ | |
372 | /* Looks up a given glyph by its StandardEncoding charcode. Used */ | |
373 | /* to implement the SEAC Type 1 operator. */ | |
374 | /* */ | |
375 | /* <Input> */ | |
376 | /* face :: The current face object. */ | |
377 | /* */ | |
378 | /* charcode :: The character code to look for. */ | |
379 | /* */ | |
380 | /* <Return> */ | |
381 | /* A glyph index in the font face. Returns -1 if the corresponding */ | |
382 | /* glyph wasn't found. */ | |
383 | /* */ | |
384 | static | |
385 | FT_Int lookup_glyph_by_stdcharcode( T1_Face face, | |
386 | FT_Int charcode ) | |
387 | { | |
388 | FT_Int n; | |
389 | const FT_String* glyph_name; | |
390 | PSNames_Interface* psnames = (PSNames_Interface*)face->psnames; | |
391 | ||
392 | ||
393 | /* check range of standard char code */ | |
394 | if ( charcode < 0 || charcode > 255 ) | |
395 | return -1; | |
396 | ||
397 | glyph_name = psnames->adobe_std_strings( | |
398 | psnames->adobe_std_encoding[charcode]); | |
399 | ||
400 | for ( n = 0; n < face->type1.num_glyphs; n++ ) | |
401 | { | |
402 | FT_String* name = (FT_String*)face->type1.glyph_names[n]; | |
403 | ||
404 | ||
405 | if ( name && strcmp( name,glyph_name ) == 0 ) | |
406 | return n; | |
407 | } | |
408 | ||
409 | return -1; | |
410 | } | |
411 | ||
412 | ||
413 | /*************************************************************************/ | |
414 | /* */ | |
415 | /* <Function> */ | |
416 | /* t1operator_seac */ | |
417 | /* */ | |
418 | /* <Description> */ | |
419 | /* Implements the `seac' Type 1 operator for a Type 1 decoder. */ | |
420 | /* */ | |
421 | /* <Input> */ | |
422 | /* decoder :: The current CID decoder. */ | |
423 | /* */ | |
424 | /* asb :: The accent's side bearing. */ | |
425 | /* */ | |
426 | /* adx :: The horizontal offset of the accent. */ | |
427 | /* */ | |
428 | /* ady :: The vertical offset of the accent. */ | |
429 | /* */ | |
430 | /* bchar :: The base character's StandardEncoding charcode. */ | |
431 | /* */ | |
432 | /* achar :: The accent character's StandardEncoding charcode. */ | |
433 | /* */ | |
434 | /* <Return> */ | |
435 | /* FreeType error code. 0 means success. */ | |
436 | /* */ | |
437 | static | |
438 | FT_Error t1operator_seac( Z1_Decoder* decoder, | |
439 | FT_Pos asb, | |
440 | FT_Pos adx, | |
441 | FT_Pos ady, | |
442 | FT_Int bchar, | |
443 | FT_Int achar ) | |
444 | { | |
445 | FT_Error error; | |
446 | FT_Int bchar_index, achar_index, n_base_points; | |
447 | FT_Outline* base = decoder->builder.base; | |
448 | FT_Vector left_bearing, advance; | |
449 | T1_Face face = decoder->builder.face; | |
450 | T1_Font* type1 = &face->type1; | |
451 | ||
452 | ||
453 | bchar_index = lookup_glyph_by_stdcharcode( face, bchar ); | |
454 | achar_index = lookup_glyph_by_stdcharcode( face, achar ); | |
455 | ||
456 | if ( bchar_index < 0 || achar_index < 0 ) | |
457 | { | |
458 | FT_ERROR(( "t1operator_seac:" )); | |
459 | FT_ERROR(( " invalid seac character code arguments\n" )); | |
460 | return T1_Err_Syntax_Error; | |
461 | } | |
462 | ||
463 | /* if we are trying to load a composite glyph, do not load the */ | |
464 | /* accent character and return the array of subglyphs. */ | |
465 | if ( decoder->builder.no_recurse ) | |
466 | { | |
467 | FT_GlyphSlot glyph = (FT_GlyphSlot)decoder->builder.glyph; | |
468 | FT_GlyphLoader* loader = glyph->loader; | |
469 | FT_SubGlyph* subg; | |
470 | ||
471 | ||
472 | /* reallocate subglyph array if necessary */ | |
473 | error = FT_GlyphLoader_Check_Subglyphs( loader, 2 ); | |
474 | if ( error ) | |
475 | goto Exit; | |
476 | ||
477 | subg = loader->current.subglyphs; | |
478 | ||
479 | /* subglyph 0 = base character */ | |
480 | subg->index = bchar_index; | |
481 | subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES | | |
482 | FT_SUBGLYPH_FLAG_USE_MY_METRICS; | |
483 | subg->arg1 = 0; | |
484 | subg->arg2 = 0; | |
485 | subg++; | |
486 | ||
487 | /* subglyph 1 = accent character */ | |
488 | subg->index = achar_index; | |
489 | subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES; | |
490 | subg->arg1 = adx - asb; | |
491 | subg->arg2 = ady; | |
492 | ||
493 | /* set up remaining glyph fields */ | |
494 | glyph->num_subglyphs = 2; | |
495 | glyph->subglyphs = loader->base.subglyphs; | |
496 | glyph->format = ft_glyph_format_composite; | |
497 | ||
498 | loader->current.num_subglyphs = 2; | |
499 | } | |
500 | ||
501 | /* First load `bchar' in builder */ | |
502 | /* now load the unscaled outline */ | |
503 | ||
504 | FT_GlyphLoader_Prepare( decoder->builder.loader ); /* prepare loader */ | |
505 | ||
506 | error = Z1_Parse_CharStrings( decoder, | |
507 | type1->charstrings [bchar_index], | |
508 | type1->charstrings_len[bchar_index], | |
509 | type1->num_subrs, | |
510 | type1->subrs, | |
511 | type1->subrs_len ); | |
512 | if ( error ) | |
513 | goto Exit; | |
514 | ||
515 | n_base_points = base->n_points; | |
516 | ||
517 | /* save the left bearing and width of the base character */ | |
518 | /* as they will be erased by the next load. */ | |
519 | ||
520 | left_bearing = decoder->builder.left_bearing; | |
521 | advance = decoder->builder.advance; | |
522 | ||
523 | decoder->builder.left_bearing.x = 0; | |
524 | decoder->builder.left_bearing.y = 0; | |
525 | ||
526 | /* Now load `achar' on top of */ | |
527 | /* the base outline */ | |
528 | error = Z1_Parse_CharStrings( decoder, | |
529 | type1->charstrings [achar_index], | |
530 | type1->charstrings_len[achar_index], | |
531 | type1->num_subrs, | |
532 | type1->subrs, | |
533 | type1->subrs_len ); | |
534 | if ( error ) | |
535 | return error; | |
536 | ||
537 | /* restore the left side bearing and */ | |
538 | /* advance width of the base character */ | |
539 | ||
540 | decoder->builder.left_bearing = left_bearing; | |
541 | decoder->builder.advance = advance; | |
542 | ||
543 | /* Finally, move the accent */ | |
544 | if ( decoder->builder.load_points ) | |
545 | { | |
546 | FT_Outline dummy; | |
547 | ||
548 | ||
549 | dummy.n_points = base->n_points - n_base_points; | |
550 | dummy.points = base->points + n_base_points; | |
551 | FT_Outline_Translate( &dummy, adx - asb, ady ); | |
552 | } | |
553 | ||
554 | Exit: | |
555 | return error; | |
556 | } | |
557 | ||
558 | ||
559 | #define USE_ARGS( n ) do \ | |
560 | { \ | |
561 | top -= n; \ | |
562 | if ( top < decoder->stack ) \ | |
563 | goto Stack_Underflow; \ | |
564 | } while ( 0 ) | |
565 | ||
566 | ||
567 | /*************************************************************************/ | |
568 | /* */ | |
569 | /* <Function> */ | |
570 | /* Z1_Parse_CharStrings */ | |
571 | /* */ | |
572 | /* <Description> */ | |
573 | /* Parses a given Type 1 charstrings program. */ | |
574 | /* */ | |
575 | /* <Input> */ | |
576 | /* decoder :: The current Type 1 decoder. */ | |
577 | /* */ | |
578 | /* charstring_base :: The base address of the charstring stream. */ | |
579 | /* */ | |
580 | /* charstring_len :: The length in bytes of the charstring stream. */ | |
581 | /* */ | |
582 | /* num_subrs :: The number of sub-routines. */ | |
583 | /* */ | |
584 | /* subrs_base :: An array of sub-routines addresses. */ | |
585 | /* */ | |
586 | /* subrs_len :: An array of sub-routines lengths. */ | |
587 | /* */ | |
588 | /* <Return> */ | |
589 | /* Free error code. 0 means success. */ | |
590 | /* */ | |
591 | LOCAL_FUNC | |
592 | FT_Error Z1_Parse_CharStrings( Z1_Decoder* decoder, | |
593 | FT_Byte* charstring_base, | |
594 | FT_Int charstring_len, | |
595 | FT_Int num_subrs, | |
596 | FT_Byte** subrs_base, | |
597 | FT_Int* subrs_len ) | |
598 | { | |
599 | FT_Error error; | |
600 | Z1_Decoder_Zone* zone; | |
601 | FT_Byte* ip; | |
602 | FT_Byte* limit; | |
603 | Z1_Builder* builder = &decoder->builder; | |
604 | FT_Outline* outline; | |
605 | FT_Pos x, y; | |
606 | ||
607 | ||
608 | /* First of all, initialize the decoder */ | |
609 | decoder->top = decoder->stack; | |
610 | decoder->zone = decoder->zones; | |
611 | zone = decoder->zones; | |
612 | ||
613 | builder->path_begun = 0; | |
614 | ||
615 | zone->base = charstring_base; | |
616 | limit = zone->limit = charstring_base + charstring_len; | |
617 | ip = zone->cursor = zone->base; | |
618 | ||
619 | error = T1_Err_Ok; | |
620 | outline = builder->current; | |
621 | ||
622 | x = builder->pos_x; | |
623 | y = builder->pos_y; | |
624 | ||
625 | /* now, execute loop */ | |
626 | while ( ip < limit ) | |
627 | { | |
628 | FT_Int* top = decoder->top; | |
629 | Z1_Operator op = op_none; | |
630 | FT_Long value = 0; | |
631 | ||
632 | ||
633 | /*********************************************************************/ | |
634 | /* */ | |
635 | /* Decode operator or operand */ | |
636 | /* */ | |
637 | /* */ | |
638 | ||
639 | /* first of all, decompress operator or value */ | |
640 | switch ( *ip++ ) | |
641 | { | |
642 | case 1: | |
643 | op = op_hstem; | |
644 | break; | |
645 | ||
646 | case 3: | |
647 | op = op_vstem; | |
648 | break; | |
649 | case 4: | |
650 | op = op_vmoveto; | |
651 | break; | |
652 | case 5: | |
653 | op = op_rlineto; | |
654 | break; | |
655 | case 6: | |
656 | op = op_hlineto; | |
657 | break; | |
658 | case 7: | |
659 | op = op_vlineto; | |
660 | break; | |
661 | case 8: | |
662 | op = op_rrcurveto; | |
663 | break; | |
664 | case 9: | |
665 | op = op_closepath; | |
666 | break; | |
667 | case 10: | |
668 | op = op_callsubr; | |
669 | break; | |
670 | case 11: | |
671 | op = op_return; | |
672 | break; | |
673 | ||
674 | case 13: | |
675 | op = op_hsbw; | |
676 | break; | |
677 | case 14: | |
678 | op = op_endchar; | |
679 | break; | |
680 | ||
681 | case 21: | |
682 | op = op_rmoveto; | |
683 | break; | |
684 | case 22: | |
685 | op = op_hmoveto; | |
686 | break; | |
687 | ||
688 | case 30: | |
689 | op = op_vhcurveto; | |
690 | break; | |
691 | case 31: | |
692 | op = op_hvcurveto; | |
693 | break; | |
694 | ||
695 | case 12: | |
696 | if ( ip > limit ) | |
697 | { | |
698 | FT_ERROR(( "Z1_Parse_CharStrings: invalid escape (12+EOF)\n" )); | |
699 | goto Syntax_Error; | |
700 | } | |
701 | ||
702 | switch ( *ip++ ) | |
703 | { | |
704 | case 0: | |
705 | op = op_dotsection; | |
706 | break; | |
707 | case 1: | |
708 | op = op_vstem3; | |
709 | break; | |
710 | case 2: | |
711 | op = op_hstem3; | |
712 | break; | |
713 | case 6: | |
714 | op = op_seac; | |
715 | break; | |
716 | case 7: | |
717 | op = op_sbw; | |
718 | break; | |
719 | case 12: | |
720 | op = op_div; | |
721 | break; | |
722 | case 16: | |
723 | op = op_callothersubr; | |
724 | break; | |
725 | case 17: | |
726 | op = op_pop; | |
727 | break; | |
728 | case 33: | |
729 | op = op_setcurrentpoint; | |
730 | break; | |
731 | ||
732 | default: | |
733 | FT_ERROR(( "Z1_Parse_CharStrings: invalid escape (12+%d)\n", | |
734 | ip[-1] )); | |
735 | goto Syntax_Error; | |
736 | } | |
737 | break; | |
738 | ||
739 | case 255: /* four bytes integer */ | |
740 | if ( ip + 4 > limit ) | |
741 | { | |
742 | FT_ERROR(( "Z1_Parse_CharStrings: unexpected EOF in integer\n" )); | |
743 | goto Syntax_Error; | |
744 | } | |
745 | ||
746 | value = ( (FT_Long)ip[0] << 24 ) | | |
747 | ( (FT_Long)ip[1] << 16 ) | | |
748 | ( (FT_Long)ip[2] << 8 ) | | |
749 | ip[3]; | |
750 | ip += 4; | |
751 | break; | |
752 | ||
753 | default: | |
754 | if ( ip[-1] >= 32 ) | |
755 | { | |
756 | if ( ip[-1] < 247 ) | |
757 | value = (FT_Long)ip[-1] - 139; | |
758 | else | |
759 | { | |
760 | if ( ++ip > limit ) | |
761 | { | |
762 | FT_ERROR(( "Z1_Parse_CharStrings:" )); | |
763 | FT_ERROR(( " unexpected EOF in integer\n" )); | |
764 | goto Syntax_Error; | |
765 | } | |
766 | ||
767 | if ( ip[-2] < 251 ) | |
768 | value = ( (FT_Long)( ip[-2] - 247 ) << 8 ) + ip[-1] + 108; | |
769 | else | |
770 | value = -( ( ( (FT_Long)ip[-2] - 251 ) << 8 ) + ip[-1] + 108 ); | |
771 | } | |
772 | } | |
773 | else | |
774 | { | |
775 | FT_ERROR(( "Z1_Parse_CharStrings: invalid byte (%d)\n", | |
776 | ip[-1] )); | |
777 | goto Syntax_Error; | |
778 | } | |
779 | } | |
780 | ||
781 | /*********************************************************************/ | |
782 | /* */ | |
783 | /* Push value on stack, or process operator */ | |
784 | /* */ | |
785 | /* */ | |
786 | if ( op == op_none ) | |
787 | { | |
788 | if ( top - decoder->stack >= T1_MAX_CHARSTRINGS_OPERANDS ) | |
789 | { | |
790 | FT_ERROR(( "Z1_Parse_CharStrings: stack overflow!\n" )); | |
791 | goto Syntax_Error; | |
792 | } | |
793 | ||
794 | FT_TRACE4(( " %ld", value )); | |
795 | ||
796 | *top++ = value; | |
797 | decoder->top = top; | |
798 | } | |
799 | else if ( op == op_callothersubr ) /* callothersubr */ | |
800 | { | |
801 | FT_TRACE4(( " callothersubr" )); | |
802 | ||
803 | if ( top - decoder->stack < 2 ) | |
804 | goto Stack_Underflow; | |
805 | ||
806 | top -= 2; | |
807 | switch ( top[1] ) | |
808 | { | |
809 | case 1: /* start flex feature */ | |
810 | if ( top[0] != 0 ) | |
811 | goto Unexpected_OtherSubr; | |
812 | ||
813 | decoder->flex_state = 1; | |
814 | decoder->num_flex_vectors = 0; | |
815 | if ( start_point( builder, x, y ) || | |
816 | check_points( builder, 6 ) ) | |
817 | goto Memory_Error; | |
818 | break; | |
819 | ||
820 | case 2: /* add flex vectors */ | |
821 | { | |
822 | FT_Int index; | |
823 | ||
824 | if ( top[0] != 0 ) | |
825 | goto Unexpected_OtherSubr; | |
826 | ||
827 | /* note that we should not add a point for index 0; */ | |
828 | /* this will move our current position to the flex */ | |
829 | /* point without adding any point to the outline */ | |
830 | index = decoder->num_flex_vectors++; | |
831 | if ( index > 0 && index < 7 ) | |
832 | add_point( builder, | |
833 | x, | |
834 | y, | |
835 | (FT_Byte)( index == 3 || index == 6 ) ); | |
836 | } | |
837 | break; | |
838 | ||
839 | case 0: /* end flex feature */ | |
840 | if ( top[0] != 3 ) | |
841 | goto Unexpected_OtherSubr; | |
842 | ||
843 | if ( decoder->flex_state == 0 || | |
844 | decoder->num_flex_vectors != 7 ) | |
845 | { | |
846 | FT_ERROR(( "Z1_Parse_CharStrings: unexpected flex end\n" )); | |
847 | goto Syntax_Error; | |
848 | } | |
849 | ||
850 | /* now consume the remaining `pop pop setcurpoint' */ | |
851 | if ( ip + 6 > limit || | |
852 | ip[0] != 12 || ip[1] != 17 || /* pop */ | |
853 | ip[2] != 12 || ip[3] != 17 || /* pop */ | |
854 | ip[4] != 12 || ip[5] != 33 ) /* setcurpoint */ | |
855 | { | |
856 | FT_ERROR(( "Z1_Parse_CharStrings: invalid flex charstring\n" )); | |
857 | goto Syntax_Error; | |
858 | } | |
859 | ||
860 | ip += 6; | |
861 | decoder->flex_state = 0; | |
862 | break; | |
863 | ||
864 | case 3: /* change hints */ | |
865 | if ( top[0] != 1 ) | |
866 | goto Unexpected_OtherSubr; | |
867 | ||
868 | /* eat the following `pop' */ | |
869 | if ( ip + 2 > limit ) | |
870 | { | |
871 | FT_ERROR(( "Z1_Parse_CharStrings: invalid escape (12+%d)\n", | |
872 | ip[-1] )); | |
873 | goto Syntax_Error; | |
874 | } | |
875 | ||
876 | if ( ip[0] != 12 || ip[1] != 17 ) | |
877 | { | |
878 | FT_ERROR(( "Z1_Parse_CharStrings:" )); | |
879 | FT_ERROR(( " `pop' expected, found (%d %d)\n", | |
880 | ip[0], ip[1] )); | |
881 | goto Syntax_Error; | |
882 | } | |
883 | ip += 2; | |
884 | break; | |
885 | ||
886 | case 12: | |
887 | case 13: | |
888 | /* counter control hints, clear stack */ | |
889 | top = decoder->stack; | |
890 | break; | |
891 | ||
892 | case 14: | |
893 | case 15: | |
894 | case 16: | |
895 | case 17: | |
896 | case 18: /* multiple masters */ | |
897 | { | |
898 | T1_Blend* blend = decoder->blend; | |
899 | FT_UInt num_points, nn, mm; | |
900 | FT_Int* delta; | |
901 | FT_Int* values; | |
902 | ||
903 | ||
904 | if ( !blend ) | |
905 | { | |
906 | FT_ERROR(( "Z1_Parse_CharStrings:" )); | |
907 | FT_ERROR(( " unexpected multiple masters operator!\n" )); | |
908 | goto Syntax_Error; | |
909 | } | |
910 | ||
911 | num_points = top[1] - 13 + ( top[1] == 18 ); | |
912 | if ( top[0] != (FT_Int)( num_points * blend->num_designs ) ) | |
913 | { | |
914 | FT_ERROR(( "Z1_Parse_CharStrings:" )); | |
915 | FT_ERROR(( " incorrect number of mm arguments\n" )); | |
916 | goto Syntax_Error; | |
917 | } | |
918 | ||
919 | top -= blend->num_designs*num_points; | |
920 | if ( top < decoder->stack ) | |
921 | goto Stack_Underflow; | |
922 | ||
923 | /* we want to compute: */ | |
924 | /* */ | |
925 | /* a0*w0 + a1*w1 + ... + ak*wk */ | |
926 | /* */ | |
927 | /* but we only have the a0, a1-a0, a2-a0, .. ak-a0 */ | |
928 | /* however, given that w0 + w1 + ... + wk == 1, we can */ | |
929 | /* rewrite it easily as: */ | |
930 | /* */ | |
931 | /* a0 + (a1-a0)*w1 + (a2-a0)*w2 + .. + (ak-a0)*wk */ | |
932 | /* */ | |
933 | /* where k == num_designs-1 */ | |
934 | /* */ | |
935 | /* I guess that's why it's written in this `compact' */ | |
936 | /* form. */ | |
937 | /* */ | |
938 | delta = top + num_points; | |
939 | values = top; | |
940 | for ( nn = 0; nn < num_points; nn++ ) | |
941 | { | |
942 | FT_Int x = values[0]; | |
943 | ||
944 | ||
945 | for ( mm = 1; mm < blend->num_designs; mm++ ) | |
946 | x += FT_MulFix( *delta++, blend->weight_vector[mm] ); | |
947 | ||
948 | *values++ = x; | |
949 | } | |
950 | /* note that `top' will be incremented later by calls to `pop' */ | |
951 | break; | |
952 | } | |
953 | ||
954 | default: | |
955 | Unexpected_OtherSubr: | |
956 | FT_ERROR(( "Z1_Parse_CharStrings: invalid othersubr [%d %d]!\n", | |
957 | top[0], top[1] )); | |
958 | goto Syntax_Error; | |
959 | } | |
960 | decoder->top = top; | |
961 | } | |
962 | else /* general operator */ | |
963 | { | |
964 | FT_Int num_args = t1_args_count[op]; | |
965 | ||
966 | ||
967 | if ( top - decoder->stack < num_args ) | |
968 | goto Stack_Underflow; | |
969 | ||
970 | top -= num_args; | |
971 | ||
972 | switch ( op ) | |
973 | { | |
974 | case op_endchar: | |
975 | FT_TRACE4(( " endchar" )); | |
976 | ||
977 | close_contour( builder ); | |
978 | ||
979 | /* add current outline to the glyph slot */ | |
980 | FT_GlyphLoader_Add( builder->loader ); | |
981 | ||
982 | /* return now! */ | |
983 | FT_TRACE4(( "\n\n" )); | |
984 | return T1_Err_Ok; | |
985 | ||
986 | case op_hsbw: | |
987 | FT_TRACE4(( " hsbw" )); | |
988 | ||
989 | builder->left_bearing.x += top[0]; | |
990 | builder->advance.x = top[1]; | |
991 | builder->advance.y = 0; | |
992 | ||
993 | builder->last.x = x = top[0]; | |
994 | builder->last.y = y = 0; | |
995 | ||
996 | /* the `metrics_only' indicates that we only want to compute */ | |
997 | /* the glyph's metrics (lsb + advance width), not load the */ | |
998 | /* rest of it; so exit immediately */ | |
999 | if ( builder->metrics_only ) | |
1000 | return T1_Err_Ok; | |
1001 | ||
1002 | break; | |
1003 | ||
1004 | case op_seac: | |
1005 | /* return immediately after the processing */ | |
1006 | return t1operator_seac( decoder, top[0], top[1], | |
1007 | top[2], top[3], top[4] ); | |
1008 | ||
1009 | case op_sbw: | |
1010 | FT_TRACE4(( " sbw" )); | |
1011 | ||
1012 | builder->left_bearing.x += top[0]; | |
1013 | builder->left_bearing.y += top[1]; | |
1014 | builder->advance.x = top[2]; | |
1015 | builder->advance.y = top[3]; | |
1016 | ||
1017 | builder->last.x = x = top[0]; | |
1018 | builder->last.y = y = top[1]; | |
1019 | ||
1020 | /* the `metrics_only' indicates that we only want to compute */ | |
1021 | /* the glyph's metrics (lsb + advance width), not load the */ | |
1022 | /* rest of it; so exit immediately */ | |
1023 | if ( builder->metrics_only ) | |
1024 | return T1_Err_Ok; | |
1025 | ||
1026 | break; | |
1027 | ||
1028 | case op_closepath: | |
1029 | FT_TRACE4(( " closepath" )); | |
1030 | ||
1031 | close_contour( builder ); | |
1032 | builder->path_begun = 0; | |
1033 | break; | |
1034 | ||
1035 | case op_hlineto: | |
1036 | FT_TRACE4(( " hlineto" )); | |
1037 | ||
1038 | if ( start_point( builder, x, y ) ) | |
1039 | goto Memory_Error; | |
1040 | ||
1041 | x += top[0]; | |
1042 | goto Add_Line; | |
1043 | ||
1044 | case op_hmoveto: | |
1045 | FT_TRACE4(( " hmoveto" )); | |
1046 | ||
1047 | x += top[0]; | |
1048 | break; | |
1049 | ||
1050 | case op_hvcurveto: | |
1051 | FT_TRACE4(( " hvcurveto" )); | |
1052 | ||
1053 | if ( start_point( builder, x, y ) || | |
1054 | check_points( builder, 3 ) ) | |
1055 | goto Memory_Error; | |
1056 | ||
1057 | x += top[0]; | |
1058 | add_point( builder, x, y, 0 ); | |
1059 | x += top[1]; | |
1060 | y += top[2]; | |
1061 | add_point( builder, x, y, 0 ); | |
1062 | y += top[3]; | |
1063 | add_point( builder, x, y, 1 ); | |
1064 | break; | |
1065 | ||
1066 | case op_rlineto: | |
1067 | FT_TRACE4(( " rlineto" )); | |
1068 | ||
1069 | if ( start_point( builder, x, y ) ) | |
1070 | goto Memory_Error; | |
1071 | ||
1072 | x += top[0]; | |
1073 | y += top[1]; | |
1074 | ||
1075 | Add_Line: | |
1076 | if ( add_point1( builder, x, y ) ) | |
1077 | goto Memory_Error; | |
1078 | break; | |
1079 | ||
1080 | case op_rmoveto: | |
1081 | FT_TRACE4(( " rmoveto" )); | |
1082 | ||
1083 | x += top[0]; | |
1084 | y += top[1]; | |
1085 | break; | |
1086 | ||
1087 | case op_rrcurveto: | |
1088 | FT_TRACE4(( " rcurveto" )); | |
1089 | ||
1090 | if ( start_point( builder, x, y ) || | |
1091 | check_points( builder, 3 ) ) | |
1092 | goto Memory_Error; | |
1093 | ||
1094 | x += top[0]; | |
1095 | y += top[1]; | |
1096 | add_point( builder, x, y, 0 ); | |
1097 | ||
1098 | x += top[2]; | |
1099 | y += top[3]; | |
1100 | add_point( builder, x, y, 0 ); | |
1101 | ||
1102 | x += top[4]; | |
1103 | y += top[5]; | |
1104 | add_point( builder, x, y, 1 ); | |
1105 | break; | |
1106 | ||
1107 | case op_vhcurveto: | |
1108 | FT_TRACE4(( " vhcurveto" )); | |
1109 | ||
1110 | if ( start_point( builder, x, y ) || | |
1111 | check_points( builder, 3 ) ) | |
1112 | goto Memory_Error; | |
1113 | ||
1114 | y += top[0]; | |
1115 | add_point( builder, x, y, 0 ); | |
1116 | x += top[1]; | |
1117 | y += top[2]; | |
1118 | add_point( builder, x, y, 0 ); | |
1119 | x += top[3]; | |
1120 | add_point( builder, x, y, 1 ); | |
1121 | break; | |
1122 | ||
1123 | case op_vlineto: | |
1124 | FT_TRACE4(( " vlineto" )); | |
1125 | ||
1126 | if ( start_point( builder, x, y ) ) | |
1127 | goto Memory_Error; | |
1128 | ||
1129 | y += top[0]; | |
1130 | goto Add_Line; | |
1131 | ||
1132 | case op_vmoveto: | |
1133 | FT_TRACE4(( " vmoveto" )); | |
1134 | ||
1135 | y += top[0]; | |
1136 | break; | |
1137 | ||
1138 | case op_div: | |
1139 | FT_TRACE4(( " div" )); | |
1140 | ||
1141 | if ( top[1] ) | |
1142 | { | |
1143 | *top = top[0] / top[1]; | |
1144 | ++top; | |
1145 | } | |
1146 | else | |
1147 | { | |
1148 | FT_ERROR(( "Z1_Parse_CharStrings: division by 0\n" )); | |
1149 | goto Syntax_Error; | |
1150 | } | |
1151 | break; | |
1152 | ||
1153 | case op_callsubr: | |
1154 | { | |
1155 | FT_Int index; | |
1156 | ||
1157 | ||
1158 | FT_TRACE4(( " callsubr" )); | |
1159 | ||
1160 | index = top[0]; | |
1161 | if ( index < 0 || index >= num_subrs ) | |
1162 | { | |
1163 | FT_ERROR(( "Z1_Parse_CharStrings: invalid subrs index\n" )); | |
1164 | goto Syntax_Error; | |
1165 | } | |
1166 | ||
1167 | if ( zone - decoder->zones >= T1_MAX_SUBRS_CALLS ) | |
1168 | { | |
1169 | FT_ERROR(( "Z1_Parse_CharStrings: too many nested subrs\n" )); | |
1170 | goto Syntax_Error; | |
1171 | } | |
1172 | ||
1173 | zone->cursor = ip; /* save current instruction pointer */ | |
1174 | ||
1175 | zone++; | |
1176 | zone->base = subrs_base[index]; | |
1177 | zone->limit = zone->base + subrs_len[index]; | |
1178 | zone->cursor = zone->base; | |
1179 | ||
1180 | if ( !zone->base ) | |
1181 | { | |
1182 | FT_ERROR(( "Z1_Parse_CharStrings: invoking empty subrs!\n" )); | |
1183 | goto Syntax_Error; | |
1184 | } | |
1185 | ||
1186 | decoder->zone = zone; | |
1187 | ip = zone->base; | |
1188 | limit = zone->limit; | |
1189 | break; | |
1190 | } | |
1191 | ||
1192 | case op_pop: | |
1193 | FT_TRACE4(( " pop" )); | |
1194 | ||
1195 | /* theorically, the arguments are already on the stack */ | |
1196 | top++; | |
1197 | break; | |
1198 | ||
1199 | case op_return: | |
1200 | FT_TRACE4(( " return" )); | |
1201 | ||
1202 | if ( zone <= decoder->zones ) | |
1203 | { | |
1204 | FT_ERROR(( "Z1_Parse_CharStrings: unexpected return\n" )); | |
1205 | goto Syntax_Error; | |
1206 | } | |
1207 | ||
1208 | zone--; | |
1209 | ip = zone->cursor; | |
1210 | limit = zone->limit; | |
1211 | decoder->zone = zone; | |
1212 | break; | |
1213 | ||
1214 | case op_dotsection: | |
1215 | FT_TRACE4(( " dotsection" )); | |
1216 | ||
1217 | break; | |
1218 | ||
1219 | case op_hstem: | |
1220 | FT_TRACE4(( " hstem" )); | |
1221 | ||
1222 | break; | |
1223 | ||
1224 | case op_hstem3: | |
1225 | FT_TRACE4(( " hstem3" )); | |
1226 | ||
1227 | break; | |
1228 | ||
1229 | case op_vstem: | |
1230 | FT_TRACE4(( " vstem" )); | |
1231 | ||
1232 | break; | |
1233 | ||
1234 | case op_vstem3: | |
1235 | FT_TRACE4(( " vstem3" )); | |
1236 | ||
1237 | break; | |
1238 | ||
1239 | case op_setcurrentpoint: | |
1240 | FT_TRACE4(( " setcurrentpoint" )); | |
1241 | ||
1242 | FT_ERROR(( "Z1_Parse_CharStrings:" )); | |
1243 | FT_ERROR(( " unexpected `setcurrentpoint'\n" )); | |
1244 | goto Syntax_Error; | |
1245 | ||
1246 | default: | |
1247 | FT_ERROR(( "Z1_Parse_CharStrings: unhandled opcode %d\n", op )); | |
1248 | goto Syntax_Error; | |
1249 | } | |
1250 | ||
1251 | decoder->top = top; | |
1252 | ||
1253 | } /* general operator processing */ | |
1254 | ||
1255 | } /* while ip < limit */ | |
1256 | ||
1257 | FT_TRACE4(( "..end..\n\n" )); | |
1258 | return error; | |
1259 | ||
1260 | Syntax_Error: | |
1261 | return T1_Err_Syntax_Error; | |
1262 | ||
1263 | Stack_Underflow: | |
1264 | return T1_Err_Stack_Underflow; | |
1265 | ||
1266 | Memory_Error: | |
1267 | return builder->error; | |
1268 | } | |
1269 | ||
1270 | ||
1271 | /*************************************************************************/ | |
1272 | /*************************************************************************/ | |
1273 | /*************************************************************************/ | |
1274 | /********** *********/ | |
1275 | /********** COMPUTE THE MAXIMUM ADVANCE WIDTH *********/ | |
1276 | /********** *********/ | |
1277 | /********** The following code is in charge of computing *********/ | |
1278 | /********** the maximum advance width of the font. It *********/ | |
1279 | /********** quickly processes each glyph charstring to *********/ | |
1280 | /********** extract the value from either a `sbw' or `seac' *********/ | |
1281 | /********** operator. *********/ | |
1282 | /********** *********/ | |
1283 | /*************************************************************************/ | |
1284 | /*************************************************************************/ | |
1285 | /*************************************************************************/ | |
1286 | ||
1287 | ||
1288 | LOCAL_FUNC | |
1289 | FT_Error Z1_Compute_Max_Advance( T1_Face face, | |
1290 | FT_Int* max_advance ) | |
1291 | { | |
1292 | FT_Error error; | |
1293 | Z1_Decoder decoder; | |
1294 | FT_Int glyph_index; | |
1295 | T1_Font* type1 = &face->type1; | |
1296 | ||
1297 | ||
1298 | *max_advance = 0; | |
1299 | ||
1300 | /* Initialize load decoder */ | |
1301 | Z1_Init_Decoder( &decoder ); | |
1302 | Z1_Init_Builder( &decoder.builder, face, 0, 0 ); | |
1303 | ||
1304 | decoder.blend = face->blend; | |
1305 | decoder.builder.metrics_only = 1; | |
1306 | decoder.builder.load_points = 0; | |
1307 | ||
1308 | /* for each glyph, parse the glyph charstring and extract */ | |
1309 | /* the advance width */ | |
1310 | for ( glyph_index = 0; glyph_index < type1->num_glyphs; glyph_index++ ) | |
1311 | { | |
1312 | /* now get load the unscaled outline */ | |
1313 | error = Z1_Parse_CharStrings( &decoder, | |
1314 | type1->charstrings [glyph_index], | |
1315 | type1->charstrings_len[glyph_index], | |
1316 | type1->num_subrs, | |
1317 | type1->subrs, | |
1318 | type1->subrs_len ); | |
1319 | /* ignore the error if one occured - skip to next glyph */ | |
1320 | } | |
1321 | ||
1322 | *max_advance = decoder.builder.advance.x; | |
1323 | return T1_Err_Ok; | |
1324 | } | |
1325 | ||
1326 | ||
1327 | /*************************************************************************/ | |
1328 | /*************************************************************************/ | |
1329 | /*************************************************************************/ | |
1330 | /********** *********/ | |
1331 | /********** UNHINTED GLYPH LOADER *********/ | |
1332 | /********** *********/ | |
1333 | /********** The following code is in charge of loading a *********/ | |
1334 | /********** single outline. It completely ignores hinting *********/ | |
1335 | /********** and is used when FT_LOAD_NO_HINTING is set. *********/ | |
1336 | /********** *********/ | |
1337 | /********** The Type 1 hinter is located in `t1hint.c' *********/ | |
1338 | /********** *********/ | |
1339 | /*************************************************************************/ | |
1340 | /*************************************************************************/ | |
1341 | /*************************************************************************/ | |
1342 | ||
1343 | ||
1344 | LOCAL_FUNC | |
1345 | FT_Error Z1_Load_Glyph( Z1_GlyphSlot glyph, | |
1346 | Z1_Size size, | |
1347 | FT_Int glyph_index, | |
1348 | FT_Int load_flags ) | |
1349 | { | |
1350 | FT_Error error; | |
1351 | Z1_Decoder decoder; | |
1352 | T1_Face face = (T1_Face)glyph->root.face; | |
1353 | FT_Bool hinting; | |
1354 | T1_Font* type1 = &face->type1; | |
1355 | ||
1356 | ||
1357 | if ( load_flags & FT_LOAD_NO_RECURSE ) | |
1358 | load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING; | |
1359 | ||
1360 | glyph->x_scale = size->root.metrics.x_scale; | |
1361 | glyph->y_scale = size->root.metrics.y_scale; | |
1362 | ||
1363 | glyph->root.outline.n_points = 0; | |
1364 | glyph->root.outline.n_contours = 0; | |
1365 | ||
1366 | hinting = ( load_flags & FT_LOAD_NO_SCALE ) == 0 && | |
1367 | ( load_flags & FT_LOAD_NO_HINTING ) == 0; | |
1368 | ||
1369 | glyph->root.format = ft_glyph_format_outline; | |
1370 | ||
1371 | Z1_Init_Decoder( &decoder ); | |
1372 | Z1_Init_Builder( &decoder.builder, face, size, glyph ); | |
1373 | ||
1374 | decoder.blend = ((T1_Face)glyph->root.face)->blend; | |
1375 | decoder.builder.no_recurse = ( load_flags & FT_LOAD_NO_RECURSE ) != 0; | |
1376 | ||
1377 | /* now load the unscaled outline */ | |
1378 | error = Z1_Parse_CharStrings( &decoder, | |
1379 | type1->charstrings [glyph_index], | |
1380 | type1->charstrings_len[glyph_index], | |
1381 | type1->num_subrs, | |
1382 | type1->subrs, | |
1383 | type1->subrs_len ); | |
1384 | ||
1385 | /* save new glyph tables */ | |
1386 | Z1_Done_Builder( &decoder.builder ); | |
1387 | ||
1388 | /* now, set the metrics -- this is rather simple, as */ | |
1389 | /* the left side bearing is the xMin, and the top side */ | |
1390 | /* bearing the yMax */ | |
1391 | if ( !error ) | |
1392 | { | |
1393 | glyph->root.outline.flags &= ft_outline_owner; | |
1394 | glyph->root.outline.flags |= ft_outline_reverse_fill; | |
1395 | ||
1396 | /* for composite glyphs, return only left side bearing and */ | |
1397 | /* advance width */ | |
1398 | if ( load_flags & FT_LOAD_NO_RECURSE ) | |
1399 | { | |
1400 | glyph->root.metrics.horiBearingX = decoder.builder.left_bearing.x; | |
1401 | glyph->root.metrics.horiAdvance = decoder.builder.advance.x; | |
1402 | } | |
1403 | else | |
1404 | { | |
1405 | FT_BBox cbox; | |
1406 | FT_Glyph_Metrics* metrics = &glyph->root.metrics; | |
1407 | ||
1408 | ||
1409 | /* copy the _unscaled_ advance width */ | |
1410 | metrics->horiAdvance = decoder.builder.advance.x; | |
1411 | ||
1412 | /* make up vertical metrics */ | |
1413 | metrics->vertBearingX = 0; | |
1414 | metrics->vertBearingY = 0; | |
1415 | metrics->vertAdvance = 0; | |
1416 | ||
1417 | glyph->root.format = ft_glyph_format_outline; | |
1418 | ||
1419 | if ( size && size->root.metrics.y_ppem < 24 ) | |
1420 | glyph->root.outline.flags |= ft_outline_high_precision; | |
1421 | ||
1422 | #if 0 | |
1423 | glyph->root.outline.second_pass = TRUE; | |
1424 | glyph->root.outline.high_precision = size->root.metrics.y_ppem < 24; | |
1425 | glyph->root.outline.dropout_mode = 2; | |
1426 | #endif /* 0 */ | |
1427 | ||
1428 | if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 ) | |
1429 | { | |
1430 | /* scale the outline and the metrics */ | |
1431 | FT_Int n; | |
1432 | FT_Outline* cur = decoder.builder.base; | |
1433 | FT_Vector* vec = cur->points; | |
1434 | FT_Fixed x_scale = glyph->x_scale; | |
1435 | FT_Fixed y_scale = glyph->y_scale; | |
1436 | ||
1437 | ||
1438 | /* First of all, scale the points */ | |
1439 | for ( n = cur->n_points; n > 0; n--, vec++ ) | |
1440 | { | |
1441 | vec->x = FT_MulFix( vec->x, x_scale ); | |
1442 | vec->y = FT_MulFix( vec->y, y_scale ); | |
1443 | } | |
1444 | ||
1445 | FT_Outline_Get_CBox( &glyph->root.outline, &cbox ); | |
1446 | ||
1447 | /* Then scale the metrics */ | |
1448 | metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale ); | |
1449 | metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale ); | |
1450 | ||
1451 | metrics->vertBearingX = FT_MulFix( metrics->vertBearingX, x_scale ); | |
1452 | metrics->vertBearingY = FT_MulFix( metrics->vertBearingY, y_scale ); | |
1453 | } | |
1454 | ||
1455 | /* apply the font matrix */ | |
1456 | FT_Outline_Transform( &glyph->root.outline, | |
1457 | &face->type1.font_matrix ); | |
1458 | ||
1459 | /* compute the other metrics */ | |
1460 | FT_Outline_Get_CBox( &glyph->root.outline, &cbox ); | |
1461 | ||
1462 | /* grid fit the bounding box if necessary */ | |
1463 | if ( hinting ) | |
1464 | { | |
1465 | cbox.xMin &= -64; | |
1466 | cbox.yMin &= -64; | |
1467 | cbox.xMax = ( cbox.xMax+63 ) & -64; | |
1468 | cbox.yMax = ( cbox.yMax+63 ) & -64; | |
1469 | } | |
1470 | ||
1471 | metrics->width = cbox.xMax - cbox.xMin; | |
1472 | metrics->height = cbox.yMax - cbox.yMin; | |
1473 | ||
1474 | metrics->horiBearingX = cbox.xMin; | |
1475 | metrics->horiBearingY = cbox.yMax; | |
1476 | } | |
1477 | } | |
1478 | return error; | |
1479 | } | |
1480 | ||
1481 | ||
1482 | /* END */ |