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