~ubuntu-branches/ubuntu/utopic/texlive-bin/utopic

« back to all changes in this revision

Viewing changes to texk/dvipdfmx/dvipdfmx-20110311/src/mpost.c

  • Committer: Package Import Robot
  • Author(s): Norbert Preining
  • Date: 2012-05-07 10:47:49 UTC
  • mfrom: (1.2.4)
  • Revision ID: package-import@ubuntu.com-20120507104749-p00ot5sajjbkp1hp
Tags: 2011.20120507-1
* new upstream checkout: uptex 1.10
* drop patches for config file inclusion in (x)dvipdfmx, included upstream
* add man page for etex
* include pmpost patches and build it
* adapt/unfuzzify patches for current sources
* disable mtx building, we have prepmx package in Debian

Show diffs side-by-side

added added

removed removed

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