1 /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
2
3 Copyright (C) 2007-2014 by Jin-Hwan Cho and Shunsaku Hirata,
4 the dvipdfmx project team.
5
6 Copyright (C) 1998, 1999 by Mark A. Wicks <mwicks@kettering.edu>
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <ctype.h>
28 #include <string.h>
29 #include <math.h>
30
31 #include "system.h"
32 #include "mem.h"
33 #include "error.h"
34 #include "mfileio.h"
35 #include "numbers.h"
36
37 #include "tfm.h"
38
39 #include "pdfobj.h"
40 #include "pdfparse.h"
41 #include "pdfdev.h"
42 #include "pdfdoc.h"
43
44 #include "pdfcolor.h"
45 #include "pdfdraw.h"
46
47 #include "fontmap.h"
48 #include "subfont.h"
49
50 #include "pdfximage.h"
51
52 #include "mpost.h"
53
54 /*
55 * Define the origin as (llx, lly) in order to
56 * match the new xetex.def and dvipdfmx.def
57 */
58
59 static double Xorigin, Yorigin;
60
61 /*
62 * In PDF, current path is not a part of graphics state parameter.
63 * Hence, current path is not saved by the "q" operator and is not
64 * recovered by the "Q" operator. This means that the following PS
65 * code
66 *
67 * <path construction> gsave <path painting> grestore ...
68 *
69 * can't be translated to PDF code
70 *
71 * <path construction> q <path painting> Q ...
72 *
73 * . Only clipping path (which is graphics state parameter in PDF
74 * too) is treated in the same way. So, we write clipping path
75 * immediately and forget about it but remember current path.
76 */
77
78 static int mp_parse_body (const char **start, const char *end, double x_user, double y_user);
79
80 static struct mp_font
81 {
82 char *font_name;
83 int font_id;
84 int tfm_id; /* Used for text width calculation */
85 int subfont_id;
86 double pt_size;
87 } font_stack[PDF_GSAVE_MAX] = {
88 {NULL, -1, -1, -1, 0}
89 };
90 static int currentfont = -1;
91
92 #define CURRENT_FONT() ((currentfont < 0) ? NULL : &font_stack[currentfont])
93
94 /* Compatibility */
95 #define MP_CMODE_MPOST 0
96 #define MP_CMODE_DVIPSK 1
97 #define MP_CMODE_PTEXVERT 2
98 static int mp_cmode = MP_CMODE_MPOST;
99
100 static int
mp_setfont(const char * font_name,double pt_size)101 mp_setfont (const char *font_name, double pt_size)
102 {
103 const char *name = font_name;
104 struct mp_font *font;
105 int subfont_id = -1;
106 fontmap_rec *mrec;
107
108 font = CURRENT_FONT();
109
110 if (font) {
111 if (!strcmp(font->font_name, font_name) &&
112 font->pt_size == pt_size)
113 return 0;
114 } else { /* No currentfont */
115 /* ***TODO*** Here some problem exists! */
116 font = &font_stack[0];
117 font->font_name = NULL;
118 currentfont = 0;
119 }
120
121 mrec = pdf_lookup_fontmap_record(font_name);
122 if (mrec && mrec->charmap.sfd_name && mrec->charmap.subfont_id) {
123 subfont_id = sfd_load_record(mrec->charmap.sfd_name, mrec->charmap.subfont_id);
124 }
125
126 /* See comments in dvi_locate_font() in dvi.c. */
127 if (mrec && mrec->map_name) {
128 name = mrec->map_name;
129 } else {
130 name = font_name;
131 }
132
133 if (font->font_name)
134 RELEASE(font->font_name);
135 font->font_name = NEW(strlen(font_name) + 1, char);
136 strcpy(font->font_name, font_name);
137 font->subfont_id = subfont_id;
138 font->pt_size = pt_size;
139 font->tfm_id = tfm_open(font_name, 0); /* Need not exist in MP mode */
140 font->font_id = pdf_dev_locate_font(name,
141 (spt_t) (pt_size * dev_unit_dviunit()));
142
143 if (font->font_id < 0) {
144 ERROR("MPOST: No physical font assigned for \"%s\".", font_name);
145 return 1;
146 }
147
148 return 0;
149 }
150
151 static void
save_font(void)152 save_font (void)
153 {
154 struct mp_font *current, *next;
155
156 if (currentfont < 0) {
157 font_stack[0].font_name = NEW(strlen("Courier") + 1, char);
158 strcpy(font_stack[0].font_name, "Courier");
159 font_stack[0].pt_size = 1;
160 font_stack[0].tfm_id = 0;
161 font_stack[0].subfont_id = 0;
162 currentfont = 0;
163 }
164
165 current = &font_stack[currentfont++];
166 next = &font_stack[currentfont ];
167 next->font_name = NEW(strlen(current->font_name)+1, char);
168 strcpy(next->font_name, current->font_name);
169 next->pt_size = current->pt_size;
170
171 next->subfont_id = current->subfont_id;
172 next->tfm_id = current->tfm_id;
173 }
174
175 static void
restore_font(void)176 restore_font (void)
177 {
178 struct mp_font *current;
179
180 current = CURRENT_FONT();
181 if (current) {
182 if (current->font_name)
183 RELEASE(current->font_name);
184 current->font_name = NULL;
185 } else {
186 ERROR("No currentfont...");
187 }
188
189 currentfont--;
190 }
191
192 static void
clear_fonts(void)193 clear_fonts (void)
194 {
195 while (currentfont >= 0) {
196 if (font_stack[currentfont].font_name)
197 RELEASE(font_stack[currentfont].font_name);
198 currentfont--;
199 }
200 }
201
202 static int
is_fontname(const char * token)203 is_fontname (const char *token)
204 {
205 fontmap_rec *mrec;
206
207 mrec = pdf_lookup_fontmap_record(token);
208 if (mrec)
209 return 1;
210
211 return tfm_exists(token);
212 }
213
214 int
mps_scan_bbox(const char ** pp,const char * endptr,pdf_rect * bbox)215 mps_scan_bbox (const char **pp, const char *endptr, pdf_rect *bbox)
216 {
217 char *number;
218 double values[4];
219 int i;
220
221 /* skip_white() skips lines starting '%'... */
222 while (*pp < endptr && isspace((unsigned char)**pp))
223 (*pp)++;
224
225 /* Scan for bounding box record */
226 while (*pp < endptr && **pp == '%') {
227 if (*pp + 14 < endptr &&
228 !strncmp(*pp, "%%BoundingBox:", 14)) {
229
230 *pp += 14;
231
232 for (i = 0; i < 4; i++) {
233 skip_white(pp, endptr);
234 number = parse_number(pp, endptr);
235 if (!number) {
236 break;
237 }
238 values[i] = atof(number);
239 RELEASE(number);
240 }
241 if (i < 4) {
242 return -1;
243 } else {
244 /* The new xetex.def and dvipdfmx.def require bbox->llx = bbox->lly = 0. */
245 bbox->llx = 0;
246 bbox->lly = 0;
247 bbox->urx = values[2] - values[0];
248 bbox->ury = values[3] - values[1];
249
250 Xorigin = (double)values[0];
251 Yorigin = (double)values[1];
252
253 return 0;
254 }
255 }
256 skip_line (pp, endptr);
257 while (*pp < endptr && isspace((unsigned char)**pp))
258 (*pp)++;
259 }
260
261 return -1;
262 }
263
264 static void
skip_prolog(const char ** start,const char * end)265 skip_prolog (const char **start, const char *end)
266 {
267 int found_prolog = 0;
268 const char *save;
269
270 save = *start;
271 while (*start < end) {
272 if (**start != '%')
273 skip_white(start, end);
274 if (*start >= end)
275 break;
276 if (!strncmp(*start, "%%EndProlog", 11)) {
277 found_prolog = 1;
278 skip_line(start, end);
279 break;
280 } else if (!strncmp(*start, "%%Page:", 7)) {
281 skip_line(start, end);
282 break;
283 }
284 skip_line(start, end);
285 }
286 if (!found_prolog) {
287 *start = save;
288 }
289
290 return;
291 }
292
293 /* PostScript Operators */
294
295 #define ADD 1
296 #define SUB 2
297 #define MUL 3
298 #define DIV 4
299 #define NEG 5
300 #define TRUNCATE 6
301
302 #define CLEAR 10
303 #define EXCH 11
304 #define POP 12
305
306 #define NEWPATH 31
307 #define CLOSEPATH 32
308 #define MOVETO 33
309 #define RMOVETO 34
310 #define CURVETO 35
311 #define RCURVETO 36
312 #define LINETO 37
313 #define RLINETO 38
314 #define ARC 39
315 #define ARCN 40
316
317 #define FILL 41
318 #define STROKE 42
319 #define SHOW 43
320
321 #define CLIP 44
322 #define EOCLIP 45
323
324 #define SHOWPAGE 49
325
326 #define GSAVE 50
327 #define GRESTORE 51
328
329 #define CONCAT 52
330 #define SCALE 53
331 #define TRANSLATE 54
332 #define ROTATE 55
333
334 #define SETLINEWIDTH 60
335 #define SETDASH 61
336 #define SETLINECAP 62
337 #define SETLINEJOIN 63
338 #define SETMITERLIMIT 64
339
340 #define SETGRAY 70
341 #define SETRGBCOLOR 71
342 #define SETCMYKCOLOR 72
343
344 #define CURRENTPOINT 80
345 #define IDTRANSFORM 81
346 #define DTRANSFORM 82
347
348 #define FINDFONT 201
349 #define SCALEFONT 202
350 #define SETFONT 203
351 #define CURRENTFONT 204
352
353 #define STRINGWIDTH 210
354
355 #define DEF 999
356
357 #define FSHOW 1001
358 #define STEXFIG 1002
359 #define ETEXFIG 1003
360 #define HLW 1004
361 #define VLW 1005
362 #define RD 1006
363 #define B 1007
364
365 static struct operators
366 {
367 const char *token;
368 int opcode;
369 } ps_operators[] = {
370 {"add", ADD},
371 {"mul", MUL},
372 {"div", DIV},
373 {"neg", NEG},
374 {"sub", SUB},
375 {"truncate", TRUNCATE},
376
377 {"clear", CLEAR},
378 {"exch", EXCH},
379 {"pop", POP},
380
381 {"clip", CLIP},
382 {"eoclip", EOCLIP},
383 {"closepath", CLOSEPATH},
384 {"concat", CONCAT},
385
386 {"newpath", NEWPATH},
387 {"moveto", MOVETO},
388 {"rmoveto", RMOVETO},
389 {"lineto", LINETO},
390 {"rlineto", RLINETO},
391 {"curveto", CURVETO},
392 {"rcurveto", RCURVETO},
393 {"arc", ARC},
394 {"arcn", ARCN},
395
396 {"stroke", STROKE},
397 {"fill", FILL},
398 {"show", SHOW},
399 {"showpage", SHOWPAGE},
400
401 {"gsave", GSAVE},
402 {"grestore", GRESTORE},
403 {"translate", TRANSLATE},
404 {"rotate", ROTATE},
405 {"scale", SCALE},
406
407 {"setlinecap", SETLINECAP},
408 {"setlinejoin", SETLINEJOIN},
409 {"setlinewidth", SETLINEWIDTH},
410 {"setmiterlimit", SETMITERLIMIT},
411 {"setdash", SETDASH},
412
413 {"setgray", SETGRAY},
414 {"setrgbcolor", SETRGBCOLOR},
415 {"setcmykcolor", SETCMYKCOLOR},
416
417 {"currentpoint", CURRENTPOINT}, /* This is here for rotate support
418 in graphics package-not MP support */
419 {"dtransform", DTRANSFORM},
420 {"idtransform", IDTRANSFORM},
421
422 {"findfont", FINDFONT},
423 {"scalefont", SCALEFONT},
424 {"setfont", SETFONT},
425 {"currentfont", CURRENTFONT},
426
427 {"stringwidth", STRINGWIDTH},
428
429 {"def", DEF} /* not implemented yet; just work with mptopdf */
430 };
431
432 static struct operators mps_operators[] = {
433 {"fshow", FSHOW}, /* exch findfont exch scalefont setfont show */
434 {"startTexFig", STEXFIG},
435 {"endTexFig", ETEXFIG},
436 {"hlw", HLW}, /* 0 dtransform exch truncate exch idtransform pop setlinewidth */
437 {"vlw", VLW}, /* 0 exch dtransform truncate idtransform pop setlinewidth pop */
438 {"l", LINETO},
439 {"r", RLINETO},
440 {"c", CURVETO},
441 {"m", MOVETO},
442 {"p", CLOSEPATH},
443 {"n", NEWPATH},
444 {"C", SETCMYKCOLOR},
445 {"G", SETGRAY},
446 {"R", SETRGBCOLOR},
447 {"lj", SETLINEJOIN},
448 {"ml", SETMITERLIMIT},
449 {"lc", SETLINECAP},
450 {"S", STROKE},
451 {"F", FILL},
452 {"q", GSAVE},
453 {"Q", GRESTORE},
454 {"s", SCALE},
455 {"t", CONCAT},
456 {"sd", SETDASH},
457 {"rd", RD}, /* [] 0 setdash */
458 {"P", SHOWPAGE},
459 {"B", B}, /* gsave fill grestore */
460 {"W", CLIP}
461 };
462
463 #define NUM_PS_OPERATORS (sizeof(ps_operators)/sizeof(ps_operators[0]))
464 #define NUM_MPS_OPERATORS (sizeof(mps_operators)/sizeof(mps_operators[0]))
465 static int
get_opcode(const char * token)466 get_opcode (const char *token)
467 {
468 int i;
469
470 for (i = 0; i < NUM_PS_OPERATORS; i++) {
471 if (!strcmp(token, ps_operators[i].token)) {
472 return ps_operators[i].opcode;
473 }
474 }
475
476 for (i = 0; i < NUM_MPS_OPERATORS; i++) {
477 if (!strcmp(token, mps_operators[i].token)) {
478 return mps_operators[i].opcode;
479 }
480 }
481
482 return -1;
483 }
484
485 #define PS_STACK_SIZE 1024
486
487 static pdf_obj *stack[PS_STACK_SIZE];
488 static unsigned top_stack = 0;
489
490 #define POP_STACK() ((top_stack > 0) ? stack[--top_stack] : NULL)
491 #define PUSH_STACK(o,e) { \
492 if (top_stack < PS_STACK_SIZE) { \
493 stack[top_stack++] = (o); \
494 } else { \
495 WARN("PS stack overflow including MetaPost file or inline PS code"); \
496 *(e) = 1; \
497 } \
498 }
499
500 static int
do_exch(void)501 do_exch (void)
502 {
503 pdf_obj *tmp;
504
505 if (top_stack < 2)
506 return -1;
507
508 tmp = stack[top_stack-1];
509 stack[top_stack-1] = stack[top_stack-2];
510 stack[top_stack-2] = tmp;
511
512 return 0;
513 }
514
515 static int
do_clear(void)516 do_clear (void)
517 {
518 pdf_obj *tmp;
519
520 while (top_stack > 0) {
521 tmp = POP_STACK();
522 if (tmp)
523 pdf_release_obj(tmp);
524 }
525
526 return 0;
527 }
528
529 /* This should be set_bottom and clear (or
530 * have independent stack) to ensure stack
531 * depth do not go below real stack bottom.
532 */
533 static void
mps_stack_clear_to(int depth)534 mps_stack_clear_to (int depth)
535 {
536 pdf_obj *tmp;
537
538 while (top_stack > depth) {
539 tmp = POP_STACK();
540 if (tmp)
541 pdf_release_obj(tmp);
542 }
543
544 return;
545 }
546
547 static int
pop_get_numbers(double * values,int count)548 pop_get_numbers (double *values, int count)
549 {
550 pdf_obj *tmp;
551
552 while (count-- > 0) {
553 tmp = POP_STACK();
554 if (!tmp) {
555 WARN("mpost: Stack underflow.");
556 break;
557 } else if (!PDF_OBJ_NUMBERTYPE(tmp)) {
558 WARN("mpost: Not a number!");
559 pdf_release_obj(tmp);
560 break;
561 }
562 values[count] = pdf_number_value(tmp);
563 pdf_release_obj(tmp);
564 }
565
566 return (count + 1);
567 }
568
569 static int
cvr_array(pdf_obj * array,double * values,int count)570 cvr_array (pdf_obj *array, double *values, int count)
571 {
572 if (!PDF_OBJ_ARRAYTYPE(array)) {
573 WARN("mpost: Not an array!");
574 } else {
575 pdf_obj *tmp;
576
577 while (count-- > 0) {
578 tmp = pdf_get_array(array, count);
579 if (!PDF_OBJ_NUMBERTYPE(tmp)) {
580 WARN("mpost: Not a number!");
581 break;
582 }
583 values[count] = pdf_number_value(tmp);
584 }
585 }
586 if (array)
587 pdf_release_obj(array);
588
589 return (count + 1);
590 }
591
592 static int
is_fontdict(pdf_obj * dict)593 is_fontdict (pdf_obj *dict)
594 {
595 pdf_obj *tmp;
596
597 if (!PDF_OBJ_DICTTYPE(dict))
598 return 0;
599
600 tmp = pdf_lookup_dict(dict, "Type");
601 if (!tmp || !PDF_OBJ_NAMETYPE(tmp) ||
602 strcmp(pdf_name_value(tmp), "Font")) {
603 return 0;
604 }
605
606 tmp = pdf_lookup_dict(dict, "FontName");
607 if (!tmp || !PDF_OBJ_NAMETYPE(tmp)) {
608 return 0;
609 }
610
611 tmp = pdf_lookup_dict(dict, "FontScale");
612 if (!tmp || !PDF_OBJ_NUMBERTYPE(tmp)) {
613 return 0;
614 }
615
616 return 1;
617 }
618
619 static int
do_findfont(void)620 do_findfont (void)
621 {
622 int error = 0;
623 pdf_obj *font_dict, *font_name;
624
625 font_name = POP_STACK();
626 if (!font_name)
627 return 1;
628 else if (PDF_OBJ_STRINGTYPE(font_name) ||
629 PDF_OBJ_NAMETYPE(font_name)) {
630 /* Do not check the existence...
631 * The reason for this is that we cannot locate PK font without
632 * font scale.
633 */
634 font_dict = pdf_new_dict();
635 pdf_add_dict(font_dict,
636 pdf_new_name("Type"), pdf_new_name("Font"));
637 if (PDF_OBJ_STRINGTYPE(font_name)) {
638 pdf_add_dict(font_dict,
639 pdf_new_name("FontName"),
640 pdf_new_name(pdf_string_value(font_name)));
641 pdf_release_obj(font_name);
642 } else {
643 pdf_add_dict(font_dict,
644 pdf_new_name("FontName"), font_name);
645 }
646 pdf_add_dict(font_dict,
647 pdf_new_name("FontScale"), pdf_new_number(1.0));
648
649 if (top_stack < PS_STACK_SIZE) {
650 stack[top_stack++] = font_dict;
651 } else {
652 WARN("PS stack overflow including MetaPost file or inline PS code");
653 pdf_release_obj(font_dict);
654 error = 1;
655 }
656 } else {
657 error = 1;
658 }
659
660 return error;
661 }
662
663 static int
do_scalefont(void)664 do_scalefont (void)
665 {
666 int error = 0;
667 pdf_obj *font_dict;
668 pdf_obj *font_scale;
669 double scale;
670
671 error = pop_get_numbers(&scale, 1);
672 if (error)
673 return error;
674
675 font_dict = POP_STACK();
676 if (!font_dict)
677 error = 1;
678 else if (is_fontdict(font_dict)) {
679 font_scale = pdf_lookup_dict(font_dict, "FontScale");
680 pdf_set_number(font_scale, pdf_number_value(font_scale)*scale);
681 if (top_stack < PS_STACK_SIZE) {
682 stack[top_stack++] = font_dict;
683 } else {
684 WARN("PS stack overflow including MetaPost file or inline PS code");
685 pdf_release_obj(font_dict);
686 error = 1;
687 }
688 } else {
689 error = 1;
690 }
691
692 return error;
693 }
694
695 static int
do_setfont(void)696 do_setfont (void)
697 {
698 int error = 0;
699 char *font_name;
700 double font_scale;
701 pdf_obj *font_dict;
702
703 font_dict = POP_STACK();
704 if (!is_fontdict(font_dict))
705 error = 1;
706 else {
707 /* Subfont support prevent us from managing
708 * font in a single place...
709 */
710 font_name = pdf_name_value (pdf_lookup_dict(font_dict, "FontName"));
711 font_scale = pdf_number_value(pdf_lookup_dict(font_dict, "FontScale"));
712
713 error = mp_setfont(font_name, font_scale);
714 }
715 pdf_release_obj(font_dict);
716
717 return error;
718 }
719
720 /* Push dummy font dict onto PS stack */
721 static int
do_currentfont(void)722 do_currentfont (void)
723 {
724 int error = 0;
725 struct mp_font *font;
726 pdf_obj *font_dict;
727
728 font = CURRENT_FONT();
729 if (!font) {
730 WARN("Currentfont undefined...");
731 return 1;
732 } else {
733 font_dict = pdf_new_dict();
734 pdf_add_dict(font_dict,
735 pdf_new_name("Type"),
736 pdf_new_name("Font"));
737 pdf_add_dict(font_dict,
738 pdf_new_name("FontName"),
739 pdf_new_name(font->font_name));
740 pdf_add_dict(font_dict,
741 pdf_new_name("FontScale"),
742 pdf_new_number(font->pt_size));
743 if (top_stack < PS_STACK_SIZE) {
744 stack[top_stack++] = font_dict;
745 } else {
746 WARN("PS stack overflow...");
747 pdf_release_obj(font_dict);
748 error = 1;
749 }
750 }
751
752 return error;
753 }
754
755 static int
do_show(void)756 do_show (void)
757 {
758 struct mp_font *font;
759 pdf_coord cp;
760 pdf_obj *text_str;
761 int length;
762 unsigned char *strptr;
763 double text_width;
764
765 font = CURRENT_FONT();
766 if (!font) {
767 WARN("Currentfont not set."); /* Should not be error... */
768 return 1;
769 }
770
771 pdf_dev_currentpoint(&cp);
772
773 text_str = POP_STACK();
774 if (!PDF_OBJ_STRINGTYPE(text_str)) {
775 if (text_str)
776 pdf_release_obj(text_str);
777 return 1;
778 }
779 if (font->font_id < 0) {
780 WARN("mpost: not set."); /* Should not be error... */
781 pdf_release_obj(text_str);
782 return 1;
783 }
784
785 strptr = pdf_string_value (text_str);
786 length = pdf_string_length(text_str);
787
788 if (font->tfm_id < 0) {
789 WARN("mpost: TFM not found for \"%s\".", font->font_name);
790 WARN("mpost: Text width not calculated...");
791 }
792
793 text_width = 0.0;
794 if (font->subfont_id >= 0) {
795 unsigned short uch;
796 unsigned char *ustr;
797 int i;
798
799 ustr = NEW(length * 2, unsigned char);
800 for (i = 0; i < length; i++) {
801 uch = lookup_sfd_record(font->subfont_id, strptr[i]);
802 ustr[2*i ] = uch >> 8;
803 ustr[2*i+1] = uch & 0xff;
804 if (font->tfm_id >= 0) {
805 text_width += tfm_get_width(font->tfm_id, strptr[i]);
806 }
807 }
808 text_width *= font->pt_size;
809
810 pdf_dev_set_string((spt_t)(cp.x * dev_unit_dviunit()),
811 (spt_t)(cp.y * dev_unit_dviunit()),
812 ustr, length * 2,
813 (spt_t)(text_width*dev_unit_dviunit()),
814 font->font_id, 0);
815 RELEASE(ustr);
816 } else {
817 #define FWBASE ((double) (1<<20))
818 if (font->tfm_id >= 0) {
819 text_width = (double) tfm_string_width(font->tfm_id, strptr, length)/FWBASE;
820 text_width *= font->pt_size;
821 }
822 pdf_dev_set_string((spt_t)(cp.x * dev_unit_dviunit()),
823 (spt_t)(cp.y * dev_unit_dviunit()),
824 strptr, length,
825 (spt_t)(text_width*dev_unit_dviunit()),
826 font->font_id, 0);
827 }
828
829 if (pdf_dev_get_font_wmode(font->font_id)) {
830 pdf_dev_rmoveto(0.0, -text_width);
831 } else {
832 pdf_dev_rmoveto(text_width, 0.0);
833 }
834
835 graphics_mode();
836 pdf_release_obj(text_str);
837
838 return 0;
839 }
840
841 static int
do_mpost_bind_def(const char * ps_code,double x_user,double y_user)842 do_mpost_bind_def (const char *ps_code, double x_user, double y_user)
843 {
844 int error = 0;
845 const char *start, *end;
846
847 start = ps_code;
848 end = start + strlen(start);
849
850 error = mp_parse_body(&start, end, x_user, y_user);
851
852 return error;
853 }
854
855 static int
do_texfig_operator(int opcode,double x_user,double y_user)856 do_texfig_operator (int opcode, double x_user, double y_user)
857 {
858 static transform_info fig_p;
859 static int in_tfig = 0;
860 static int xobj_id = -1;
861 static int count = 0;
862 double values[6];
863 int error = 0;
864
865 switch (opcode) {
866 case STEXFIG:
867 error = pop_get_numbers(values, 6);
868 if (!error) {
869 double dvi2pts;
870 char resname[256];
871
872 transform_info_clear(&fig_p);
873 dvi2pts = 1.0/dev_unit_dviunit();
874
875 fig_p.width = values[0] * dvi2pts;
876 fig_p.height = values[1] * dvi2pts;
877 fig_p.bbox.llx = values[2] * dvi2pts;
878 fig_p.bbox.lly = -values[3] * dvi2pts;
879 fig_p.bbox.urx = values[4] * dvi2pts;
880 fig_p.bbox.ury = -values[5] * dvi2pts;
881 fig_p.flags |= INFO_HAS_USER_BBOX;
882
883 sprintf(resname, "__tf%d__", count);
884 xobj_id = pdf_doc_begin_grabbing(resname,
885 fig_p.bbox.llx, fig_p.bbox.ury, &fig_p.bbox);
886
887 in_tfig = 1;
888 count++;
889 }
890 break;
891 case ETEXFIG:
892 if (!in_tfig)
893 ERROR("endTexFig without valid startTexFig!.");
894
895 pdf_doc_end_grabbing(NULL);
896 pdf_dev_put_image(xobj_id, &fig_p, x_user, y_user);
897 in_tfig = 0;
898 break;
899 default:
900 error = 1;
901 }
902
903 return error;
904 }
905
906 /*
907 * buggy...
908 */
909
910 /*
911 * CTM(Current Transformation Matrix) means the transformation of User Space
912 * to Device Space coordinates. Because DVIPDFMx does not know the resolution
913 * of Device Space, we assume that the resolution is 1/1000.
914 */
915 #define DEVICE_RESOLUTION 1000
916 static int
ps_dev_CTM(pdf_tmatrix * M)917 ps_dev_CTM (pdf_tmatrix *M)
918 {
919 pdf_dev_currentmatrix(M);
920 M->a *= DEVICE_RESOLUTION; M->b *= DEVICE_RESOLUTION;
921 M->c *= DEVICE_RESOLUTION; M->d *= DEVICE_RESOLUTION;
922 M->e *= DEVICE_RESOLUTION; M->f *= DEVICE_RESOLUTION;
923
924 return 0;
925 }
926
927 /*
928 * Again, the only piece that needs x_user and y_user is
929 * that piece dealing with texfig.
930 */
931 static int
do_operator(const char * token,double x_user,double y_user)932 do_operator (const char *token, double x_user, double y_user)
933 {
934 int error = 0;
935 int opcode = 0;
936 double values[12];
937 pdf_obj *tmp = NULL;
938 pdf_tmatrix matrix;
939 pdf_coord cp;
940 pdf_color color;
941
942 #define PUSH(o) { \
943 if (top_stack < PS_STACK_SIZE) { \
944 stack[top_stack++] = (o); \
945 } else { \
946 WARN("PS stack overflow including MetaPost file or inline PS code"); \
947 error=1; \
948 break;\
949 } \
950 }
951
952 opcode = get_opcode(token);
953
954 switch (opcode) {
955
956 /*
957 * Arithmetic operators
958 */
959 case ADD:
960 error = pop_get_numbers(values, 2);
961 if (!error)
962 PUSH(pdf_new_number(values[0] + values[1]));
963 break;
964 case MUL:
965 error = pop_get_numbers(values, 2);
966 if (!error)
967 PUSH(pdf_new_number(values[0]*values[1]));
968 break;
969 case NEG:
970 error = pop_get_numbers(values, 1);
971 if (!error)
972 PUSH(pdf_new_number(-values[0]));
973 break;
974 case SUB:
975 error = pop_get_numbers(values, 2);
976 if (!error)
977 PUSH(pdf_new_number(values[0] - values[1]));
978 break;
979 case DIV:
980 error = pop_get_numbers(values, 2);
981 if (!error)
982 PUSH(pdf_new_number(values[0]/values[1]));
983 break;
984 case TRUNCATE: /* Round toward zero. */
985 error = pop_get_numbers(values, 1);
986 if (!error)
987 PUSH(pdf_new_number(((values[0] > 0) ? floor(values[0]) : ceil(values[0]))));
988 break;
989
990 /* Stack operation */
991 case CLEAR:
992 error = do_clear();
993 break;
994 case POP:
995 tmp = POP_STACK();
996 if (tmp)
997 pdf_release_obj(tmp);
998 break;
999 case EXCH:
1000 error = do_exch();
1001 break;
1002
1003 /* Path construction */
1004 case MOVETO:
1005 error = pop_get_numbers(values, 2);
1006 if (!error)
1007 error = pdf_dev_moveto(values[0], values[1]);
1008 break;
1009 case RMOVETO:
1010 error = pop_get_numbers(values, 2);
1011 if (!error)
1012 error = pdf_dev_rmoveto(values[0], values[1]);
1013 break;
1014 case LINETO:
1015 error = pop_get_numbers(values, 2);
1016 if (!error)
1017 error = pdf_dev_lineto(values[0], values[1]);
1018 break;
1019 case RLINETO:
1020 error = pop_get_numbers(values, 2);
1021 if (!error)
1022 error = pdf_dev_rlineto(values[0], values[1]);
1023 break;
1024 case CURVETO:
1025 error = pop_get_numbers(values, 6);
1026 if (!error)
1027 error = pdf_dev_curveto(values[0], values[1],
1028 values[2], values[3],
1029 values[4], values[5]);
1030 break;
1031 case RCURVETO:
1032 error = pop_get_numbers(values, 6);
1033 if (!error)
1034 error = pdf_dev_rcurveto(values[0], values[1],
1035 values[2], values[3],
1036 values[4], values[5]);
1037 break;
1038 case CLOSEPATH:
1039 error = pdf_dev_closepath();
1040 break;
1041 case ARC:
1042 error = pop_get_numbers(values, 5);
1043 if (!error)
1044 error = pdf_dev_arc(values[0], values[1],
1045 values[2], /* rad */
1046 values[3], values[4]);
1047 break;
1048 case ARCN:
1049 error = pop_get_numbers(values, 5);
1050 if (!error)
1051 error = pdf_dev_arcn(values[0], values[1],
1052 values[2], /* rad */
1053 values[3], values[4]);
1054 break;
1055
1056 case NEWPATH:
1057 pdf_dev_newpath();
1058 break;
1059 case STROKE:
1060 /* fill rule not supported yet */
1061 pdf_dev_flushpath('S', PDF_FILL_RULE_NONZERO);
1062 break;
1063 case FILL:
1064 pdf_dev_flushpath('f', PDF_FILL_RULE_NONZERO);
1065 break;
1066
1067 case CLIP:
1068 error = pdf_dev_clip();
1069 break;
1070 case EOCLIP:
1071 error = pdf_dev_eoclip();
1072 break;
1073
1074 /* Graphics state operators: */
1075 case GSAVE:
1076 error = pdf_dev_gsave();
1077 save_font();
1078 break;
1079 case GRESTORE:
1080 error = pdf_dev_grestore();
1081 restore_font();
1082 break;
1083
1084 case CONCAT:
1085 tmp = POP_STACK();
1086 error = cvr_array(tmp, values, 6); /* This does pdf_release_obj() */
1087 tmp = NULL;
1088 if (error)
1089 WARN("Missing array before \"concat\".");
1090 else {
1091 pdf_setmatrix(&matrix,
1092 values[0], values[1],
1093 values[2], values[3],
1094 values[4], values[5]);
1095 error = pdf_dev_concat(&matrix);
1096 }
1097 break;
1098 case SCALE:
1099 error = pop_get_numbers(values, 2);
1100 if (!error) {
1101 switch (mp_cmode) {
1102 #ifndef WITHOUT_ASCII_PTEX
1103 case MP_CMODE_PTEXVERT:
1104 pdf_setmatrix(&matrix,
1105 values[1], 0.0,
1106 0.0 , values[0],
1107 0.0 , 0.0);
1108 break;
1109 #endif /* !WITHOUT_ASCII_PTEX */
1110 default:
1111 pdf_setmatrix(&matrix,
1112 values[0], 0.0,
1113 0.0 , values[1],
1114 0.0 , 0.0);
1115 break;
1116 }
1117
1118 error = pdf_dev_concat(&matrix);
1119 }
1120 break;
1121 /* Positive angle means clock-wise direction in graphicx-dvips??? */
1122 case ROTATE:
1123 error = pop_get_numbers(values, 1);
1124 if (!error) {
1125 values[0] = values[0] * M_PI / 180;
1126
1127 switch (mp_cmode) {
1128 case MP_CMODE_DVIPSK:
1129 case MP_CMODE_MPOST: /* Really? */
1130 #ifndef WITHOUT_ASCII_PTEX
1131 case MP_CMODE_PTEXVERT:
1132 #endif /* !WITHOUT_ASCII_PTEX */
1133 pdf_setmatrix(&matrix,
1134 cos(values[0]), -sin(values[0]),
1135 sin(values[0]), cos(values[0]),
1136 0.0, 0.0);
1137 break;
1138 default:
1139 pdf_setmatrix(&matrix,
1140 cos(values[0]) , sin(values[0]),
1141 -sin(values[0]), cos(values[0]),
1142 0.0, 0.0);
1143 break;
1144 }
1145 error = pdf_dev_concat(&matrix);
1146 }
1147 break;
1148 case TRANSLATE:
1149 error = pop_get_numbers(values, 2);
1150 if (!error) {
1151 pdf_setmatrix(&matrix,
1152 1.0, 0.0,
1153 0.0, 1.0,
1154 values[0], values[1]);
1155 error = pdf_dev_concat(&matrix);
1156 }
1157 break;
1158
1159 case SETDASH:
1160 error = pop_get_numbers(values, 1);
1161 if (!error) {
1162 pdf_obj *pattern, *dash;
1163 int i, num_dashes;
1164 double dash_values[PDF_DASH_SIZE_MAX];
1165 double offset;
1166
1167 offset = values[0];
1168 pattern = POP_STACK();
1169 if (!PDF_OBJ_ARRAYTYPE(pattern)) {
1170 if (pattern)
1171 pdf_release_obj(pattern);
1172 error = 1;
1173 break;
1174 }
1175 num_dashes = pdf_array_length(pattern);
1176 if (num_dashes > PDF_DASH_SIZE_MAX) {
1177 WARN("Too many dashes...");
1178 pdf_release_obj(pattern);
1179 error = 1;
1180 break;
1181 }
1182 for (i = 0;
1183 i < num_dashes && !error ; i++) {
1184 dash = pdf_get_array(pattern, i);
1185 if (!PDF_OBJ_NUMBERTYPE(dash))
1186 error = 1;
1187 else {
1188 dash_values[i] = pdf_number_value(dash);
1189 }
1190 }
1191 pdf_release_obj(pattern);
1192 if (!error) {
1193 error = pdf_dev_setdash(num_dashes, dash_values, offset);
1194 }
1195 }
1196 break;
1197 case SETLINECAP:
1198 error = pop_get_numbers(values, 1);
1199 if (!error)
1200 error = pdf_dev_setlinecap((int)values[0]);
1201 break;
1202 case SETLINEJOIN:
1203 error = pop_get_numbers(values, 1);
1204 if (!error)
1205 error = pdf_dev_setlinejoin((int)values[0]);
1206 break;
1207 case SETLINEWIDTH:
1208 error = pop_get_numbers(values, 1);
1209 if (!error)
1210 error = pdf_dev_setlinewidth(values[0]);
1211 break;
1212 case SETMITERLIMIT:
1213 error = pop_get_numbers(values, 1);
1214 if (!error)
1215 error = pdf_dev_setmiterlimit(values[0]);
1216 break;
1217
1218 case SETCMYKCOLOR:
1219 error = pop_get_numbers(values, 4);
1220 /* Not handled properly */
1221 if (!error) {
1222 pdf_color_cmykcolor(&color,
1223 values[0], values[1],
1224 values[2], values[3]);
1225 pdf_dev_set_strokingcolor(&color);
1226 pdf_dev_set_nonstrokingcolor(&color);
1227 }
1228 break;
1229 case SETGRAY:
1230 /* Not handled properly */
1231 error = pop_get_numbers(values, 1);
1232 if (!error) {
1233 pdf_color_graycolor(&color, values[0]);
1234 pdf_dev_set_strokingcolor(&color);
1235 pdf_dev_set_nonstrokingcolor(&color);
1236 }
1237 break;
1238 case SETRGBCOLOR:
1239 error = pop_get_numbers(values, 3);
1240 if (!error) {
1241 pdf_color_rgbcolor(&color,
1242 values[0], values[1], values[2]);
1243 pdf_dev_set_strokingcolor(&color);
1244 pdf_dev_set_nonstrokingcolor(&color);
1245 }
1246 break;
1247
1248 case SHOWPAGE: /* Let's ignore this for now */
1249 break;
1250
1251 case CURRENTPOINT:
1252 error = pdf_dev_currentpoint(&cp);
1253 if (!error) {
1254 PUSH(pdf_new_number(cp.x));
1255 PUSH(pdf_new_number(cp.y));
1256 }
1257 break;
1258
1259 case DTRANSFORM:
1260 {
1261 int has_matrix = 0;
1262
1263 tmp = POP_STACK();
1264 if (PDF_OBJ_ARRAYTYPE(tmp)) {
1265 error = cvr_array(tmp, values, 6); /* This does pdf_release_obj() */
1266 tmp = NULL;
1267 if (error)
1268 break;
1269 pdf_setmatrix(&matrix,
1270 values[0], values[1],
1271 values[2], values[3],
1272 values[4], values[5]);
1273 tmp = POP_STACK();
1274 has_matrix = 1;
1275 }
1276
1277 if (!PDF_OBJ_NUMBERTYPE(tmp)) {
1278 error = 1;
1279 break;
1280 }
1281 cp.y = pdf_number_value(tmp);
1282 pdf_release_obj(tmp);
1283
1284 tmp = POP_STACK();
1285 if (!PDF_OBJ_NUMBERTYPE(tmp)) {
1286 error = 1;
1287 break;
1288 }
1289 cp.x = pdf_number_value(tmp);
1290 pdf_release_obj(tmp);
1291
1292 if (!has_matrix) {
1293 ps_dev_CTM(&matrix); /* Here, we need real PostScript CTM */
1294 }
1295 pdf_dev_dtransform(&cp, &matrix);
1296 PUSH(pdf_new_number(cp.x));
1297 PUSH(pdf_new_number(cp.y));
1298 }
1299 break;
1300
1301 case IDTRANSFORM:
1302 {
1303 int has_matrix = 0;
1304
1305 tmp = POP_STACK();
1306 if (PDF_OBJ_ARRAYTYPE(tmp)) {
1307 error = cvr_array(tmp, values, 6); /* This does pdf_release_obj() */
1308 tmp = NULL;
1309 if (error)
1310 break;
1311 pdf_setmatrix(&matrix,
1312 values[0], values[1],
1313 values[2], values[3],
1314 values[4], values[5]);
1315 tmp = POP_STACK();
1316 has_matrix = 1;
1317 }
1318
1319 if (!PDF_OBJ_NUMBERTYPE(tmp)) {
1320 error = 1;
1321 break;
1322 }
1323 cp.y = pdf_number_value(tmp);
1324 pdf_release_obj(tmp);
1325
1326 tmp = POP_STACK();
1327 if (!PDF_OBJ_NUMBERTYPE(tmp)) {
1328 error = 1;
1329 break;
1330 }
1331 cp.x = pdf_number_value(tmp);
1332 pdf_release_obj(tmp);
1333
1334 if (!has_matrix) {
1335 ps_dev_CTM(&matrix); /* Here, we need real PostScript CTM */
1336 }
1337 pdf_dev_idtransform(&cp, &matrix);
1338 PUSH(pdf_new_number(cp.x));
1339 PUSH(pdf_new_number(cp.y));
1340 break;
1341 }
1342
1343 case FINDFONT:
1344 error = do_findfont();
1345 break;
1346 case SCALEFONT:
1347 error = do_scalefont();
1348 break;
1349 case SETFONT:
1350 error = do_setfont();
1351 break;
1352 case CURRENTFONT:
1353 error = do_currentfont();
1354 break;
1355
1356 case SHOW:
1357 error = do_show();
1358 break;
1359
1360 case STRINGWIDTH:
1361 error = 1;
1362 break;
1363
1364 /* Extensions */
1365 case FSHOW:
1366 error = do_mpost_bind_def("exch findfont exch scalefont setfont show", x_user, y_user);
1367 break;
1368 case STEXFIG:
1369 case ETEXFIG:
1370 error = do_texfig_operator(opcode, x_user, y_user);
1371 break;
1372 case HLW:
1373 error = do_mpost_bind_def("0 dtransform exch truncate exch idtransform pop setlinewidth", x_user, y_user);
1374 break;
1375 case VLW:
1376 error = do_mpost_bind_def("0 exch dtransform truncate idtransform setlinewidth pop", x_user, y_user);
1377 break;
1378 case RD:
1379 error = do_mpost_bind_def("[] 0 setdash", x_user, y_user);
1380 break;
1381 case B:
1382 error = do_mpost_bind_def("gsave fill grestore", x_user, y_user);
1383 break;
1384
1385 case DEF:
1386 tmp = POP_STACK();
1387 tmp = POP_STACK();
1388 /* do nothing; not implemented yet */
1389 break;
1390
1391 default:
1392 if (is_fontname(token)) {
1393 PUSH(pdf_new_name(token));
1394 } else {
1395 WARN("Unknown token \"%s\"", token);
1396 error = 1;
1397 }
1398 break;
1399 }
1400
1401 return error;
1402 }
1403
1404 /*
1405 * The only sections that need to know x_user and y _user are those
1406 * dealing with texfig.
1407 */
1408 static int
mp_parse_body(const char ** start,const char * end,double x_user,double y_user)1409 mp_parse_body (const char **start, const char *end, double x_user, double y_user)
1410 {
1411 char *token;
1412 pdf_obj *obj;
1413 int error = 0;
1414
1415 skip_white(start, end);
1416 while (*start < end && !error) {
1417 if (isdigit((unsigned char)**start) ||
1418 (*start < end - 1 &&
1419 (**start == '+' || **start == '-' || **start == '.' ))) {
1420 double value;
1421 char *next;
1422
1423 value = strtod(*start, &next);
1424 if (next < end && !strchr("<([{/%", *next) && !isspace((unsigned char)*next)) {
1425 WARN("Unkown PostScript operator.");
1426 dump(*start, next);
1427 error = 1;
1428 } else {
1429 PUSH(pdf_new_number(value));
1430 *start = next;
1431 }
1432 /*
1433 * PDF parser can't handle PS operator inside arrays.
1434 * This shouldn't use parse_pdf_array().
1435 */
1436 } else if (**start == '[' &&
1437 (obj = parse_pdf_array(start, end, NULL))) {
1438 PUSH(obj);
1439 /* This cannot handle ASCII85 string. */
1440 } else if (*start < end - 1 &&
1441 (**start == '<' && *(*start+1) == '<') &&
1442 (obj = parse_pdf_dict(start, end, NULL))) {
1443 PUSH(obj);
1444 } else if ((**start == '(' || **start == '<') &&
1445 (obj = parse_pdf_string (start, end))) {
1446 PUSH(obj);
1447 } else if (**start == '/' &&
1448 (obj = parse_pdf_name(start, end))) {
1449 PUSH(obj);
1450 } else {
1451 token = parse_ident(start, end);
1452 if (!token)
1453 error = 1;
1454 else {
1455 error = do_operator(token, x_user, y_user);
1456 RELEASE(token);
1457 }
1458 }
1459 skip_white(start, end);
1460 }
1461
1462 return error;
1463 }
1464
1465 void
mps_eop_cleanup(void)1466 mps_eop_cleanup (void)
1467 {
1468 clear_fonts();
1469 do_clear();
1470 }
1471
1472 int
mps_stack_depth(void)1473 mps_stack_depth (void)
1474 {
1475 return top_stack;
1476 }
1477
1478 int
mps_exec_inline(const char ** p,const char * endptr,double x_user,double y_user)1479 mps_exec_inline (const char **p, const char *endptr,
1480 double x_user, double y_user)
1481 {
1482 int error;
1483 int dirmode, autorotate;
1484
1485 /* Compatibility for dvipsk. */
1486 dirmode = pdf_dev_get_dirmode();
1487 if (dirmode) {
1488 mp_cmode = MP_CMODE_PTEXVERT;
1489 } else {
1490 mp_cmode = MP_CMODE_DVIPSK;
1491 }
1492
1493 autorotate = pdf_dev_get_param(PDF_DEV_PARAM_AUTOROTATE);
1494 pdf_dev_set_param(PDF_DEV_PARAM_AUTOROTATE, 0);
1495 //pdf_color_push(); /* ... */
1496
1497 /* Comment in dvipdfm:
1498 * Remember that x_user and y_user are off by 0.02 %
1499 */
1500 pdf_dev_moveto(x_user, y_user);
1501 error = mp_parse_body(p, endptr, x_user, y_user);
1502
1503 //pdf_color_pop(); /* ... */
1504 pdf_dev_set_param(PDF_DEV_PARAM_AUTOROTATE, autorotate);
1505 pdf_dev_set_dirmode(dirmode);
1506
1507 return error;
1508 }
1509
1510 /* mp inclusion is a bit of a hack. The routine
1511 * starts a form at the lower left corner of
1512 * the page and then calls begin_form_xobj telling
1513 * it to record the image drawn there and bundle it
1514 * up in an xojbect. This allows us to use the coordinates
1515 * in the MP file directly. This appears to be the
1516 * easiest way to be able to use the pdf_dev_set_string()
1517 * command (with its scaled and extended fonts) without
1518 * getting all confused about the coordinate system.
1519 * After the xobject is created, the whole thing can
1520 * be scaled any way the user wants
1521 */
1522
1523 /* Should implement save and restore. */
1524 int
mps_include_page(const char * ident,FILE * fp)1525 mps_include_page (const char *ident, FILE *fp)
1526 {
1527 int form_id;
1528 xform_info info;
1529 int st_depth, gs_depth;
1530 char *buffer;
1531 const char *p, *endptr;
1532 long length, nb_read;
1533 int dirmode, autorotate, error;
1534
1535 rewind(fp);
1536
1537 length = file_size(fp);
1538 if (length < 1) {
1539 WARN("Can't read any byte in the MPS file.");
1540 return -1;
1541 }
1542
1543 buffer = NEW(length + 1, char);
1544 buffer[length] = '\0';
1545 p = buffer;
1546 endptr = p + length;
1547
1548 while (length > 0) {
1549 nb_read = fread(buffer, sizeof(char), length, fp);
1550 if (nb_read < 0) {
1551 RELEASE(buffer);
1552 WARN("Reading file failed...");
1553 return -1;
1554 }
1555 length -= nb_read;
1556 }
1557
1558 error = mps_scan_bbox(&p, endptr, &(info.bbox));
1559 if (error) {
1560 WARN("Error occured while scanning MetaPost file headers: Could not find BoundingBox.");
1561 RELEASE(buffer);
1562 return -1;
1563 }
1564 skip_prolog(&p, endptr);
1565
1566 dirmode = pdf_dev_get_dirmode();
1567 autorotate = pdf_dev_get_param(PDF_DEV_PARAM_AUTOROTATE);
1568 pdf_dev_set_param(PDF_DEV_PARAM_AUTOROTATE, 0);
1569 //pdf_color_push();
1570
1571 form_id = pdf_doc_begin_grabbing(ident, Xorigin, Yorigin, &(info.bbox));
1572
1573 mp_cmode = MP_CMODE_MPOST;
1574 gs_depth = pdf_dev_current_depth();
1575 st_depth = mps_stack_depth();
1576 /* At this point the gstate must be initialized, since it starts a new
1577 * XObject. Note that it increase gs_depth by 1. */
1578 pdf_dev_push_gstate();
1579
1580 error = mp_parse_body(&p, endptr, 0.0, 0.0);
1581 RELEASE(buffer);
1582
1583 if (error) {
1584 WARN("Errors occured while interpreting MPS file.");
1585 /* WARN("Leaving garbage in output PDF file."); */
1586 form_id = -1;
1587 }
1588
1589 /* It's time to pop the new gstate above. */
1590 pdf_dev_pop_gstate();
1591 mps_stack_clear_to (st_depth);
1592 pdf_dev_grestore_to(gs_depth);
1593
1594 pdf_doc_end_grabbing(NULL);
1595
1596 //pdf_color_pop();
1597 pdf_dev_set_param(PDF_DEV_PARAM_AUTOROTATE, autorotate);
1598 pdf_dev_set_dirmode(dirmode);
1599
1600 return form_id;
1601 }
1602
1603 int
mps_do_page(FILE * image_file)1604 mps_do_page (FILE *image_file)
1605 {
1606 int error = 0;
1607 pdf_rect bbox;
1608 char *buffer;
1609 const char *start, *end;
1610 long size;
1611 int dir_mode;
1612
1613 rewind(image_file);
1614 if ((size = file_size(image_file)) == 0) {
1615 WARN("Can't read any byte in the MPS file.");
1616 return -1;
1617 }
1618
1619 buffer = NEW(size+1, char);
1620 fread(buffer, sizeof(char), size, image_file);
1621 buffer[size] = 0;
1622 start = buffer;
1623 end = buffer + size;
1624
1625 error = mps_scan_bbox(&start, end, &bbox);
1626 if (error) {
1627 WARN("Error occured while scanning MetaPost file headers: Could not find BoundingBox.");
1628 RELEASE(buffer);
1629 return -1;
1630 }
1631
1632 mp_cmode = MP_CMODE_MPOST;
1633
1634 pdf_doc_begin_page (1.0, -Xorigin, -Yorigin); /* scale, xorig, yorig */
1635 pdf_doc_set_mediabox(pdf_doc_current_page_number(), &bbox);
1636
1637 dir_mode = pdf_dev_get_dirmode();
1638 pdf_dev_set_autorotate(0);
1639
1640 skip_prolog(&start, end);
1641
1642 error = mp_parse_body(&start, end, 0.0, 0.0);
1643
1644 if (error) {
1645 WARN("Errors occured while interpreting MetaPost file.");
1646 }
1647
1648 pdf_dev_set_autorotate(1);
1649 pdf_dev_set_dirmode(dir_mode);
1650
1651 pdf_doc_end_page();
1652
1653 RELEASE(buffer);
1654
1655 /*
1656 * The reason why we don't return XObject itself is
1657 * PDF inclusion may not be made so.
1658 */
1659 return (error ? -1 : 0);
1660 }
1661
1662 int
check_for_mp(FILE * image_file)1663 check_for_mp (FILE *image_file)
1664 {
1665 int try_count = 10;
1666
1667 rewind (image_file);
1668 mfgets(work_buffer, WORK_BUFFER_SIZE, image_file);
1669 if (strncmp(work_buffer, "%!PS", 4))
1670 return 0;
1671
1672 while (try_count > 0) {
1673 mfgets(work_buffer, WORK_BUFFER_SIZE, image_file);
1674 if (!strncmp(work_buffer, "%%Creator:", 10)) {
1675 if (strlen(work_buffer+10) >= 8 &&
1676 strstr(work_buffer+10, "MetaPost"))
1677 break;
1678 }
1679 try_count--;
1680 }
1681
1682 return ((try_count > 0) ? 1 : 0);
1683 }
1684