3 This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
5 Copyright (C) 2002-2012 by Jin-Hwan Cho and Shunsaku Hirata,
6 the dvipdfmx project team.
8 Copyright (C) 1998, 1999 by Mark A. Wicks <mwicks@kettering.edu>
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.
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.
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.
50 * Numbers are rounding to 0-5 fractional digits
53 #define detM(M) ((M).a * (M).d - (M).b * (M).c)
54 #define detP(M) ((M)->a * (M)->d - (M)->b * (M)->c)
57 static /* __inline__ */ int
58 inversematrix (pdf_tmatrix *W, const pdf_tmatrix *M)
63 if (fabs(det) < 1.e-8) {
65 WARN("Inverting matrix with zero determinant...");
67 return -1; /* result is undefined. */
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);
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)
83 #define vecang(v,w) ( \
84 dsign(vecrot((v),(w))) * \
85 acos(vecprd((v),(w)) / sqrt(vecprd((v),(v)) * vecprd((w),(w)))) \
88 static /* __inline__ */ int
89 pdf_coord__equal (const pdf_coord *p1, const pdf_coord *p2)
91 if (fabs(p1->x - p2->x) < 1.e-7 &&
92 fabs(p1->y - p2->y) < 1.e-7)
96 #define COORD_EQUAL(p,q) pdf_coord__equal((p),(q))
100 pdf_coord__sort_compar_X (const void *pp1, const void *pp2)
102 pdf_coord *p1 = (pdf_coord *)pp1;
103 pdf_coord *p2 = (pdf_coord *)pp2;
105 if (pdf_coord__equal(p1, p2))
108 return (int) dsign(p1->x - p2->x);
114 pdf_coord__sort_compar_Y (const void *pp1, const void *pp2)
116 pdf_coord *p1 = (pdf_coord *)pp1;
117 pdf_coord *p2 = (pdf_coord *)pp2;
119 if (pdf_coord__equal(p1, p2))
122 return (int) dsign(p1->y - p2->y);
129 static /* __inline__ */ int
130 pdf_coord__transform (pdf_coord *p, const pdf_tmatrix *M)
135 p->x = x * M->a + y * M->c + M->e;
136 p->y = x * M->b + y * M->d + M->f;
142 static /* __inline__ */ int
143 pdf_coord__itransform (pdf_coord *p, const pdf_tmatrix *M)
149 error = inversematrix(&W, M);
154 p->x = x * W.a + y * W.c + W.e;
155 p->y = x * W.b + y * W.d + W.f;
161 static /* __inline__ */ int
162 pdf_coord__dtransform (pdf_coord *p, const pdf_tmatrix *M)
167 p->x = x * M->a + y * M->c;
168 p->y = x * M->b + y * M->d;
173 static /* __inline__ */ int
174 pdf_coord__idtransform (pdf_coord *p, const pdf_tmatrix *M)
180 error = inversematrix(&W, M);
185 p->x = x * W.a + y * W.c;
186 p->y = x * W.b + y * W.d;
192 /* Modify M itself */
194 pdf_invertmatrix (pdf_tmatrix *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;
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);
214 pdf_copymatrix(M, &W);
220 typedef struct pa_elem_
226 /* each subpath delimitted by moveto */
234 static const struct {
235 char opchr; /* PDF operator char */
236 int n_pts; /* number of *points* */
239 #define PE_TYPE__INVALID -1
240 #define PE_TYPE__MOVETO 0
242 #define PE_TYPE__LINETO 1
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
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 : ' ')
262 #define PA_LENGTH(pa) ((pa)->num_paths)
264 #define GS_FLAG_CURRENTPOINT_SET (1 << 0)
267 static char fmt_buf[1024]; /* FIXME */
268 #define FORMAT_BUFF_PTR(p) fmt_buf
269 #define FORMAT_BUFF_LEN(p) 1024
272 init_a_path (pdf_path *p)
284 pdf_path__clearpath (pdf_path *p)
294 pdf_path__growpath (pdf_path *p, int max_pe)
296 if (max_pe < p->max_paths)
299 p->max_paths = MAX(p->max_paths + 8, max_pe);
300 p->path = RENEW(p->path, p->max_paths, pa_elem);
306 clear_a_path (pdf_path *p)
320 pdf_path__copypath (pdf_path *p1, const pdf_path *p0)
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]);
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;
338 p1->num_paths = PA_LENGTH(p0);
344 /* start new subpath */
346 pdf_path__moveto (pdf_path *pa,
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;
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;
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).
374 * 'moveto' must be used to enforce starting new path.
375 * This affects how 'closepath' is treated.
378 pdf_path__next_pe (pdf_path *pa, const pdf_coord *cp)
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;
389 return &pa->path[pa->num_paths++];
392 pe = &pa->path[pa->num_paths-1];
394 case PE_TYPE__MOVETO:
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;
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;
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;
423 case PE_TYPE__CLOSEPATH:
424 pe = &pa->path[pa->num_paths++];
425 pe->type = PE_TYPE__MOVETO;
431 return &pa->path[pa->num_paths++];
435 pdf_path__transform (pdf_path *pa, const pdf_tmatrix *M)
442 for (i = 0; i < PA_LENGTH(pa); i++) {
446 pdf_coord__transform(&(pe->p[n]), M);
453 /* Path Construction */
455 pdf_path__lineto (pdf_path *pa,
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;
470 pdf_path__curveto (pdf_path *pa,
479 pe = pdf_path__next_pe(pa, cp);
480 if (COORD_EQUAL(cp, p0)) {
481 pe->type = PE_TYPE__CURVETO_V;
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;
490 pe->p[1].x = cp->x = p1->x;
491 pe->p[1].y = cp->y = p1->y;
493 pe->type = PE_TYPE__CURVETO;
498 pe->p[2].x = cp->x = p2->x;
499 pe->p[2].y = cp->y = p2->y;
506 #define QB_TWO_THIRD (2.0/3.0)
507 #define QB_ONE_THIRD (1.0/3.0)
510 pdf_path__curveto_QB (pdf_path *pa,
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);
524 return pdf_path__curveto(pa, cp, &q0, &q1, p1);
529 /* This isn't specified as cp to somewhere. */
531 pdf_path__elliptarc (pdf_path *pa,
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 */
544 pdf_coord p0, p1, p2, p3;
547 int n_c; /* number of segments */
550 if (fabs(r_x) < 1.e-8 ||
555 for ( ; a_1 > a_0; a_1 -= 360.0);
557 for ( ; a_1 < a_0; a_0 -= 360.0);
561 for (n_c = 1; fabs(d_a) > 90.0 * n_c; n_c++);
563 if (fabs(d_a) < 1.e-8)
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;
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));
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 */
588 for (i = 0; !error && i < n_c; i++) {
590 e0.x = cos(q); e0.y = sin(q);
591 e1.x = cos(q + d_a); e1.y = sin(q + d_a);
593 /* Condition for tangent vector requirs
594 * d1 = p1 - p0 = f ( sin a, -cos a)
595 * d2 = p2 - p3 = g ( sin b, -cos b)
599 p0.x = r_x * e0.x; /* s.p. */
601 p3.x = r_x * e1.x; /* e.p. */
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 ;
618 error = pdf_path__curveto(pa, &p0, &p1, &p2, &p3);
619 cp->x = p3.x; cp->y = p3.y;
626 pdf_path__closepath (pdf_path *pa, pdf_coord *cp /* no arg */)
631 /* search for start point of the last subpath */
632 for (i = PA_LENGTH(pa) - 1; i >= 0; i--) {
634 if (pe->type == PE_TYPE__MOVETO)
639 return -1; /* No path or no start point(!) */
644 pdf_path__growpath(pa, PA_LENGTH(pa) + 1);
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
652 pe = &pa->path[pa->num_paths++];
653 pe->type = PE_TYPE__CLOSEPATH;
659 * x y width height re
665 * (x + width) (y + height) l
669 /* Just for quick test */
670 static /* __inline__ */ int
671 pdf_path__isarect (pdf_path *pa,
672 int f_ir /* fill-rule is ignorable */
675 pa_elem *pe0, *pe1, *pe2, *pe3, *pe4;
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) {
695 /* Winding number is different but ignore it here. */
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) {
713 #define PT_OP_VALID(c) ( \
714 (c) == 'f' || (c) == 'F' || \
715 (c) == 's' || (c) == 'S' || \
716 (c) == 'b' || (c) == 'B' || \
720 static /* __inline__ */ int
721 INVERTIBLE_MATRIX (const pdf_tmatrix *M)
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);
732 /* rectfill, rectstroke, rectclip, recteoclip
734 * Draw isolated rectangle without actually doing
735 * gsave/grestore operation.
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.
745 pdf_dev__rectshape (pdf_dev *P,
747 const pdf_tmatrix *M,
751 char *buf = FORMAT_BUFF_PTR(P);
757 ASSERT(r && PT_OP_VALID(opchr));
759 isclip = (opchr == 'W') ? 1 : 0;
761 /* disallow matrix for clipping.
762 * q ... clip Q does nothing and
763 * n M cm ... clip n alter CTM.
766 !INVERTIBLE_MATRIX(M)))
776 len += pdf_sprint_matrix(buf + len, M);
778 buf[len++] = 'c'; buf[len++] = 'm';
784 p.x = r->llx; p.y = r->lly;
785 wd = r->urx - r->llx;
786 ht = r->ury - r->lly;
788 len += pdf_sprint_coord (buf + len, &p);
790 len += pdf_sprint_length(buf + len, wd);
792 len += pdf_sprint_length(buf + len, ht);
794 buf[len++] = 'r'; buf[len++] = 'e';
800 buf[len++] = isclip ? 'n' : 'Q';
802 pdf_doc_add_page_content(buf, len); /* op: q cm n re Q */
809 pdf_dev__flushpath (pdf_dev *P,
816 char *b = FORMAT_BUFF_PTR(P);
817 long b_len = FORMAT_BUFF_LEN(P);
818 pdf_rect r; /* FIXME */
824 ASSERT(pa && PT_OP_VALID(opchr));
826 if (PA_LENGTH(pa) <= 0)
830 isrect = pdf_path__isarect(pa, ignore_rule);
833 pe1 = &(pa->path[2]);
837 r.urx = pe1->p[0].x - pe->p[0].x; /* width... */
838 r.ury = pe1->p[0].y - pe->p[0].y; /* height... */
841 len += pdf_sprint_rect(b + len, &r);
845 pdf_doc_add_page_content(b, len); /* op: re */
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++) {
855 len += pdf_sprint_coord(b + len, pt);
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 */
865 pdf_doc_add_page_content(b, len); /* op: m l c v y h */
872 if (rule == PDF_FILL_RULE_EVENODD)
875 pdf_doc_add_page_content(b, len); /* op: f F s S b B W f* F* s* S* b* B* W* */
882 typedef struct pdf_gstate_
886 pdf_tmatrix matrix; /* cm, - */
888 pdf_color strokecolor;
890 /* colorspace here */
894 double pattern[PDF_DASH_SIZE_MAX];
896 } linedash; /* d, D */
898 double linewidth; /* w, LW */
900 int linecap; /* J, LC */
901 int linejoin; /* j, LJ */
902 double miterlimit; /* M, ML */
904 int flatness; /* i, FL, 0 to 100 (0 for use device-default) */
912 typedef struct m_stack_elem
915 struct m_stack_elem *prev;
918 typedef struct m_stack
922 m_stack_elem *bottom;
926 m_stack_init (m_stack *stack)
932 stack->bottom = NULL;
938 m_stack_push (m_stack *stack, void *data)
944 elem = NEW(1, m_stack_elem);
945 elem->prev = stack->top;
949 if (stack->size == 0)
950 stack->bottom = elem;
958 m_stack_pop (m_stack *stack)
965 if (stack->size == 0)
968 data = stack->top->data;
970 stack->top = elem->prev;
971 if (stack->size == 1)
972 stack->bottom = NULL;
981 m_stack_top (m_stack *stack)
987 if (stack->size == 0)
990 data = stack->top->data;
995 #define m_stack_depth(s) ((s)->size)
997 static m_stack gs_stack;
1000 init_a_gstate (pdf_gstate *gs)
1005 pdf_setmatrix(&gs->matrix, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
1007 pdf_color_black(&gs->strokecolor);
1008 pdf_color_black(&gs->fillcolor);
1010 gs->linedash.num_dash = 0;
1011 gs->linedash.offset = 0;
1014 gs->linewidth = 1.0;
1015 gs->miterlimit = 10.0;
1017 gs->flatness = 1; /* default to 1 in PDF */
1019 /* Internal variables */
1021 init_a_path(&gs->path);
1027 clear_a_gstate (pdf_gstate *gs)
1029 clear_a_path(&gs->path);
1030 memset(gs, 0, sizeof(pdf_gstate));
1036 copy_a_gstate (pdf_gstate *gs1, pdf_gstate *gs2)
1042 gs1->cp.x = gs2->cp.x;
1043 gs1->cp.y = gs2->cp.y;
1045 pdf_copymatrix(&gs1->matrix, &gs2->matrix);
1048 * Path should be linked list and gsave only
1049 * record starting point within path rather than
1050 * copying whole path.
1052 pdf_path__copypath(&gs1->path, &gs2->path);
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];
1058 gs1->linedash.offset = gs2->linedash.offset;
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;
1066 pdf_color_copycolor(&gs1->fillcolor , &gs2->fillcolor);
1067 pdf_color_copycolor(&gs1->strokecolor, &gs2->strokecolor);
1073 pdf_dev_init_gstates (void)
1077 m_stack_init(&gs_stack);
1079 gs = NEW(1, pdf_gstate);
1082 m_stack_push(&gs_stack, gs); /* Initial state */
1088 pdf_dev_clear_gstates (void)
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.");
1095 while ((gs = m_stack_pop(&gs_stack)) != NULL) {
1103 pdf_dev_gsave (void)
1105 pdf_gstate *gs0, *gs1;
1107 gs0 = m_stack_top(&gs_stack);
1108 gs1 = NEW(1, pdf_gstate);
1110 copy_a_gstate(gs1, gs0);
1111 m_stack_push(&gs_stack, gs1);
1113 pdf_doc_add_page_content(" q", 2); /* op: q */
1119 pdf_dev_grestore (void)
1123 if (m_stack_depth(&gs_stack) <= 1) { /* Initial state at bottom */
1124 WARN("Too many grestores.");
1128 gs = m_stack_pop(&gs_stack);
1132 pdf_doc_add_page_content(" Q", 2); /* op: Q */
1134 pdf_dev_reset_fonts();
1141 pdf_dev_push_gstate (void)
1143 m_stack *gss = &gs_stack;
1146 gs0 = NEW(1, pdf_gstate);
1150 m_stack_push(gss, gs0);
1157 pdf_dev_pop_gstate (void)
1159 m_stack *gss = &gs_stack;
1162 if (m_stack_depth(gss) <= 1) { /* Initial state at bottom */
1163 WARN("Too many grestores.");
1167 gs = m_stack_pop(gss);
1176 pdf_dev_current_depth (void)
1178 return (m_stack_depth(&gs_stack) - 1); /* 0 means initial state */
1182 pdf_dev_grestore_to (int depth)
1184 m_stack *gss = &gs_stack;
1189 if (m_stack_depth(gss) > depth + 1) {
1190 WARN("Closing pending transformations at end of page/XObject.");
1193 while (m_stack_depth(gss) > depth + 1) {
1194 pdf_doc_add_page_content(" Q", 2); /* op: Q */
1195 gs = m_stack_pop(gss);
1199 pdf_dev_reset_fonts();
1205 pdf_dev_currentpoint (pdf_coord *p)
1207 m_stack *gss = &gs_stack;
1208 pdf_gstate *gs = m_stack_top(gss);
1209 pdf_coord *cpt = &gs->cp;
1213 p->x = cpt->x; p->y = cpt->y;
1219 pdf_dev_currentmatrix (pdf_tmatrix *M)
1221 m_stack *gss = &gs_stack;
1222 pdf_gstate *gs = m_stack_top(gss);
1223 pdf_tmatrix *CTM = &gs->matrix;
1227 pdf_copymatrix(M, CTM);
1234 pdf_dev_currentcolor (pdf_color *color, int is_fill)
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;
1243 pdf_color_copycolor(color, is_fill ? fcl : scl);
1250 * mask == 0 means stroking color, mask == 0x20 nonstroking color
1252 * force == 1 means that operators will be generated even if
1253 * the color is the same as the current graphics state color
1256 pdf_dev_set_color (const pdf_color *color, char mask, int force)
1260 pdf_gstate *gs = m_stack_top(&gs_stack);
1261 pdf_color *current = mask ? &gs->fillcolor : &gs->strokecolor;
1263 ASSERT(pdf_color_is_valid(color));
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
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;
1280 case PDF_COLORSPACE_TYPE_CMYK:
1281 fmt_buf[len++] = 'K' | mask;
1283 case PDF_COLORSPACE_TYPE_GRAY:
1284 fmt_buf[len++] = 'G' | mask;
1286 default: /* already verified the given color */
1289 pdf_doc_add_page_content(fmt_buf, len); /* op: RG K G rg k g */
1291 pdf_color_copycolor(current, color);
1295 pdf_dev_reset_color (int force)
1299 pdf_color_get_current(&sc, &fc);
1300 pdf_dev_set_color(sc, 0, force);
1301 pdf_dev_set_color(fc, 0x20, force);
1305 pdf_dev_concat (const pdf_tmatrix *M)
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);
1318 /* Adobe Reader erases page content if there are
1319 * non invertible transformation.
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);
1329 len += pdf_sprint_matrix(buf + len, M);
1333 pdf_doc_add_page_content(buf, len); /* op: cm */
1335 pdf_concatmatrix(CTM, M);
1337 inversematrix(&W, M);
1339 pdf_path__transform (cpa, &W);
1340 pdf_coord__transform(cpt, &W);
1346 * num w LW linewidth (g.t. 0)
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.
1356 pdf_dev_setmiterlimit (double mlimit)
1358 m_stack *gss = &gs_stack;
1359 pdf_gstate *gs = m_stack_top(gss);
1361 char *buf = FORMAT_BUFF_PTR(NULL);
1363 if (gs->miterlimit != mlimit) {
1365 len += pdf_sprint_length(buf + len, mlimit);
1368 pdf_doc_add_page_content(buf, len); /* op: M */
1369 gs->miterlimit = mlimit;
1376 pdf_dev_setlinecap (int capstyle)
1378 m_stack *gss = &gs_stack;
1379 pdf_gstate *gs = m_stack_top(gss);
1381 char *buf = FORMAT_BUFF_PTR(NULL);
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;
1393 pdf_dev_setlinejoin (int joinstyle)
1395 m_stack *gss = &gs_stack;
1396 pdf_gstate *gs = m_stack_top(gss);
1398 char *buf = FORMAT_BUFF_PTR(NULL);
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;
1410 pdf_dev_setlinewidth (double width)
1412 m_stack *gss = &gs_stack;
1413 pdf_gstate *gs = m_stack_top(gss);
1415 char *buf = FORMAT_BUFF_PTR(NULL);
1417 if (gs->linewidth != width) {
1419 len += pdf_sprint_length(buf + len, width);
1422 pdf_doc_add_page_content(buf, len); /* op: w */
1423 gs->linewidth = width;
1430 pdf_dev_setdash (int count, double *pattern, double offset)
1432 m_stack *gss = &gs_stack;
1433 pdf_gstate *gs = m_stack_top(gss);
1435 char *buf = FORMAT_BUFF_PTR(NULL);
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++) {
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];
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 */
1457 pdf_dev_setflat (int flatness)
1459 m_stack *gss = &gs_stack;
1460 pdf_gstate *gs = m_stack_top(gss);
1462 char *buf = FORMAT_BUFF_PTR(NULL);
1464 if (flatness < 0 || flatness > 100)
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 */
1481 m_stack *gss = &gs_stack;
1482 pdf_gstate *gs = m_stack_top(gss);
1483 pdf_path *cpa = &gs->path;
1485 return pdf_dev__flushpath(NULL, cpa, 'W', PDF_FILL_RULE_NONZERO, 0);
1489 pdf_dev_eoclip (void)
1491 m_stack *gss = &gs_stack;
1492 pdf_gstate *gs = m_stack_top(gss);
1493 pdf_path *cpa = &gs->path;
1495 return pdf_dev__flushpath(NULL, cpa, 'W', PDF_FILL_RULE_EVENODD, 0);
1499 pdf_dev_flushpath (char p_op, int fill_rule)
1501 m_stack *gss = &gs_stack;
1502 pdf_gstate *gs = m_stack_top(gss);
1503 pdf_path *cpa = &gs->path;
1506 /* last arg 'ignore_rule' is only for single object
1507 * that can be converted to a rect where fill rule
1510 error = pdf_dev__flushpath(NULL, cpa, p_op, fill_rule, 1);
1511 pdf_path__clearpath(cpa);
1513 gs->flags &= ~GS_FLAG_CURRENTPOINT_SET;
1519 pdf_dev_newpath (void)
1521 m_stack *gss = &gs_stack;
1522 pdf_gstate *gs = m_stack_top(gss);
1523 pdf_path *p = &gs->path;
1525 if (PA_LENGTH(p) > 0) {
1526 pdf_path__clearpath (p);
1528 /* The following is required for "newpath" operator in mpost.c. */
1529 pdf_doc_add_page_content(" n", 2); /* op: n */
1535 pdf_dev_moveto (double x, double y)
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;
1544 return pdf_path__moveto(cpa, cpt, &p); /* cpt updated */
1548 pdf_dev_rmoveto (double x, double y)
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;
1558 return pdf_path__moveto(cpa, cpt, &p); /* cpt updated */
1562 pdf_dev_lineto (double x, double y)
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;
1572 return pdf_path__lineto(cpa, cpt, &p0);
1576 pdf_dev_rlineto (double x, double y)
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;
1584 p0.x = x + cpt->x; p0.y = y + cpt->y;
1586 return pdf_path__lineto(cpa, cpt, &p0);
1590 pdf_dev_curveto (double x0, double y0,
1591 double x1, double y1,
1592 double x2, double y2)
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;
1600 p0.x = x0; p0.y = y0;
1601 p1.x = x1; p1.y = y1;
1602 p2.x = x2; p2.y = y2;
1604 return pdf_path__curveto(cpa, cpt, &p0, &p1, &p2);
1608 pdf_dev_rcurveto (double x0, double y0,
1609 double x1, double y1,
1610 double x2, double y2)
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;
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;
1622 return pdf_path__curveto(cpa, cpt, &p0, &p1, &p2);
1627 pdf_dev_closepath (void)
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;
1634 return pdf_path__closepath(cpa, cpt);
1639 pdf_dev_dtransform (pdf_coord *p, const pdf_tmatrix *M)
1641 m_stack *gss = &gs_stack;
1642 pdf_gstate *gs = m_stack_top(gss);
1643 pdf_tmatrix *CTM = &gs->matrix;
1647 pdf_coord__dtransform(p, (M ? M : CTM));
1653 pdf_dev_idtransform (pdf_coord *p, const pdf_tmatrix *M)
1655 m_stack *gss = &gs_stack;
1656 pdf_gstate *gs = m_stack_top(gss);
1657 pdf_tmatrix *CTM = &gs->matrix;
1661 pdf_coord__idtransform(p, (M ? M : CTM));
1667 pdf_dev_transform (pdf_coord *p, const pdf_tmatrix *M)
1669 m_stack *gss = &gs_stack;
1670 pdf_gstate *gs = m_stack_top(gss);
1671 pdf_tmatrix *CTM = &gs->matrix;
1675 pdf_coord__transform(p, (M ? M : CTM));
1682 pdf_dev_itransform (pdf_coord *p, const pdf_tmatrix *M)
1684 m_stack *gss = &gs_stack;
1685 pdf_gstate *gs = m_stack_top(gss);
1686 pdf_tmatrix *CTM = &gs->matrix;
1690 pdf_coord__itransform(p, (M ? M : CTM));
1697 pdf_dev_arc (double c_x , double c_y, double r,
1698 double a_0 , double a_1)
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;
1706 c.x = c_x; c.y = c_y;
1708 return pdf_path__elliptarc(cpa, cpt, &c, r, r, 0.0, a_0, a_1, +1);
1711 /* *negative* arc */
1713 pdf_dev_arcn (double c_x , double c_y, double r,
1714 double a_0 , double a_1)
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;
1722 c.x = c_x; c.y = c_y;
1724 return pdf_path__elliptarc(cpa, cpt, &c, r, r, 0.0, a_0, a_1, -1);
1728 pdf_dev_arcx (double c_x , double c_y,
1729 double r_x , double r_y,
1730 double a_0 , double a_1,
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;
1740 c.x = c_x; c.y = c_y;
1742 return pdf_path__elliptarc(cpa, cpt, &c, r_x, r_y, xar, a_0, a_1, a_d);
1745 /* Required by Tpic */
1747 pdf_dev_bspline (double x0, double y0,
1748 double x1, double y1, double x2, double y2)
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;
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;
1763 return pdf_path__curveto(cpa, cpt, &p1, &p2, &p3);
1769 pdf_dev_rectstroke (double x, double y,
1771 const pdf_tmatrix *M /* optional */
1781 return pdf_dev__rectshape(NULL, &r, M, 'S');
1786 pdf_dev_rectfill (double x, double y,
1796 return pdf_dev__rectshape(NULL, &r, NULL, 'f');
1800 pdf_dev_rectclip (double x, double y,
1810 return pdf_dev__rectshape(NULL, &r, NULL, 'W');