OSDN Git Service

updated with TeX Live 2014.
[putex/putex.git] / src / dvipdfmx-pu / src / pdfdraw.c
1 /*  
2     
3     This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
4
5     Copyright (C) 2002-2012 by Jin-Hwan Cho and Shunsaku Hirata,
6     the dvipdfmx project team.
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 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #include <math.h>
30
31 #include "system.h"
32 #include "error.h"
33 #include "mem.h"
34 #include "mfileio.h"
35 #include "dpxutil.h"
36 #include "numbers.h"
37
38 #include "pdfdoc.h"
39 #include "pdfdev.h"
40 #include "pdfcolor.h"
41
42 #include "pdfdraw.h"
43
44 #if 1
45 typedef  void  pdf_dev;
46 #endif
47
48
49 /*
50  * Numbers are rounding to 0-5 fractional digits
51  * in output routine. 
52  */
53 #define detM(M) ((M).a * (M).d - (M).b * (M).c)
54 #define detP(M) ((M)->a * (M)->d - (M)->b * (M)->c)
55
56
57 static /* __inline__ */ int
58 inversematrix (pdf_tmatrix *W, const pdf_tmatrix *M)
59 {
60   double  det;
61
62   det = detP(M);
63   if (fabs(det) < 1.e-8) {
64 #if 1
65     WARN("Inverting matrix with zero determinant...");
66 #endif 
67     return -1; /* result is undefined. */
68   }
69
70   W->a =  (M->d) / det;  W->b = -(M->b) / det;
71   W->c = -(M->c) / det;  W->d =  (M->a) / det;
72   W->e =  (M->c) * (M->f) - (M->d) * (M->e);
73   W->f =  (M->b) * (M->e) - (M->a) * (M->f);
74
75   return 0;
76 }
77
78 /* pdf_coord as vector */
79 #define vecprd(v,w) ((v).x * (w).x + (v).y * (w).y)
80 #define vecrot(v,w) ((v).x * (w).y - (v).y * (w).x)
81 #define dsign(v)    (((v) >= 0.0) ? 1.0 : -1.0)
82 /* acos => [0, pi] */
83 #define vecang(v,w) ( \
84   dsign(vecrot((v),(w))) * \
85     acos(vecprd((v),(w)) / sqrt(vecprd((v),(v)) * vecprd((w),(w)))) \
86 )
87
88 static /* __inline__ */ int
89 pdf_coord__equal (const pdf_coord *p1, const pdf_coord *p2)
90 {
91   if (fabs(p1->x - p2->x) < 1.e-7 &&
92       fabs(p1->y - p2->y) < 1.e-7)
93     return 1;
94   return 0;
95 }
96 #define COORD_EQUAL(p,q) pdf_coord__equal((p),(q))
97
98 #if 0
99 static int
100 pdf_coord__sort_compar_X (const void *pp1, const void *pp2)
101 {
102   pdf_coord *p1 = (pdf_coord *)pp1;
103   pdf_coord *p2 = (pdf_coord *)pp2;
104
105   if (pdf_coord__equal(p1, p2))
106     return 0;
107   else
108     return (int) dsign(p1->x - p2->x);
109  
110   return 1;
111 }
112
113 static int
114 pdf_coord__sort_compar_Y (const void *pp1, const void *pp2)
115 {
116   pdf_coord *p1 = (pdf_coord *)pp1;
117   pdf_coord *p2 = (pdf_coord *)pp2;
118
119   if (pdf_coord__equal(p1, p2))
120     return 0;
121   else
122     return (int) dsign(p1->y - p2->y);
123  
124   return 1;
125 }
126 #endif
127
128
129 static /* __inline__ */ int
130 pdf_coord__transform (pdf_coord *p, const pdf_tmatrix *M)
131 {
132   double x, y;
133
134   x = p->x; y = p->y;
135   p->x = x * M->a + y * M->c + M->e;
136   p->y = x * M->b + y * M->d + M->f;
137
138   return 0;
139 }
140
141 #if 0
142 static /* __inline__ */ int
143 pdf_coord__itransform (pdf_coord *p, const pdf_tmatrix *M)
144 {
145   pdf_tmatrix W;  
146   double      x, y;
147   int         error;
148
149   error = inversematrix(&W, M);
150   if (error) 
151     return error;
152
153   x = p->x;  y = p->y;
154   p->x = x * W.a + y * W.c + W.e;
155   p->y = x * W.b + y * W.d + W.f;  
156
157   return 0;
158 }
159 #endif
160
161 static /* __inline__ */ int
162 pdf_coord__dtransform (pdf_coord *p, const pdf_tmatrix *M)
163 {
164   double x, y;
165
166   x = p->x; y = p->y;
167   p->x = x * M->a + y * M->c;
168   p->y = x * M->b + y * M->d;
169
170   return 0;
171 }
172
173 static /* __inline__ */ int
174 pdf_coord__idtransform (pdf_coord *p, const pdf_tmatrix *M)
175 {
176   pdf_tmatrix W;  
177   double      x, y;
178   int         error;
179
180   error = inversematrix(&W, M);
181   if (error) 
182     return error;
183
184   x = p->x;  y = p->y;
185   p->x = x * W.a + y * W.c;
186   p->y = x * W.b + y * W.d;
187
188   return 0;
189 }
190
191
192 /* Modify M itself */
193 void
194 pdf_invertmatrix (pdf_tmatrix *M)
195 {
196   pdf_tmatrix W;  
197   double      det;
198
199   ASSERT(M);
200
201   det = detP(M);
202   if (fabs(det) < 1.e-8) {
203     WARN("Inverting matrix with zero determinant...");
204     W.a = 1.0; W.c = 0.0;
205     W.b = 0.0; W.d = 1.0;
206     W.e = 0.0; W.f = 0.0;
207   } else {
208     W.a =  (M->d) / det;  W.b = -(M->b) / det;
209     W.c = -(M->c) / det;  W.d =  (M->a) / det;
210     W.e =  (M->c) * (M->f) - (M->d) * (M->e);
211     W.f =  (M->b) * (M->e) - (M->a) * (M->f);
212   }
213
214   pdf_copymatrix(M, &W);
215
216   return;
217 }
218
219
220 typedef struct pa_elem_
221 {
222   int       type;
223   pdf_coord p[3];
224 } pa_elem;
225
226 /* each subpath delimitted by moveto */
227 struct pdf_path_
228 {
229   int       num_paths;
230   int       max_paths;
231   pa_elem  *path;
232 };
233
234 static const struct {
235   char        opchr;  /* PDF operator char  */
236   int         n_pts;  /* number of *points* */
237   const char *strkey;
238 } petypes[] = {
239 #define PE_TYPE__INVALID  -1
240 #define PE_TYPE__MOVETO    0
241   {'m', 1, "moveto"  },
242 #define PE_TYPE__LINETO    1 
243   {'l', 1, "lineto"  },
244 #define PE_TYPE__CURVETO   2 
245   {'c', 3, "curveto" },
246   /* no PS correspondence for v and y */
247 #define PE_TYPE__CURVETO_V 3 
248   {'v', 2, "vcurveto"}, /* current point replicated */
249 #define PE_TYPE__CURVETO_Y 4 
250   {'y', 2, "ycurveto"}, /* last point replicated */
251 #define PE_TYPE__CLOSEPATH 5
252   {'h', 0, "closepath"}, 
253 #define PE_TYPE__TERMINATE 6
254   {' ', 0,  NULL}
255 };
256
257 #define PE_VALID(p) ((p) && \
258   (p)->type > PE_TYPE__INVALID && (p)->type < PE_TYPE__TERMINATE)
259 #define PE_N_PTS(p)  (PE_VALID((p)) ? petypes[(p)->type].n_pts : 0)
260 #define PE_OPCHR(p)  (PE_VALID((p)) ? petypes[(p)->type].opchr : ' ')
261
262 #define PA_LENGTH(pa) ((pa)->num_paths)
263
264 #define GS_FLAG_CURRENTPOINT_SET (1 << 0)
265
266
267 static char    fmt_buf[1024]; /* FIXME */
268 #define FORMAT_BUFF_PTR(p) fmt_buf
269 #define FORMAT_BUFF_LEN(p) 1024
270
271 static void
272 init_a_path (pdf_path *p)
273 {
274   ASSERT(p);
275
276   p->num_paths = 0;
277   p->max_paths = 0;
278   p->path      = NULL;
279
280   return;
281 }
282
283 static void
284 pdf_path__clearpath (pdf_path *p)
285 {
286   ASSERT(p);
287
288   p->num_paths = 0;
289   
290   return;
291 }
292
293 static int
294 pdf_path__growpath  (pdf_path *p, int max_pe)
295 {
296   if (max_pe < p->max_paths)
297     return 0;
298
299   p->max_paths = MAX(p->max_paths + 8, max_pe);
300   p->path = RENEW(p->path, p->max_paths, pa_elem);
301
302   return 0;
303 }
304     
305 static void
306 clear_a_path (pdf_path *p)
307 {
308   ASSERT(p);
309
310   if (p->path)
311     RELEASE(p->path);
312   p->path = NULL;
313   p->num_paths = 0;
314   p->max_paths = 0;
315
316   return;
317 }
318
319 static int
320 pdf_path__copypath (pdf_path *p1, const pdf_path *p0)
321 {
322   pa_elem  *pe0, *pe1;
323   int       i;
324
325   pdf_path__growpath(p1, PA_LENGTH(p0));
326   for (i = 0; i < PA_LENGTH(p0); i++) {
327     pe1 = &(p1->path[i]);
328     pe0 = &(p0->path[i]);
329     /* FIXME */
330     pe1->type   = pe0->type;
331     pe1->p[0].x = pe0->p[0].x;
332     pe1->p[0].y = pe0->p[0].y;
333     pe1->p[1].x = pe0->p[1].x;
334     pe1->p[1].y = pe0->p[1].y;
335     pe1->p[2].x = pe0->p[2].x;
336     pe1->p[2].y = pe0->p[2].y;
337   }
338   p1->num_paths = PA_LENGTH(p0);
339
340   return 0;
341 }
342
343
344 /* start new subpath */
345 static int
346 pdf_path__moveto  (pdf_path        *pa,
347                    pdf_coord       *cp,
348                    const pdf_coord *p0)
349 {
350   pa_elem  *pe;
351   
352   pdf_path__growpath(pa, PA_LENGTH(pa) + 1);
353   if (PA_LENGTH(pa) > 0) {
354     pe = &pa->path[pa->num_paths-1];
355     if (pe->type == PE_TYPE__MOVETO) {
356       pe->p[0].x = cp->x = p0->x;
357       pe->p[0].y = cp->y = p0->y;
358       return 0;
359     }
360   }
361   pe = &pa->path[pa->num_paths++];
362   pe->type   = PE_TYPE__MOVETO;
363   pe->p[0].x = cp->x = p0->x;
364   pe->p[0].y = cp->y = p0->y;
365
366   return 0;  
367 }
368
369 /* Do 'compression' of path while adding new path elements.
370  * Sequantial moveto command will be replaced with a
371  * single moveto. If cp is not equal to the last point in pa,
372  * then moveto is inserted (starting new subpath).
373  * FIXME: 
374  * 'moveto' must be used to enforce starting new path.
375  * This affects how 'closepath' is treated.     
376  */
377 static pa_elem *
378 pdf_path__next_pe (pdf_path *pa, const pdf_coord *cp)
379 {
380   pa_elem  *pe;
381
382   pdf_path__growpath(pa, PA_LENGTH(pa) + 2);
383   if (PA_LENGTH(pa) == 0) {
384     pe = &pa->path[pa->num_paths++];
385     pe->type   = PE_TYPE__MOVETO;
386     pe->p[0].x = cp->x;
387     pe->p[0].y = cp->y;
388
389     return &pa->path[pa->num_paths++];
390   }
391     
392   pe = &pa->path[pa->num_paths-1];
393   switch (pe->type) {
394   case PE_TYPE__MOVETO:
395     pe->p[0].x = cp->x;
396     pe->p[0].y = cp->y;
397     break;
398   case PE_TYPE__LINETO:
399     if (!COORD_EQUAL(&pe->p[0], cp)) {
400       pe = &pa->path[pa->num_paths++];
401       pe->type   = PE_TYPE__MOVETO;
402       pe->p[0].x = cp->x;
403       pe->p[0].y = cp->y;
404     }
405     break;
406   case PE_TYPE__CURVETO:
407     if (!COORD_EQUAL(&pe->p[2], cp)) {
408       pe = &pa->path[pa->num_paths++];
409       pe->type   = PE_TYPE__MOVETO;
410       pe->p[0].x = cp->x;
411       pe->p[0].y = cp->y;
412     }
413     break;
414   case PE_TYPE__CURVETO_Y:
415   case PE_TYPE__CURVETO_V:
416     if (!COORD_EQUAL(&pe->p[1], cp)) {
417       pe = &pa->path[pa->num_paths++];
418       pe->type   = PE_TYPE__MOVETO;
419       pe->p[0].x = cp->x;
420       pe->p[0].y = cp->y;
421     }
422     break;
423   case PE_TYPE__CLOSEPATH:
424     pe = &pa->path[pa->num_paths++];
425     pe->type   = PE_TYPE__MOVETO;
426     pe->p[0].x = cp->x;
427     pe->p[0].y = cp->y;
428     break;
429   }
430
431   return &pa->path[pa->num_paths++];
432 }
433
434 static int
435 pdf_path__transform (pdf_path *pa, const pdf_tmatrix *M)
436 {
437   pa_elem *pe;
438   int      n = 0, i;
439
440   ASSERT(pa && M);
441
442   for (i = 0; i < PA_LENGTH(pa); i++) {
443     pe = &(pa->path[i]);
444     n  = PE_N_PTS(pe);
445     while (n-- > 0)
446       pdf_coord__transform(&(pe->p[n]), M);
447   }
448
449   return 0;
450 }
451
452
453 /* Path Construction */
454 static int
455 pdf_path__lineto (pdf_path        *pa,
456                   pdf_coord       *cp,
457                   const pdf_coord *p0)
458 {
459   pa_elem  *pe;
460
461   pe = pdf_path__next_pe(pa, cp);
462   pe->type   = PE_TYPE__LINETO;
463   pe->p[0].x = cp->x = p0->x;
464   pe->p[0].y = cp->y = p0->y;
465
466   return 0;
467 }
468
469 static int
470 pdf_path__curveto (pdf_path        *pa,
471                    pdf_coord       *cp,
472                    const pdf_coord *p0,
473                    const pdf_coord *p1,
474                    const pdf_coord *p2
475                   )
476 {
477   pa_elem *pe;
478
479   pe = pdf_path__next_pe(pa, cp);
480   if (COORD_EQUAL(cp, p0)) {
481     pe->type   = PE_TYPE__CURVETO_V;
482     pe->p[0].x = p1->x;
483     pe->p[0].y = p1->y;
484     pe->p[1].x = cp->x = p2->x;
485     pe->p[1].y = cp->y = p2->y;
486   } else if (COORD_EQUAL(p1, p2)) {
487     pe->type   = PE_TYPE__CURVETO_Y;
488     pe->p[0].x = p0->x;
489     pe->p[0].y = p0->y;
490     pe->p[1].x = cp->x = p1->x;
491     pe->p[1].y = cp->y = p1->y;
492   } else {
493     pe->type   = PE_TYPE__CURVETO;
494     pe->p[0].x = p0->x;
495     pe->p[0].y = p0->y;
496     pe->p[1].x = p1->x;
497     pe->p[1].y = p1->y;
498     pe->p[2].x = cp->x = p2->x;
499     pe->p[2].y = cp->y = p2->y;
500   }
501
502   return 0;
503 }
504
505 #if 0
506 #define QB_TWO_THIRD (2.0/3.0)
507 #define QB_ONE_THIRD (1.0/3.0)
508
509 static int
510 pdf_path__curveto_QB (pdf_path        *pa,
511                       pdf_coord       *cp,
512                       const pdf_coord *p0,
513                       const pdf_coord *p1
514                      )
515 {
516   pdf_coord  q0, q1;
517
518   q0.x = cp->x + QB_TWO_THIRD * (p0->x - cp->x);
519   q0.y = cp->y + QB_TWO_THIRD * (p0->y - cp->y);
520   q1.x = p0->x + QB_ONE_THIRD * (p1->x - p0->x);
521   q1.y = p0->y + QB_ONE_THIRD * (p1->y - p0->y);
522   /* q2 == p1 */
523  
524   return pdf_path__curveto(pa, cp, &q0, &q1, p1);
525 }
526 #endif
527
528
529 /* This isn't specified as cp to somewhere. */
530 static int
531 pdf_path__elliptarc (pdf_path         *pa,
532                      pdf_coord        *cp,
533                      const pdf_coord  *ca,   /* ellipsis center        */
534                      double            r_x,  /* x radius               */
535                      double            r_y,  /* y radius               */
536                      double            xar,  /* x-axis-rotation (deg!) */
537                      double            a_0,  /* start angle            */
538                      double            a_1,  /* stop angle             */
539                      int               a_d   /* arc orientation        */
540                     )
541 {
542   double      b, b_x, b_y;
543   double      d_a, q;
544   pdf_coord   p0, p1, p2, p3;
545   pdf_coord   e0, e1;
546   pdf_tmatrix T;
547   int         n_c; /* number of segments */
548   int         i, error = 0;
549
550   if (fabs(r_x) < 1.e-8 ||
551       fabs(r_y) < 1.e-8)
552     return -1;
553
554   if (a_d < 0) {
555     for ( ; a_1 > a_0; a_1 -= 360.0);
556   } else {
557     for ( ; a_1 < a_0; a_0 -= 360.0);
558   }
559
560   d_a  = a_1 - a_0;
561   for (n_c = 1; fabs(d_a) > 90.0 * n_c; n_c++);
562   d_a /= n_c;
563   if (fabs(d_a) < 1.e-8)
564     return -1;
565
566   a_0 *= M_PI / 180.0;
567   a_1 *= M_PI / 180.0;
568   d_a *= M_PI / 180.0;
569   xar *= M_PI / 180.0;
570   T.a  = cos(xar);  T.c = -sin(xar);
571   T.b  = -T.c    ;  T.d = T.a;
572   T.e  = 0.0     ;  T.f = 0.0;
573
574   /* A parameter that controls cb-curve (off-curve) points */
575   b    = 4.0 * (1.0 - cos(.5 * d_a)) / (3.0 * sin(.5 * d_a));
576   b_x  = r_x * b;
577   b_y  = r_y * b;
578
579   p0.x = r_x * cos(a_0);
580   p0.y = r_y * sin(a_0);
581   pdf_coord__transform(&p0, &T);
582   p0.x += ca->x; p0.y += ca->y;
583   if (PA_LENGTH(pa) == 0) {
584     pdf_path__moveto(pa, cp, &p0);
585   } else if (!COORD_EQUAL(cp, &p0)) {
586     pdf_path__lineto(pa, cp, &p0); /* add line seg */
587   } 
588   for (i = 0; !error && i < n_c; i++) {
589     q = a_0 + i * d_a;
590     e0.x = cos(q); e0.y = sin(q);
591     e1.x = cos(q + d_a); e1.y = sin(q + d_a);
592
593    /* Condition for tangent vector requirs
594     *  d1 = p1 - p0 = f ( sin a, -cos a)
595     *  d2 = p2 - p3 = g ( sin b, -cos b)
596     * and from symmetry
597     *  g^2 = f^2
598     */ 
599     p0.x = r_x * e0.x; /* s.p. */
600     p0.y = r_y * e0.y;
601     p3.x = r_x * e1.x; /* e.p. */
602     p3.y = r_y * e1.y;
603
604     p1.x = -b_x * e0.y;
605     p1.y =  b_y * e0.x;
606     p2.x =  b_x * e1.y;
607     p2.y = -b_y * e1.x;
608
609     pdf_coord__transform(&p0, &T);
610     pdf_coord__transform(&p1, &T);
611     pdf_coord__transform(&p2, &T);
612     pdf_coord__transform(&p3, &T);
613     p0.x += ca->x; p0.y += ca->y;
614     p3.x += ca->x; p3.y += ca->y;
615     p1.x += p0.x ; p1.y += p0.y ;
616     p2.x += p3.x ; p2.y += p3.y ;
617
618     error = pdf_path__curveto(pa, &p0, &p1, &p2, &p3);
619     cp->x = p3.x; cp->y = p3.y;
620   }
621
622   return error;
623 }
624
625 static int
626 pdf_path__closepath (pdf_path *pa, pdf_coord *cp /* no arg */)
627 {
628   pa_elem  *pe = NULL;
629   int       i;
630
631   /* search for start point of the last subpath */
632   for (i = PA_LENGTH(pa) - 1; i >= 0; i--) {
633     pe = &pa->path[i];
634     if (pe->type == PE_TYPE__MOVETO)
635       break;
636   }
637
638   if (!pe || i < 0)
639     return -1; /* No path or no start point(!) */
640
641   cp->x = pe->p[0].x;
642   cp->y = pe->p[0].y;
643
644   pdf_path__growpath(pa, PA_LENGTH(pa) + 1);
645
646   /* NOTE:
647    *  Manually closed path without closepath is not
648    *  affected by linejoin. A path with coincidental
649    *  starting and ending point is not the same as
650    *  'closed' path.
651    */
652   pe = &pa->path[pa->num_paths++];
653   pe->type = PE_TYPE__CLOSEPATH;
654
655   return 0;
656 }
657
658 /*
659  *  x y width height re
660  * 
661  * is equivalent to
662  *
663  *  x y m
664  *  (x + width) y l
665  *  (x + width) (y + height) l
666  *  x (y + height) l
667  *  h
668  */
669 /* Just for quick test */ 
670 static /* __inline__ */ int
671 pdf_path__isarect (pdf_path *pa,
672                    int       f_ir /* fill-rule is ignorable */
673                   )
674 {
675   pa_elem *pe0, *pe1, *pe2, *pe3, *pe4;
676
677   if (PA_LENGTH(pa) == 5) {
678     pe0 = &(pa->path[0]);
679     pe1 = &(pa->path[1]);
680     pe2 = &(pa->path[2]);
681     pe3 = &(pa->path[3]);
682     pe4 = &(pa->path[4]);
683     if (pe0->type == PE_TYPE__MOVETO &&
684         pe1->type == PE_TYPE__LINETO &&
685         pe2->type == PE_TYPE__LINETO &&
686         pe3->type == PE_TYPE__LINETO &&
687         pe4->type == PE_TYPE__CLOSEPATH) {
688       if (pe1->p[0].y - pe0->p[0].y == 0 &&
689           pe2->p[0].x - pe1->p[0].x == 0 &&
690           pe3->p[0].y - pe2->p[0].y == 0) {
691         if (pe1->p[0].x - pe0->p[0].x
692             == pe2->p[0].x - pe3->p[0].x) {
693           return 1;
694         }
695     /* Winding number is different but ignore it here. */
696       } else if (f_ir &&
697                  pe1->p[0].x - pe0->p[0].x == 0 &&
698                  pe2->p[0].y - pe1->p[0].y == 0 &&
699                  pe3->p[0].x - pe2->p[0].x == 0) {
700         if (pe1->p[0].y - pe0->p[0].y
701               == pe2->p[0].y - pe3->p[0].y) {
702           return 1;
703         }
704       }
705     }
706   }
707
708   return 0;
709 }
710
711 /* Path Painting */
712 /* F is obsoleted */
713 #define PT_OP_VALID(c) ( \
714  (c) == 'f' || (c) == 'F' || \
715  (c) == 's' || (c) == 'S' || \
716  (c) == 'b' || (c) == 'B' || \
717  (c) == 'W' \
718 )
719
720 static /* __inline__ */ int
721 INVERTIBLE_MATRIX (const pdf_tmatrix *M)
722 {
723   if (fabs(detP(M)) < 1.e-8) {
724     WARN("Transformation matrix not invertible.");
725     WARN("--- M = [%g %g %g %g %g %g]",
726          M->a, M->b, M->c, M->d, M->e, M->f);
727     return -1;
728   }
729   return 0;
730 }
731
732 /* rectfill, rectstroke, rectclip, recteoclip
733  *
734  * Draw isolated rectangle without actually doing
735  * gsave/grestore operation.
736  * 
737  * TODO:
738  *  linestyle, fill-opacity, stroke-opacity,....
739  *  As this routine draw a single graphics object
740  *  each time, there should be options for specifying
741  *  various drawing styles, which might inherite
742  *  current graphcs state parameter.
743  */ 
744 static int
745 pdf_dev__rectshape (pdf_dev           *P,
746                     const pdf_rect    *r,
747                     const pdf_tmatrix *M,
748                     char               opchr
749                    )
750 {
751   char     *buf = FORMAT_BUFF_PTR(P);
752   int       len = 0;
753   int       isclip = 0;
754   pdf_coord p;
755   double    wd, ht;
756
757   ASSERT(r && PT_OP_VALID(opchr));
758
759   isclip = (opchr == 'W') ? 1 : 0;
760
761   /* disallow matrix for clipping.
762    * q ... clip Q does nothing and
763    * n M cm ... clip n alter CTM.
764    */
765   if (M && (isclip ||
766             !INVERTIBLE_MATRIX(M)))
767     return -1;
768
769   graphics_mode();
770
771   buf[len++] = ' ';
772   if (!isclip) {
773     buf[len++] = 'q';
774     if (M) {
775       buf[len++] = ' ';
776       len += pdf_sprint_matrix(buf + len, M);
777       buf[len++] = ' ';
778       buf[len++] = 'c'; buf[len++] = 'm';
779     }
780     buf[len++] = ' ';
781   }
782   buf[len++] = 'n';
783
784   p.x = r->llx; p.y = r->lly;
785   wd  = r->urx - r->llx;
786   ht  = r->ury - r->lly;
787   buf[len++] = ' ';
788   len += pdf_sprint_coord (buf + len, &p);
789   buf[len++] = ' ';
790   len += pdf_sprint_length(buf + len, wd);
791   buf[len++] = ' ';
792   len += pdf_sprint_length(buf + len, ht);
793   buf[len++] = ' ';
794   buf[len++] = 'r'; buf[len++] = 'e';
795
796   buf[len++] = ' ';
797   buf[len++] = opchr;
798
799   buf[len++] = ' ';
800   buf[len++] = isclip ? 'n' : 'Q';
801
802   pdf_doc_add_page_content(buf, len);  /* op: q cm n re Q */
803
804   return 0;
805 }
806
807 /* FIXME */
808 static int
809 pdf_dev__flushpath (pdf_dev   *P,
810                     pdf_path  *pa,
811                     char       opchr,
812                     int        rule,
813                     int        ignore_rule)
814 {
815   pa_elem   *pe, *pe1;
816   char      *b      = FORMAT_BUFF_PTR(P);
817   long       b_len  = FORMAT_BUFF_LEN(P);
818   pdf_rect   r; /* FIXME */
819   pdf_coord *pt;
820   int        n_pts, n_seg;
821   int        len = 0;
822   int        isrect, i, j;
823
824   ASSERT(pa && PT_OP_VALID(opchr));
825
826   if (PA_LENGTH(pa) <= 0)
827     return 0;
828
829   graphics_mode();
830   isrect = pdf_path__isarect(pa, ignore_rule); 
831   if (isrect) {
832     pe  = &(pa->path[0]);
833     pe1 = &(pa->path[2]);
834
835     r.llx = pe->p[0].x;
836     r.lly = pe->p[0].y;
837     r.urx = pe1->p[0].x - pe->p[0].x; /* width...  */
838     r.ury = pe1->p[0].y - pe->p[0].y; /* height... */
839
840     b[len++] = ' ';
841     len += pdf_sprint_rect(b + len, &r);
842     b[len++] = ' ';
843     b[len++] = 'r';
844     b[len++] = 'e';
845     pdf_doc_add_page_content(b, len);  /* op: re */
846     len = 0;
847   } else {
848     n_seg = PA_LENGTH(pa);
849     for (i = 0, len = 0, pe = &pa->path[0];
850          i < n_seg; pe++, i++) {
851       n_pts = PE_N_PTS(pe);
852       for (j = 0, pt = &pe->p[0];
853            j < n_pts; j++, pt++) {
854         b[len++] = ' ';
855         len += pdf_sprint_coord(b + len, pt);
856       }
857       b[len++] = ' ';
858       b[len++] = PE_OPCHR(pe);
859       if (len + 128 > b_len) {
860         pdf_doc_add_page_content(b, len);  /* op: m l c v y h */
861         len = 0;
862       }
863     }
864     if (len > 0) {
865       pdf_doc_add_page_content(b, len);  /* op: m l c v y h */
866       len = 0;
867     }
868   }
869
870   b[len++] = ' ';
871   b[len++] = opchr;
872   if (rule == PDF_FILL_RULE_EVENODD)
873     b[len++] = '*';
874
875   pdf_doc_add_page_content(b, len);  /* op: f F s S b B W f* F* s* S* b* B* W* */
876
877   return 0;
878 }
879
880
881 /* Graphics State */
882 typedef struct pdf_gstate_
883 {
884   pdf_coord   cp;
885
886   pdf_tmatrix matrix;   /* cm,  - */
887
888   pdf_color   strokecolor;
889   pdf_color   fillcolor;
890   /* colorspace here */
891
892   struct {
893     int     num_dash;
894     double  pattern[PDF_DASH_SIZE_MAX];
895     double  offset;
896   } linedash;           /* d,  D  */
897
898   double    linewidth;  /* w,  LW */
899
900   int       linecap;    /* J,  LC */
901   int       linejoin;   /* j,  LJ */
902   double    miterlimit; /* M,  ML */
903
904   int       flatness;   /* i,  FL, 0 to 100 (0 for use device-default) */
905
906   /* internal */
907   pdf_path  path;
908   long      flags;
909 } pdf_gstate;
910
911
912 typedef struct m_stack_elem
913 {
914   void                *data;
915   struct m_stack_elem *prev;
916 } m_stack_elem;
917
918 typedef struct m_stack
919 {
920   int           size;
921   m_stack_elem *top;
922   m_stack_elem *bottom;
923 } m_stack;
924
925 static void
926 m_stack_init (m_stack *stack)
927 {
928   ASSERT(stack);
929
930   stack->size   = 0;
931   stack->top    = NULL;
932   stack->bottom = NULL;
933
934   return;
935 }
936
937 static void
938 m_stack_push (m_stack *stack, void *data)
939 {
940   m_stack_elem  *elem;
941
942   ASSERT(stack);
943
944   elem = NEW(1, m_stack_elem);
945   elem->prev = stack->top;
946   elem->data = data;
947
948   stack->top = elem;
949   if (stack->size == 0)
950     stack->bottom = elem;
951
952   stack->size++;
953
954   return;
955 }
956
957 static void *
958 m_stack_pop (m_stack *stack)
959 {
960   m_stack_elem *elem;
961   void         *data;
962
963   ASSERT(stack);
964
965   if (stack->size == 0)
966     return NULL;
967
968   data = stack->top->data;
969   elem = stack->top;
970   stack->top = elem->prev;
971   if (stack->size == 1)
972     stack->bottom = NULL;
973   RELEASE(elem);
974
975   stack->size--;
976
977   return data;
978 }
979
980 static void *
981 m_stack_top (m_stack *stack)
982 {
983   void  *data;
984
985   ASSERT(stack);
986
987   if (stack->size == 0)
988     return NULL;
989
990   data = stack->top->data;
991
992   return data;
993 }
994
995 #define m_stack_depth(s)    ((s)->size)
996
997 static m_stack gs_stack;
998
999 static void
1000 init_a_gstate (pdf_gstate *gs)
1001 {
1002   gs->cp.x = 0.0;
1003   gs->cp.y = 0.0;
1004
1005   pdf_setmatrix(&gs->matrix, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
1006
1007   pdf_color_black(&gs->strokecolor);
1008   pdf_color_black(&gs->fillcolor);
1009
1010   gs->linedash.num_dash = 0;
1011   gs->linedash.offset   = 0;
1012   gs->linecap    = 0;
1013   gs->linejoin   = 0;
1014   gs->linewidth  = 1.0;
1015   gs->miterlimit = 10.0;
1016
1017   gs->flatness   = 1; /* default to 1 in PDF */
1018
1019   /* Internal variables */
1020   gs->flags = 0;
1021   init_a_path(&gs->path);
1022
1023   return;
1024 }
1025
1026 static void
1027 clear_a_gstate (pdf_gstate *gs)
1028 {
1029   clear_a_path(&gs->path);
1030   memset(gs, 0, sizeof(pdf_gstate));
1031
1032   return;
1033 }
1034
1035 static void
1036 copy_a_gstate (pdf_gstate *gs1, pdf_gstate *gs2)
1037 {
1038   int   i;
1039
1040   ASSERT(gs1 && gs2);
1041
1042   gs1->cp.x = gs2->cp.x;
1043   gs1->cp.y = gs2->cp.y;
1044
1045   pdf_copymatrix(&gs1->matrix, &gs2->matrix);
1046
1047   /* TODO:
1048    * Path should be linked list and gsave only
1049    * record starting point within path rather than
1050    * copying whole path.
1051    */
1052   pdf_path__copypath(&gs1->path, &gs2->path);
1053
1054   gs1->linedash.num_dash = gs2->linedash.num_dash;
1055   for (i = 0; i < gs2->linedash.num_dash; i++) {
1056     gs1->linedash.pattern[i] = gs2->linedash.pattern[i];
1057   }
1058   gs1->linedash.offset = gs2->linedash.offset;
1059
1060   gs1->linecap    = gs2->linecap;
1061   gs1->linejoin   = gs2->linejoin;
1062   gs1->linewidth  = gs2->linewidth;
1063   gs1->miterlimit = gs2->miterlimit;
1064   gs1->flatness   = gs2->flatness;
1065
1066   pdf_color_copycolor(&gs1->fillcolor  , &gs2->fillcolor);
1067   pdf_color_copycolor(&gs1->strokecolor, &gs2->strokecolor);
1068
1069   return;
1070 }
1071     
1072 void
1073 pdf_dev_init_gstates (void)
1074 {
1075   pdf_gstate *gs;
1076
1077   m_stack_init(&gs_stack);
1078
1079   gs = NEW(1, pdf_gstate);
1080   init_a_gstate(gs);
1081
1082   m_stack_push(&gs_stack, gs); /* Initial state */
1083
1084   return;
1085 }
1086
1087 void
1088 pdf_dev_clear_gstates (void)
1089 {
1090   pdf_gstate *gs;
1091
1092   if (m_stack_depth(&gs_stack) > 1) /* at least 1 elem. */
1093     WARN("GS stack depth is not zero at the end of the document.");
1094
1095   while ((gs = m_stack_pop(&gs_stack)) != NULL) {
1096     clear_a_gstate(gs);
1097     RELEASE(gs);
1098   }
1099   return;
1100 }
1101
1102 int
1103 pdf_dev_gsave (void)
1104 {
1105   pdf_gstate *gs0, *gs1;
1106
1107   gs0 = m_stack_top(&gs_stack);
1108   gs1 = NEW(1, pdf_gstate);
1109   init_a_gstate(gs1);
1110   copy_a_gstate(gs1, gs0);
1111   m_stack_push(&gs_stack, gs1);
1112
1113   pdf_doc_add_page_content(" q", 2);  /* op: q */
1114
1115   return 0;
1116 }
1117
1118 int
1119 pdf_dev_grestore (void)
1120 {
1121   pdf_gstate *gs;
1122
1123   if (m_stack_depth(&gs_stack) <= 1) { /* Initial state at bottom */
1124     WARN("Too many grestores.");
1125     return  -1;
1126   }
1127
1128   gs = m_stack_pop(&gs_stack);
1129   clear_a_gstate(gs);
1130   RELEASE(gs);
1131
1132   pdf_doc_add_page_content(" Q", 2);  /* op: Q */
1133
1134   pdf_dev_reset_fonts();
1135
1136   return  0;
1137 }
1138
1139
1140 int
1141 pdf_dev_push_gstate (void)
1142 {
1143   m_stack    *gss = &gs_stack;
1144   pdf_gstate *gs0;
1145
1146   gs0 = NEW(1, pdf_gstate);
1147
1148   init_a_gstate(gs0);
1149
1150   m_stack_push(gss, gs0);
1151
1152   return 0;
1153 }
1154
1155
1156 int
1157 pdf_dev_pop_gstate (void)
1158 {
1159   m_stack    *gss = &gs_stack;
1160   pdf_gstate *gs;
1161
1162   if (m_stack_depth(gss) <= 1) { /* Initial state at bottom */
1163     WARN("Too many grestores.");
1164     return  -1;
1165   }
1166
1167   gs = m_stack_pop(gss);
1168   clear_a_gstate(gs);
1169   RELEASE(gs);
1170
1171   return  0;
1172 }
1173
1174
1175 int
1176 pdf_dev_current_depth (void)
1177 {
1178   return (m_stack_depth(&gs_stack) - 1); /* 0 means initial state */
1179 }
1180
1181 void
1182 pdf_dev_grestore_to (int depth)
1183 {
1184   m_stack    *gss = &gs_stack;
1185   pdf_gstate *gs;
1186
1187   ASSERT(depth >= 0);
1188
1189   if (m_stack_depth(gss) > depth + 1) {
1190     WARN("Closing pending transformations at end of page/XObject.");
1191   }
1192
1193   while (m_stack_depth(gss) > depth + 1) {
1194     pdf_doc_add_page_content(" Q", 2);  /* op: Q */
1195     gs = m_stack_pop(gss);
1196     clear_a_gstate(gs);
1197     RELEASE(gs);
1198   }
1199   pdf_dev_reset_fonts();
1200
1201   return;
1202 }
1203
1204 int
1205 pdf_dev_currentpoint (pdf_coord *p)
1206 {
1207   m_stack    *gss = &gs_stack;
1208   pdf_gstate *gs  = m_stack_top(gss);
1209   pdf_coord  *cpt = &gs->cp;
1210
1211   ASSERT(p);
1212
1213   p->x = cpt->x; p->y = cpt->y;
1214
1215   return 0;
1216 }
1217
1218 int
1219 pdf_dev_currentmatrix (pdf_tmatrix *M)
1220 {
1221   m_stack     *gss = &gs_stack;
1222   pdf_gstate  *gs  = m_stack_top(gss);
1223   pdf_tmatrix *CTM = &gs->matrix;
1224
1225   ASSERT(M);
1226
1227   pdf_copymatrix(M, CTM);
1228
1229   return 0;
1230 }
1231
1232 #if  0
1233 int
1234 pdf_dev_currentcolor (pdf_color *color, int is_fill)
1235 {
1236   m_stack    *gss = &gs_stack;
1237   pdf_gstate *gs  = m_stack_top(gss);
1238   pdf_color  *fcl = &gs->fillcolor;
1239   pdf_color  *scl = &gs->strokecolor;
1240
1241   ASSERT(color);
1242
1243   pdf_color_copycolor(color, is_fill ? fcl : scl);
1244
1245   return 0;
1246 }
1247 #endif /* 0 */
1248
1249 /*
1250  * mask == 0 means stroking color, mask == 0x20 nonstroking color
1251  *
1252  * force == 1 means that operators will be generated even if
1253  *   the color is the same as the current graphics state color
1254  */
1255 void
1256 pdf_dev_set_color (const pdf_color *color, char mask, int force)
1257 {
1258   int len;
1259
1260   pdf_gstate *gs  = m_stack_top(&gs_stack);
1261   pdf_color *current = mask ? &gs->fillcolor : &gs->strokecolor;
1262
1263   ASSERT(pdf_color_is_valid(color));
1264
1265   if (!(pdf_dev_get_param(PDF_DEV_PARAM_COLORMODE) &&
1266         (force || pdf_color_compare(color, current))))
1267     /* If "color" is already the current color, then do nothing
1268      * unless a color operator is forced
1269      */
1270     return;
1271
1272   graphics_mode();
1273   len = pdf_color_to_string(color, fmt_buf);
1274   fmt_buf[len++] = ' ';
1275   switch (pdf_color_type(color)) {
1276   case  PDF_COLORSPACE_TYPE_RGB:
1277     fmt_buf[len++] = 'R' | mask;
1278     fmt_buf[len++] = 'G' | mask;
1279     break;
1280   case  PDF_COLORSPACE_TYPE_CMYK:
1281     fmt_buf[len++] = 'K' | mask;
1282     break;
1283   case  PDF_COLORSPACE_TYPE_GRAY:
1284     fmt_buf[len++] = 'G' | mask;
1285     break;
1286   default: /* already verified the given color */
1287     break;
1288   }
1289   pdf_doc_add_page_content(fmt_buf, len);  /* op: RG K G rg k g */
1290
1291   pdf_color_copycolor(current, color);
1292 }
1293
1294 void
1295 pdf_dev_reset_color (int force)
1296 {
1297   pdf_color *sc, *fc;
1298
1299   pdf_color_get_current(&sc, &fc);
1300   pdf_dev_set_color(sc,    0, force);
1301   pdf_dev_set_color(fc, 0x20, force);
1302 }
1303
1304 int
1305 pdf_dev_concat (const pdf_tmatrix *M)
1306 {
1307   m_stack     *gss = &gs_stack;
1308   pdf_gstate  *gs  = m_stack_top(gss);
1309   pdf_path    *cpa = &gs->path;
1310   pdf_coord   *cpt = &gs->cp;
1311   pdf_tmatrix *CTM = &gs->matrix;
1312   pdf_tmatrix  W   = {0, 0, 0, 0, 0, 0};  /* Init to avoid compiler warning */
1313   char        *buf = FORMAT_BUFF_PTR(NULL);
1314   int          len = 0;
1315
1316   ASSERT(M);
1317
1318   /* Adobe Reader erases page content if there are
1319    * non invertible transformation.
1320    */
1321   if (fabs(detP(M)) < 1.0e-8) {
1322     WARN("Transformation matrix not invertible.");
1323     WARN("--- M = [%g %g %g %g %g %g]",
1324          M->a, M->b, M->c, M->d, M->e, M->f);
1325     return -1;
1326   }
1327
1328   buf[len++] = ' ';
1329   len += pdf_sprint_matrix(buf + len, M);
1330   buf[len++] = ' ';
1331   buf[len++] = 'c';
1332   buf[len++] = 'm';
1333   pdf_doc_add_page_content(buf, len);  /* op: cm */
1334
1335   pdf_concatmatrix(CTM, M);
1336
1337   inversematrix(&W, M);
1338
1339   pdf_path__transform (cpa, &W);
1340   pdf_coord__transform(cpt, &W);
1341
1342   return 0;
1343 }
1344
1345 /*
1346  * num w        LW  linewidth (g.t. 0)
1347  * int J        LC  linecap
1348  * int j        LJ  linejoin
1349  * num M        ML  miter limit (g.t. 0)
1350  * array num d  D   line dash
1351  * int ri       RI  renderint intnet
1352  * int i        FL  flatness tolerance (0-100)
1353  * name gs      --  name: res. name of ExtGState dict.  
1354  */      
1355 int
1356 pdf_dev_setmiterlimit (double mlimit)
1357 {
1358   m_stack    *gss = &gs_stack;
1359   pdf_gstate *gs  = m_stack_top(gss);
1360   int         len = 0;
1361   char       *buf = FORMAT_BUFF_PTR(NULL);
1362
1363   if (gs->miterlimit != mlimit) {
1364     buf[len++] = ' ';
1365     len += pdf_sprint_length(buf + len, mlimit);
1366     buf[len++] = ' ';
1367     buf[len++] = 'M';
1368     pdf_doc_add_page_content(buf, len);  /* op: M */
1369     gs->miterlimit = mlimit;
1370   }
1371
1372   return 0;
1373 }
1374
1375 int
1376 pdf_dev_setlinecap (int capstyle)
1377 {
1378   m_stack    *gss = &gs_stack;
1379   pdf_gstate *gs  = m_stack_top(gss);
1380   int         len = 0;
1381   char       *buf = FORMAT_BUFF_PTR(NULL);
1382
1383   if (gs->linecap != capstyle) {
1384     len = sprintf(buf, " %d J", capstyle);
1385     pdf_doc_add_page_content(buf, len);  /* op: J */
1386     gs->linecap = capstyle;
1387   }
1388
1389   return 0;
1390 }
1391
1392 int
1393 pdf_dev_setlinejoin (int joinstyle)
1394 {
1395   m_stack    *gss = &gs_stack;
1396   pdf_gstate *gs  = m_stack_top(gss);
1397   int         len = 0;
1398   char       *buf = FORMAT_BUFF_PTR(NULL);
1399
1400   if (gs->linejoin != joinstyle) {
1401     len = sprintf(buf, " %d j", joinstyle);
1402     pdf_doc_add_page_content(buf, len);  /* op: j */
1403     gs->linejoin = joinstyle;
1404   }
1405
1406   return 0;
1407 }
1408
1409 int
1410 pdf_dev_setlinewidth (double width)
1411 {
1412   m_stack    *gss = &gs_stack;
1413   pdf_gstate *gs  = m_stack_top(gss);  
1414   int         len = 0;
1415   char       *buf = FORMAT_BUFF_PTR(NULL);
1416
1417   if (gs->linewidth != width) {
1418     buf[len++] = ' ';
1419     len += pdf_sprint_length(buf + len, width);
1420     buf[len++] = ' ';
1421     buf[len++] = 'w';
1422     pdf_doc_add_page_content(buf, len);  /* op: w */
1423     gs->linewidth = width;
1424   }
1425
1426   return 0;
1427 }
1428
1429 int
1430 pdf_dev_setdash (int count, double *pattern, double offset)
1431 {
1432   m_stack    *gss = &gs_stack;
1433   pdf_gstate *gs  = m_stack_top(gss);
1434   int         len = 0;
1435   char       *buf = FORMAT_BUFF_PTR(NULL);
1436   int         i;
1437
1438   gs->linedash.num_dash = count;
1439   gs->linedash.offset   = offset;
1440   pdf_doc_add_page_content(" [", 2);  /* op: */
1441   for (i = 0; i < count; i++) {
1442     buf[0] = ' ';
1443     len = pdf_sprint_length (buf + 1, pattern[i]);
1444     pdf_doc_add_page_content(buf, len + 1);  /* op: */
1445     gs->linedash.pattern[i] = pattern[i];
1446   }
1447   pdf_doc_add_page_content("] ", 2);  /* op: */
1448   len = pdf_sprint_length (buf, offset);
1449   pdf_doc_add_page_content(buf, len);  /* op: */
1450   pdf_doc_add_page_content(" d", 2);  /* op: d */
1451
1452   return 0;
1453 }
1454
1455 #if 0
1456 int
1457 pdf_dev_setflat (int flatness)
1458 {
1459   m_stack    *gss = &gs_stack;
1460   pdf_gstate *gs  = m_stack_top(gss);
1461   int         len = 0;
1462   char       *buf = FORMAT_BUFF_PTR(NULL);
1463
1464   if (flatness < 0 || flatness > 100)
1465     return -1;
1466
1467   if (gs->flatness != flatness) {
1468     gs->flatness = flatness;
1469     len = sprintf(buf, " %d i", flatness);
1470     pdf_doc_add_page_content(buf, len);  /* op: i */
1471   }
1472
1473   return 0;
1474 }
1475 #endif
1476
1477 /* ZSYUEDVEDEOF */
1478 int
1479 pdf_dev_clip (void)
1480 {
1481   m_stack    *gss = &gs_stack;
1482   pdf_gstate *gs  = m_stack_top(gss);
1483   pdf_path   *cpa = &gs->path;
1484
1485   return pdf_dev__flushpath(NULL, cpa, 'W', PDF_FILL_RULE_NONZERO, 0);
1486 }
1487
1488 int
1489 pdf_dev_eoclip (void)
1490 {
1491   m_stack    *gss = &gs_stack;
1492   pdf_gstate *gs  = m_stack_top(gss);
1493   pdf_path   *cpa = &gs->path;
1494
1495   return pdf_dev__flushpath(NULL, cpa, 'W', PDF_FILL_RULE_EVENODD, 0);
1496 }
1497
1498 int
1499 pdf_dev_flushpath (char p_op, int fill_rule)
1500 {
1501   m_stack    *gss   = &gs_stack;
1502   pdf_gstate *gs    = m_stack_top(gss);
1503   pdf_path   *cpa   = &gs->path;
1504   int         error = 0;
1505
1506   /* last arg 'ignore_rule' is only for single object
1507    * that can be converted to a rect where fill rule
1508    * is inessential.
1509    */
1510   error = pdf_dev__flushpath(NULL, cpa, p_op, fill_rule, 1);
1511   pdf_path__clearpath(cpa);
1512
1513   gs->flags &= ~GS_FLAG_CURRENTPOINT_SET;
1514
1515   return error;
1516 }
1517
1518 int
1519 pdf_dev_newpath (void)
1520 {
1521   m_stack    *gss = &gs_stack;
1522   pdf_gstate *gs  = m_stack_top(gss);
1523   pdf_path   *p   = &gs->path;
1524
1525   if (PA_LENGTH(p) > 0) {
1526     pdf_path__clearpath (p);
1527   }
1528   /* The following is required for "newpath" operator in mpost.c. */
1529   pdf_doc_add_page_content(" n", 2);  /* op: n */
1530
1531   return 0;
1532 }
1533
1534 int
1535 pdf_dev_moveto (double x, double y)
1536 {
1537   m_stack    *gss = &gs_stack;
1538   pdf_gstate *gs  = m_stack_top(gss);
1539   pdf_path   *cpa = &gs->path;
1540   pdf_coord  *cpt = &gs->cp;
1541   pdf_coord   p;
1542
1543   p.x = x; p.y = y;
1544   return pdf_path__moveto(cpa, cpt, &p); /* cpt updated */
1545 }
1546
1547 int
1548 pdf_dev_rmoveto (double x, double y)
1549 {
1550   m_stack    *gss = &gs_stack;
1551   pdf_gstate *gs  = m_stack_top(gss);
1552   pdf_path   *cpa = &gs->path;
1553   pdf_coord  *cpt = &gs->cp;
1554   pdf_coord   p;
1555
1556   p.x = cpt->x + x;
1557   p.y = cpt->y + y;
1558   return pdf_path__moveto(cpa, cpt, &p); /* cpt updated */
1559 }
1560
1561 int
1562 pdf_dev_lineto (double x, double y)
1563 {
1564   m_stack    *gss = &gs_stack;
1565   pdf_gstate *gs  = m_stack_top(gss);
1566   pdf_path   *cpa = &gs->path;
1567   pdf_coord  *cpt = &gs->cp;
1568   pdf_coord   p0;
1569
1570   p0.x = x; p0.y = y;
1571
1572   return pdf_path__lineto(cpa, cpt, &p0);
1573 }
1574
1575 int
1576 pdf_dev_rlineto (double x, double y)
1577 {
1578   m_stack    *gss = &gs_stack;
1579   pdf_gstate *gs  = m_stack_top(gss);
1580   pdf_path   *cpa = &gs->path;
1581   pdf_coord  *cpt = &gs->cp;
1582   pdf_coord   p0;
1583
1584   p0.x = x + cpt->x; p0.y = y + cpt->y;
1585
1586   return pdf_path__lineto(cpa, cpt, &p0);
1587 }
1588
1589 int
1590 pdf_dev_curveto  (double x0, double y0,
1591                   double x1, double y1,
1592                   double x2, double y2)
1593 {
1594   m_stack    *gss = &gs_stack;
1595   pdf_gstate *gs  = m_stack_top(gss);
1596   pdf_path   *cpa = &gs->path;
1597   pdf_coord  *cpt = &gs->cp;
1598   pdf_coord   p0, p1, p2;
1599
1600   p0.x = x0; p0.y = y0;
1601   p1.x = x1; p1.y = y1;
1602   p2.x = x2; p2.y = y2;
1603
1604   return pdf_path__curveto(cpa, cpt, &p0, &p1, &p2);
1605 }
1606
1607 int
1608 pdf_dev_rcurveto (double x0, double y0,
1609                   double x1, double y1,
1610                   double x2, double y2)
1611 {
1612   m_stack    *gss = &gs_stack;
1613   pdf_gstate *gs  = m_stack_top(gss);
1614   pdf_path   *cpa = &gs->path;
1615   pdf_coord  *cpt = &gs->cp;
1616   pdf_coord   p0, p1, p2;
1617
1618   p0.x = x0 + cpt->x; p0.y = y0 + cpt->y;
1619   p1.x = x1 + cpt->x; p1.y = y1 + cpt->y;
1620   p2.x = x2 + cpt->x; p2.y = y2 + cpt->y;
1621
1622   return pdf_path__curveto(cpa, cpt, &p0, &p1, &p2);
1623 }
1624
1625
1626 int
1627 pdf_dev_closepath (void)
1628 {
1629   m_stack    *gss = &gs_stack;
1630   pdf_gstate *gs  = m_stack_top(gss);
1631   pdf_coord  *cpt = &gs->cp;
1632   pdf_path   *cpa = &gs->path;
1633
1634   return pdf_path__closepath(cpa, cpt);
1635 }
1636
1637
1638 void
1639 pdf_dev_dtransform (pdf_coord *p, const pdf_tmatrix *M)
1640 {
1641   m_stack     *gss = &gs_stack;
1642   pdf_gstate  *gs  = m_stack_top(gss);
1643   pdf_tmatrix *CTM = &gs->matrix;
1644
1645   ASSERT(p);
1646
1647   pdf_coord__dtransform(p, (M ? M : CTM));
1648
1649   return;
1650 }
1651
1652 void
1653 pdf_dev_idtransform (pdf_coord *p, const pdf_tmatrix *M)
1654 {
1655   m_stack     *gss = &gs_stack;
1656   pdf_gstate  *gs  = m_stack_top(gss);
1657   pdf_tmatrix *CTM = &gs->matrix;
1658
1659   ASSERT(p);
1660
1661   pdf_coord__idtransform(p, (M ? M : CTM));
1662
1663   return;
1664 }
1665
1666 void
1667 pdf_dev_transform (pdf_coord *p, const pdf_tmatrix *M)
1668 {
1669   m_stack     *gss = &gs_stack;
1670   pdf_gstate  *gs  = m_stack_top(gss);
1671   pdf_tmatrix *CTM = &gs->matrix;
1672
1673   ASSERT(p);
1674
1675   pdf_coord__transform(p, (M ? M : CTM));
1676
1677   return;
1678 }
1679
1680 #if 0
1681 void
1682 pdf_dev_itransform (pdf_coord *p, const pdf_tmatrix *M)
1683 {
1684   m_stack     *gss = &gs_stack;
1685   pdf_gstate  *gs  = m_stack_top(gss);
1686   pdf_tmatrix *CTM = &gs->matrix;
1687
1688   ASSERT(p);
1689
1690   pdf_coord__itransform(p, (M ? M : CTM));
1691
1692   return;
1693 }
1694 #endif
1695
1696 int
1697 pdf_dev_arc  (double c_x , double c_y, double r,
1698               double a_0 , double a_1)
1699 {
1700   m_stack    *gss = &gs_stack;
1701   pdf_gstate *gs  = m_stack_top(gss);
1702   pdf_path   *cpa = &gs->path;
1703   pdf_coord  *cpt = &gs->cp;
1704   pdf_coord   c;
1705
1706   c.x = c_x; c.y = c_y;
1707
1708   return  pdf_path__elliptarc(cpa, cpt, &c, r, r, 0.0, a_0, a_1, +1);
1709 }
1710
1711 /* *negative* arc */
1712 int
1713 pdf_dev_arcn (double c_x , double c_y, double r,
1714               double a_0 , double a_1)
1715 {
1716   m_stack    *gss = &gs_stack;
1717   pdf_gstate *gs  = m_stack_top(gss);
1718   pdf_path   *cpa = &gs->path;
1719   pdf_coord  *cpt = &gs->cp;
1720   pdf_coord   c;
1721
1722   c.x = c_x; c.y = c_y;
1723
1724   return  pdf_path__elliptarc(cpa, cpt, &c, r, r, 0.0, a_0, a_1, -1);
1725 }
1726
1727 int
1728 pdf_dev_arcx (double c_x , double c_y,
1729               double r_x , double r_y,
1730               double a_0 , double a_1,
1731               int    a_d ,
1732               double xar)
1733 {
1734   m_stack    *gss = &gs_stack;
1735   pdf_gstate *gs  = m_stack_top(gss);
1736   pdf_path   *cpa = &gs->path;
1737   pdf_coord  *cpt = &gs->cp;
1738   pdf_coord   c;
1739
1740   c.x = c_x; c.y = c_y;
1741
1742   return  pdf_path__elliptarc(cpa, cpt, &c, r_x, r_y, xar, a_0, a_1, a_d);
1743 }
1744
1745 /* Required by Tpic */
1746 int
1747 pdf_dev_bspline (double x0, double y0,
1748                  double x1, double y1, double x2, double y2)
1749 {
1750   m_stack    *gss = &gs_stack;
1751   pdf_gstate *gs  = m_stack_top(gss);
1752   pdf_path   *cpa = &gs->path;
1753   pdf_coord  *cpt = &gs->cp;  
1754   pdf_coord   p1, p2, p3;
1755
1756   p1.x = x0 + 2.0 * (x1 - x0) / 3.0;
1757   p1.y = y0 + 2.0 * (y1 - y0) / 3.0;
1758   p2.x = x1 + (x2 - x1) / 3.0;
1759   p2.y = y1 + (y2 - y1) / 3.0;
1760   p3.x = x2;
1761   p3.y = y2;
1762
1763   return  pdf_path__curveto(cpa, cpt, &p1, &p2, &p3);
1764 }
1765
1766
1767 #if 0
1768 int
1769 pdf_dev_rectstroke (double x, double y,
1770                     double w, double h,
1771                     const pdf_tmatrix *M  /* optional */
1772                    )
1773 {
1774   pdf_rect r;
1775
1776   r.llx = x;
1777   r.lly = y;
1778   r.urx = x + w;
1779   r.ury = y + h;
1780
1781   return  pdf_dev__rectshape(NULL, &r, M, 'S');
1782 }
1783 #endif
1784
1785 int
1786 pdf_dev_rectfill  (double x, double y,
1787                    double w, double h)
1788 {
1789   pdf_rect r;
1790
1791   r.llx = x;
1792   r.lly = y;
1793   r.urx = x + w;
1794   r.ury = y + h;
1795
1796   return  pdf_dev__rectshape(NULL, &r, NULL, 'f');
1797 }
1798
1799 int
1800 pdf_dev_rectclip (double x, double y,
1801                   double w, double h)
1802 {
1803   pdf_rect r;
1804
1805   r.llx = x;
1806   r.lly = y;
1807   r.urx = x + w;
1808   r.ury = y + h;
1809   
1810   return  pdf_dev__rectshape(NULL, &r, NULL, 'W');
1811 }