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