3 Various utility functions for dealing with gfxdevices.
5 Part of the swftools package.
7 Copyright (c) 2005 Matthias Kramm <kramm@quiss.org>
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
35 typedef struct _linedraw_internal
41 } linedraw_internal_t
;
43 static void linedraw_moveTo(gfxdrawer_t
*d
, gfxcoord_t x
, gfxcoord_t y
)
45 linedraw_internal_t
*i
= (linedraw_internal_t
*)d
->internal
;
46 gfxline_t
*l
= (gfxline_t
*)rfx_alloc(sizeof(gfxline_t
));
61 static void linedraw_lineTo(gfxdrawer_t
*d
, gfxcoord_t x
, gfxcoord_t y
)
63 linedraw_internal_t
*i
= (linedraw_internal_t
*)d
->internal
;
65 /* starts with a line, not with a moveto. As this is the first
66 entry in the list, this is probably *meant* to be a moveto */
67 linedraw_moveTo(d
, x
, y
);
71 gfxline_t
*l
= (gfxline_t
*)rfx_alloc(sizeof(gfxline_t
));
83 static void linedraw_splineTo(gfxdrawer_t
*d
, gfxcoord_t sx
, gfxcoord_t sy
, gfxcoord_t x
, gfxcoord_t y
)
85 linedraw_internal_t
*i
= (linedraw_internal_t
*)d
->internal
;
87 linedraw_moveTo(d
, x
, y
);
91 gfxline_t
*l
= (gfxline_t
*)rfx_alloc(sizeof(gfxline_t
));
92 l
->type
= gfx_splineTo
;
104 static void linedraw_close(gfxdrawer_t
*d
)
106 linedraw_internal_t
*i
= (linedraw_internal_t
*)d
->internal
;
109 linedraw_lineTo(d
, i
->x0
, i
->y0
);
114 static void* linedraw_result(gfxdrawer_t
*d
)
116 linedraw_internal_t
*i
= (linedraw_internal_t
*)d
->internal
;
117 void*result
= (void*)i
->start
;
119 memset(d
, 0, sizeof(gfxdrawer_t
));
123 void gfxdrawer_target_gfxline(gfxdrawer_t
*d
)
125 linedraw_internal_t
*i
= (linedraw_internal_t
*)rfx_calloc(sizeof(linedraw_internal_t
));
129 d
->moveTo
= linedraw_moveTo
;
130 d
->lineTo
= linedraw_lineTo
;
131 d
->splineTo
= linedraw_splineTo
;
132 d
->close
= linedraw_close
;
133 d
->result
= linedraw_result
;
136 typedef struct _qspline_abc
142 typedef struct qspline_t
149 typedef struct cspline_t
157 static void mkspline(qspline_abc_t
*s
, double x
, double y
, gfxline_t
*l
)
160 Form 1: x = t*t*l->x + 2*t*(1-t)*l->sx + (1-t)*(1-t)*x;
161 Form 2: x = a*t*t + b*t + c
163 s
->cx
= x
; s
->bx
= 2*l
->sx
- 2*x
; s
->ax
= l
->x
- 2*l
->sx
+ x
;
164 s
->cy
= y
; s
->by
= 2*l
->sy
- 2*y
; s
->ay
= l
->y
- 2*l
->sy
+ y
;
167 static void spline_get_controlpoint(qspline_abc_t
*q
, double t1
, double t2
, double*dx
, double*dy
)
170 double nax
= q
->ax
*dt
*dt
;
171 double nay
= q
->ay
*dt
*dt
;
172 double nbx
= 2*q
->ax
*dt
*t1
+ q
->bx
*dt
;
173 double nby
= 2*q
->ay
*dt
*t1
+ q
->by
*dt
;
174 double ncx
= q
->ax
*t1
*t1
+ q
->bx
*t1
+ q
->cx
;
175 double ncy
= q
->ay
*t1
*t1
+ q
->by
*t1
+ q
->cy
;
180 static double get_spline_len(qspline_abc_t
*s
)
182 int parts
= (int)(sqrt(fabs(s
->ax
) + fabs(s
->ay
))*3);
187 if(parts
< 3) parts
= 3;
189 r2
= 1.0/(parts
*parts
);
192 double dx
= s
->ax
*(2*i
+1)*r2
+ s
->bx
*r
;
193 double dy
= s
->ay
*(2*i
+1)*r2
+ s
->by
*r
;
194 len
+= sqrt(dx
*dx
+dy
*dy
);
196 /*printf("Spline from %f,%f to %f,%f has len %f (%f)\n", s->cx, s->cy,
197 s->cx + s->bx + s->ax,
198 s->cy + s->by + s->ay, len,
199 sqrt((s->bx + s->ax)*(s->bx + s->ax) + (s->by + s->ay)*(s->by + s->ay))
201 assert(len+0.5 >= sqrt((s->bx + s->ax)*(s->bx + s->ax) + (s->by + s->ay)*(s->by + s->ay)));
206 void gfxtool_draw_dashed_line(gfxdrawer_t
*d
, gfxline_t
*line
, float*r
, float phase
)
209 double linepos
= 0,nextpos
= 0;
213 if(line
&& line
->type
!= gfx_moveTo
) {
214 fprintf(stderr
, "gfxtool: outline doesn't start with a moveTo");
220 for(i
=0;r
[i
]>=0;i
++) {
223 if(!r
|| (r
[0]<=0 && r
[0]>-0.01) || dashlen
<0.001) {
224 // no dashing. just draw the thing
226 if(line
->type
== gfx_moveTo
) {
227 d
->moveTo(d
, line
->x
, line
->y
);
228 } else if(line
->type
== gfx_lineTo
) {
229 d
->lineTo(d
, line
->x
, line
->y
);
230 } else if(line
->type
== gfx_splineTo
) {
231 d
->splineTo(d
, line
->sx
, line
->sy
, line
->x
, line
->y
);
242 if(r
[0]<0 || phase
<0) {
243 fprintf(stderr
, "gfxtool: invalid (negative) dashes: %f, phase=%f\n", r
[0], phase
);
247 for(;line
;line
=line
->next
) {
248 if(line
->type
== gfx_moveTo
) {
249 d
->moveTo(d
, line
->x
, line
->y
);
250 on
= 1; nextpos
= r
[0]; apos
= 0; linepos
= 0;
251 x
= line
->x
; y
= line
->y
;
252 while(linepos
< phase
) {
253 //printf("[+] linepos: %f, phase: %f, on:%d, apos:%d nextpos:%f\n", linepos, phase, on, apos, nextpos);
255 if(linepos
< phase
) {
263 //printf("[k] linepos: %f, phase: %f, on:%d, apos:%d nextpos:%f \n", linepos, phase, on, apos, nextpos);
264 } else if(line
->type
== gfx_lineTo
) {
265 double dx
= line
->x
- x
;
266 double dy
= line
->y
- y
;
267 double len
= sqrt(dx
*dx
+dy
*dy
);
270 double lineend
= linepos
+len
;
275 assert(nextpos
>=linepos
);
276 //printf("(line) on:%d apos: %d nextpos: %f, line pos: %f, line end: %f\n", on, apos, nextpos, linepos, linepos+len);
277 while(nextpos
<lineend
) {
278 double nx
= x
+ vx
*(nextpos
-linepos
);
279 double ny
= y
+ vy
*(nextpos
-linepos
);
280 if(on
) {d
->lineTo(d
, nx
,ny
);/*printf("lineTo %f\n", nextpos);*/}
281 else {d
->moveTo(d
, nx
,ny
);/*printf("moveTo %f\n", nextpos);*/}
289 //printf("lineTo %f\n", 1.0);
290 d
->lineTo(d
, line
->x
,line
->y
);
292 x
= line
->x
; y
= line
->y
;
293 } else if(line
->type
== gfx_splineTo
) {
295 double len
, lineend
,lastt
;
296 mkspline(&q
, x
, y
, line
);
298 len
= get_spline_len(&q
);
299 //printf("%f %f -> %f %f, len: %f\n", x, y, line->x, line->y, len);
302 lineend
= linepos
+len
;
305 printf("%f !< %f\n", nextpos
, linepos
);
306 assert(nextpos
>=linepos
);
307 //printf("(spline) on:%d apos: %d nextpos: %f, line pos: %f, line end: %f\n", on, apos, nextpos, linepos, linepos+len);
308 while(nextpos
<lineend
) {
309 double t
= (nextpos
-linepos
)/len
;
310 //printf("%f (%f-%f) apos=%d r[apos]=%f\n", t, nextpos, linepos, apos, r[apos]);
311 double nx
= q
.ax
*t
*t
+q
.bx
*t
+q
.cx
;
312 double ny
= q
.ay
*t
*t
+q
.by
*t
+q
.cy
;
315 spline_get_controlpoint(&q
, lastt
, t
, &sx
, &sy
);
316 d
->splineTo(d
, sx
, sy
, nx
,ny
);
317 //printf("splineTo %f\n", nextpos);
320 //printf("moveTo %f\n", nextpos);
331 spline_get_controlpoint(&q
, lastt
, 1, &sx
, &sy
);
332 d
->splineTo(d
, sx
, sy
, line
->x
,line
->y
);
333 //printf("splineTo %f\n", 1.0);
335 x
= line
->x
; y
= line
->y
;
340 static char* getToken(const char**p
)
344 while(**p
&& strchr(" ,()\t\n\r", **p
)) {
348 if (strchr("LMlm", **p
) && (isdigit(*(*p
+1))||strchr("+-", *(*p
+1)))) {
350 } else while(**p
&& !strchr(" ,()\t\n\r", **p
)) {
353 result
= (char*)malloc((*p
)-start
+1);
354 memcpy(result
,start
,(*p
)-start
+1);
355 result
[(*p
)-start
] = 0;
359 static float getFloat(const char** p
)
361 char* token
= getToken(p
);
362 float result
= atof(token
);
367 gfxline_t
*gfxline_fromstring(const char*string
)
370 gfxdrawer_target_gfxline(&d
);
372 const char*p
= string
;
374 char*token
= getToken(&p
);
381 if(!strcmp(token
, "M")) {
382 double x
= getFloat(&p
);
383 double y
= getFloat(&p
);
385 } else if(!strncmp(token
, "L", 1)) {
386 double x
= getFloat(&p
);
387 double y
= getFloat(&p
);
389 } else if(!strncmp(token
, "C", 1)) {
390 double x1
= getFloat(&p
);
391 double y1
= getFloat(&p
);
392 double x2
= getFloat(&p
);
393 double y2
= getFloat(&p
);
394 double x3
= getFloat(&p
);
395 double y3
= getFloat(&p
);
396 gfxdraw_cubicTo(&d
, x1
,y1
, x2
,y2
, x3
,y3
, 0.9);
397 } else if(!strncmp(token
, "z", 1)) {
400 fprintf(stderr
, "gfxdraw: Warning: unknown primitive '%s'\n", token
);
403 gfxline_t
*line
= d
.result(&d
);
408 gfxline_t
* gfxline_clone(gfxline_t
*line
)
413 gfxline_t
*n
= (gfxline_t
*)rfx_calloc(sizeof(gfxline_t
));
427 static char splineIsStraight(double x
, double y
, gfxline_t
*l
)
429 if(l
->type
== gfx_moveTo
)
431 if(l
->type
== gfx_lineTo
)
437 if(fabs(dx
*sy
- dy
*sx
) < 0.000001 && (dx
*sx
+ dy
*sy
) >= 0) {
443 void gfxline_optimize(gfxline_t
*line
)
446 /* step 1: convert splines to lines, where possible */
449 if(l
->type
== gfx_splineTo
&& splineIsStraight(x
,y
,l
)) {
450 l
->type
= gfx_lineTo
;
456 /* step 2: combine adjacent lines and splines, where possible */
458 while(l
&& l
->next
) {
459 gfxline_t
*next
= l
->next
;
462 if(l
->type
== gfx_lineTo
&& next
->type
== gfx_lineTo
) {
465 double nx
= next
->x
-l
->x
;
466 double ny
= next
->y
-l
->y
;
467 if(fabs(dx
*ny
- dy
*nx
) < 0.000001 && (dx
*nx
+ dy
*ny
) >= 0) {
470 } else if(l
->type
== gfx_splineTo
&& next
->type
== gfx_splineTo
) {
474 l
->next
= next
->next
;
489 gfxline_t
* gfxtool_dash_line(gfxline_t
*line
, float*dashes
, float phase
)
493 gfxdrawer_target_gfxline(&d
);
494 gfxtool_draw_dashed_line(&d
, line
, dashes
, phase
);
495 result
= (gfxline_t
*)d
.result(&d
);
499 void gfxline_show(gfxline_t
*l
, FILE*fi
)
502 if(l
->type
== gfx_moveTo
) {
503 fprintf(fi
, "moveTo %.2f,%.2f\n", l
->x
, l
->y
);
505 if(l
->type
== gfx_lineTo
) {
506 fprintf(fi
, "lineTo %.2f,%.2f\n", l
->x
, l
->y
);
508 if(l
->type
== gfx_splineTo
) {
509 fprintf(fi
, "splineTo %.2f,%.2f %.2f,%.2f\n", l
->sx
, l
->sy
, l
->x
, l
->y
);
515 void gfxline_free(gfxline_t
*l
)
517 if(l
&& (l
+1) == l
->next
) {
531 static inline gfxpoint_t
cspline_getpoint(const struct cspline_t
*s
, double t
)
537 double mtmt
= mt
*(1-t
);
538 double mtmtmt
= mtmt
*(1-t
);
539 p
.x
= s
->end
.x
*ttt
+ 3*s
->control2
.x
*tt
*mt
540 + 3*s
->control1
.x
*t
*mtmt
+ s
->start
.x
*mtmtmt
;
541 p
.y
= s
->end
.y
*ttt
+ 3*s
->control2
.y
*tt
*mt
542 + 3*s
->control1
.y
*t
*mtmt
+ s
->start
.y
*mtmtmt
;
545 static gfxpoint_t
qspline_getpoint(const qspline_t
*s
, double t
)
548 p
.x
= s
->end
.x
*t
*t
+ 2*s
->control
.x
*t
*(1-t
) + s
->start
.x
*(1-t
)*(1-t
);
549 p
.y
= s
->end
.y
*t
*t
+ 2*s
->control
.y
*t
*(1-t
) + s
->start
.y
*(1-t
)*(1-t
);
553 static int approximate3(const cspline_t
*s
, qspline_t
*q
, int size
, double quality2
)
555 unsigned int gran
= 0;
556 unsigned int istep
= 0x80000000;
557 unsigned int istart
= 0;
561 while(istart
<0x80000000)
563 unsigned int iend
= istart
+ istep
;
564 double start
= istart
/(double)0x80000000;
565 double end
= iend
/(double)0x80000000;
568 char left
= 0,recurse
=0;
573 /* create simple approximation: a qspline_t which run's through the
574 qspline_t point at 0.5 */
575 test
.start
= cspline_getpoint(s
, start
);
576 test
.control
= cspline_getpoint(s
, (start
+end
)/2);
577 test
.end
= cspline_getpoint(s
, end
);
578 /* fix the control point:
579 move it so that the new spline does runs through it */
580 test
.control
.x
= -(test
.end
.x
+ test
.start
.x
)/2 + 2*(test
.control
.x
);
581 test
.control
.y
= -(test
.end
.y
+ test
.start
.y
)/2 + 2*(test
.control
.y
);
583 /* depending on where we are in the spline, we either try to match
584 the left or right tangent */
588 pos
= left
?start
:end
;
590 test
.control
.x
= s
->end
.x
*(3*qpos
) + 3*s
->control2
.x
*(2*pos
-3*qpos
) +
591 3*s
->control1
.x
*(1-4*pos
+3*qpos
) + s
->start
.x
*(-3+6*pos
-3*qpos
);
592 test
.control
.y
= s
->end
.y
*(3*qpos
) + 3*s
->control2
.y
*(2*pos
-3*qpos
) +
593 3*s
->control1
.y
*(1-4*pos
+3*qpos
) + s
->start
.y
*(-3+6*pos
-3*qpos
);
595 test
.control
.x
*= (end
-start
)/2;
596 test
.control
.y
*= (end
-start
)/2;
597 test
.control
.x
+= test
.start
.x
;
598 test
.control
.y
+= test
.start
.y
;
600 test
.control
.x
*= -(end
-start
)/2;
601 test
.control
.y
*= -(end
-start
)/2;
602 test
.control
.x
+= test
.end
.x
;
603 test
.control
.y
+= test
.end
.y
;
608 /* measure the spline's accurancy, by taking a number of probes */
609 for(t
=0;t
<probes
;t
++) {
610 gfxpoint_t qr1
,qr2
,cr1
,cr2
;
611 double pos
= 0.5/(probes
*2)*(t
*2+1);
614 qr1
= qspline_getpoint(&test
, pos
);
615 cr1
= cspline_getpoint(s
, start
+pos
*(end
-start
));
624 qr2
= qspline_getpoint(&test
, (1-pos
));
625 cr2
= cspline_getpoint(s
, start
+(1-pos
)*(end
-start
));
635 #else // quadratic error: *much* faster!
637 /* convert control point representation to
638 d*x^3 + c*x^2 + b*x + a */
639 dx
= s
->end
.x
- s
->control2
.x
*3 + s
->control1
.x
*3 - s
->start
.x
;
640 dy
= s
->end
.y
- s
->control2
.y
*3 + s
->control1
.y
*3 - s
->start
.y
;
642 /* we need to do this for the subspline between [start,end], not [0,1]
643 as a transformation of t->a*t+b does nothing to highest coefficient
644 of the spline except multiply it with a^3, we just need to modify
646 {double m
= end
-start
;
651 /* use the integral over (f(x)-g(x))^2 between 0 and 1
652 to measure the approximation quality.
653 (it boils down to const*d^2) */
654 recurse
= (dx
*dx
+ dy
*dy
> quality2
);
657 if(recurse
&& istep
>1 && size
-level
> num
) {
664 while(!(istart
& istep
)) {
673 void gfxdraw_conicTo(gfxdrawer_t
*draw
, double cx
, double cy
, double tox
, double toy
, double quality
)
675 double c1x
= (draw
->x
+ 2 * cx
) / 3;
676 double c1y
= (draw
->y
+ 2 * cy
) / 3;
677 double c2x
= (2 * cx
+ tox
) / 3;
678 double c2y
= (2 * cy
+ toy
) / 3;
679 gfxdraw_cubicTo(draw
, c1x
, c1y
, c2x
, c2y
, tox
, toy
, quality
);
683 void gfxdraw_cubicTo(gfxdrawer_t
*draw
, double c1x
, double c1y
, double c2x
, double c2y
, double x
, double y
, double quality
)
687 double maxerror
= quality
>0 ? quality
: 1.0;
699 num
= approximate3(&c
, q
, 128, maxerror
);
704 mid
.x
= q
[t
].control
.x
;
705 mid
.y
= q
[t
].control
.y
;
708 draw
->splineTo(draw
, mid
.x
, mid
.y
, to
.x
, to
.y
);
712 gfxbbox_t
gfxbbox_expand_to_point(gfxbbox_t box
, gfxcoord_t x
, gfxcoord_t y
)
714 if(box
.xmin
==0 && box
.ymin
==0 && box
.xmax
==0 && box
.ymax
==0) {
719 if(x
==0 && y
==0) box
.xmax
= 0.0000001;
733 gfxbbox_t
gfxbbox_expand_to_bbox(gfxbbox_t box
, gfxbbox_t box2
)
735 if(box2
.xmin
==0 && box2
.ymin
==0 && box2
.xmax
==0 && box2
.ymax
==0) {
738 box
= gfxbbox_expand_to_point(box
, box2
.xmin
, box2
.ymin
);
739 box
= gfxbbox_expand_to_point(box
, box2
.xmax
, box2
.ymax
);
743 void gfxbbox_intersect(gfxbbox_t
*box1
, gfxbbox_t
*box2
)
745 if(box2
->xmin
> box1
->xmin
)
746 box1
->xmin
= box2
->xmin
;
747 if(box2
->ymin
> box1
->ymin
)
748 box1
->ymin
= box2
->ymin
;
749 if(box2
->xmax
< box1
->xmax
)
750 box1
->xmax
= box2
->xmax
;
751 if(box2
->ymax
< box1
->ymax
)
752 box1
->ymax
= box2
->ymax
;
753 if(box1
->xmin
> box1
->xmax
)
754 box1
->xmax
= box1
->xmin
;
755 if(box1
->ymin
> box1
->ymax
)
756 box1
->ymax
= box1
->ymin
;
759 gfxbbox_t
gfxline_getbbox(gfxline_t
*line
)
762 gfxbbox_t bbox
= {0,0,0,0};
765 if(line
->type
== gfx_moveTo
) {
767 } else if(line
->type
== gfx_lineTo
) {
768 if(last
) bbox
= gfxbbox_expand_to_point(bbox
, x
, y
);
769 bbox
= gfxbbox_expand_to_point(bbox
, line
->x
, line
->y
);
771 } else if(line
->type
== gfx_splineTo
) {
772 if(last
) bbox
= gfxbbox_expand_to_point(bbox
, x
, y
);
773 bbox
= gfxbbox_expand_to_point(bbox
, line
->sx
, line
->sy
);
774 bbox
= gfxbbox_expand_to_point(bbox
, line
->x
, line
->y
);
784 gfxline_t
* gfxline_append(gfxline_t
*line1
, gfxline_t
*line2
)
786 gfxline_t
*l
= line1
;;
796 void gfxline_transform(gfxline_t
*line
, gfxmatrix_t
*matrix
)
799 double x
= matrix
->m00
*line
->x
+ matrix
->m10
*line
->y
+ matrix
->tx
;
800 double y
= matrix
->m01
*line
->x
+ matrix
->m11
*line
->y
+ matrix
->ty
;
803 if(line
->type
== gfx_splineTo
) {
804 double sx
= matrix
->m00
*line
->sx
+ matrix
->m10
*line
->sy
+ matrix
->tx
;
805 double sy
= matrix
->m01
*line
->sx
+ matrix
->m11
*line
->sy
+ matrix
->ty
;
813 void gfxmatrix_dump(gfxmatrix_t
*m
, FILE*fi
, char*prefix
)
815 fprintf(fi
, "%s%f %f | %f\n", prefix
, m
->m00
, m
->m10
, m
->tx
);
816 fprintf(fi
, "%s%f %f | %f\n", prefix
, m
->m01
, m
->m11
, m
->ty
);
819 void gfxmatrix_transform(gfxmatrix_t
*m
, double* v
, double*dest
)
821 dest
[0] = m
->m00
*v
[0] + m
->m10
*v
[1] + m
->tx
;
822 dest
[1] = m
->m01
*v
[0] + m
->m11
*v
[1] + m
->ty
;
824 void gfxmatrix_invert(gfxmatrix_t
*m
, gfxmatrix_t
*dest
)
826 double det
= m
->m00
* m
->m11
- m
->m10
* m
->m01
;
828 memset(dest
, 0, sizeof(gfxmatrix_t
));
832 dest
->m00
= m
->m11
* det
;
833 dest
->m01
= -m
->m01
* det
;
834 dest
->m10
= -m
->m10
* det
;
835 dest
->m11
= m
->m00
* det
;
836 dest
->tx
= -(dest
->m00
* m
->tx
+ dest
->m10
* m
->ty
);
837 dest
->ty
= -(dest
->m01
* m
->tx
+ dest
->m11
* m
->ty
);
839 void gfxmatrix_unit(gfxmatrix_t
*m
)
841 memset(m
, 0, sizeof(gfxmatrix_t
));
845 void gfxmatrix_multiply(gfxmatrix_t
*m1
, gfxmatrix_t
*m2
, gfxmatrix_t
*dest
)
847 dest
->m00
= m1
->m00
*m2
->m00
+ m1
->m10
*m2
->m01
;
848 dest
->m01
= m1
->m01
*m2
->m00
+ m1
->m11
*m2
->m01
;
849 dest
->m10
= m1
->m00
*m2
->m10
+ m1
->m10
*m2
->m11
;
850 dest
->m11
= m1
->m01
*m2
->m10
+ m1
->m11
*m2
->m11
;
851 dest
->tx
= m1
->m00
*m2
->tx
+ m1
->m10
*m2
->ty
+ m1
->tx
;
852 dest
->ty
= m1
->m01
*m2
->tx
+ m1
->m11
*m2
->ty
+ m1
->ty
;
855 gfxfontlist_t
* gfxfontlist_create()
857 /* Initial list ist empty */
861 gfxfont_t
*gfxfontlist_findfont(gfxfontlist_t
*list
, char*id
)
863 gfxfontlist_t
*l
= list
;
865 if(!strcmp((char*)l
->font
->id
, id
)) {
872 char gfxfontlist_hasfont(gfxfontlist_t
*list
, gfxfont_t
*font
)
874 gfxfontlist_t
*l
= list
;
876 if(!strcmp((char*)l
->font
->id
, font
->id
)) {
883 void*gfxfontlist_getuserdata(gfxfontlist_t
*list
, const char*id
)
885 gfxfontlist_t
*l
= list
;
887 if(!strcmp((char*)l
->font
->id
, id
)) {
894 gfxfontlist_t
*gfxfontlist_addfont2(gfxfontlist_t
*list
, gfxfont_t
*font
, void*user
)
896 gfxfontlist_t
*last
=0,*l
= list
;
899 if(l
->font
== font
) {
900 return list
; // we already know this font
905 fprintf(stderr
, "Tried to add zero font\n");
907 l
= (gfxfontlist_t
*)rfx_calloc(sizeof(gfxfontlist_t
));
918 gfxfontlist_t
*gfxfontlist_addfont(gfxfontlist_t
*list
, gfxfont_t
*font
)
920 return gfxfontlist_addfont2(list
, font
, 0);
922 void gfxfontlist_free(gfxfontlist_t
*list
, char deletefonts
)
924 gfxfontlist_t
*l
= list
;
926 gfxfontlist_t
*next
= l
->next
;
927 if(deletefonts
&& l
->font
) {
928 gfxfont_free(l
->font
);l
->font
=0;
936 gfxline_t
*gfxline_makerectangle(double x1
,double y1
,double x2
, double y2
)
938 gfxline_t
* line
= (gfxline_t
*)rfx_calloc(sizeof(gfxline_t
)*5);
939 line
[0].x
= x1
;line
[0].y
= y1
;line
[0].type
= gfx_moveTo
;line
[0].next
= &line
[1];
940 line
[1].x
= x2
;line
[1].y
= y1
;line
[1].type
= gfx_lineTo
;line
[1].next
= &line
[2];
941 line
[2].x
= x2
;line
[2].y
= y2
;line
[2].type
= gfx_lineTo
;line
[2].next
= &line
[3];
942 line
[3].x
= x1
;line
[3].y
= y2
;line
[3].type
= gfx_lineTo
;line
[3].next
= &line
[4];
943 line
[4].x
= x1
;line
[4].y
= y1
;line
[4].type
= gfx_lineTo
;
947 gfxline_t
*gfxline_makecircle(double x
,double y
,double rx
, double ry
)
951 double begin
= 0.7070;
952 gfxline_t
** line
= (gfxline_t
**)rfx_calloc(sizeof(gfxline_t
*)*9);
955 line
[t
] = rfx_calloc(sizeof(gfxline_t
));
957 line
[0]->type
= gfx_moveTo
;
958 line
[0]->x
= x
+begin
*rx
;
959 line
[0]->y
= y
+begin
*ry
;
961 line
[t
-1]->next
= line
[t
];
962 line
[t
]->type
= gfx_splineTo
;
965 #define R(nr,cx,cy,mx,my) \
966 line[nr]->sx = line[nr-1]->x + (cx); \
967 line[nr]->sy = line[nr-1]->y + (cy); \
968 line[nr]->x = line[nr]->sx + (mx); \
969 line[nr]->y = line[nr]->sy + (my);
970 R(1, -C1
*rx
, C1
*ry
, -C2
*rx
, 0);
971 R(2, -C2
*rx
, 0, -C1
*rx
, -C1
*ry
);
972 R(3, -C1
*rx
, -C1
*ry
, 0, -C2
*ry
);
973 R(4, 0, -C2
*ry
, C1
*rx
, -C1
*ry
);
974 R(5, C1
*rx
, -C1
*ry
, C2
*rx
, 0);
975 R(6, C2
*rx
, 0, C1
*rx
, C1
*ry
);
976 R(7, C1
*rx
, C1
*ry
, 0, C2
*ry
);
977 R(8, 0, C2
*ry
, -C1
*rx
, C1
*ry
);
978 gfxline_t
*l
= line
[0];
983 gfxbbox_t
* gfxline_isrectangle(gfxline_t
*_l
)
988 gfxline_t
*l
= gfxline_clone(_l
);
991 double x1
=0,x2
=0,y1
=0,y2
=0;
1003 if(xc
==2 && x
!=x1
&& x
!=x2
) {fail
=1;break;}
1004 else if(xc
>=1 && x
==x1
) {left
=0;}
1005 else if(xc
==2 && x
==x2
) {left
=1;}
1006 else if(xc
==1 && x
!=x1
) {x2
= x
; xc
=2; left
=1;}
1007 else if(xc
==0) {x1
= x
; xc
=1;left
=0;}
1008 else {fprintf(stderr
, "Internal error in rectangle detection\n");}
1010 if(yc
==2 && y
!=y1
&& y
!=y2
) {fail
=1;break;}
1011 else if(yc
>=1 && y
==y1
) {top
=0;}
1012 else if(yc
==2 && y
==y2
) {top
=1;}
1013 else if(yc
==1 && y
!=y1
) {y2
= y
; yc
=2; top
=1;}
1014 else if(yc
==0) {y1
= y
; yc
=1;top
=0;}
1015 else {fprintf(stderr
, "Internal error in rectangle detection\n");}
1017 char pos
=top
<<1|left
;
1020 /* diagonal lines not allowed */
1025 /* no corner except the first one may be touched twice */
1026 if(pos
&& (corners
& 1<<pos
)) {
1029 /* mark which corners have been touched so far */
1037 if(corners
!=0x0f) return 0; // not all 4 corners reached
1039 if(x2
<x1
) {double x
= x2
;x2
=x1
;x1
=x
;}
1040 if(y2
<y1
) {double y
= y2
;y2
=y1
;y1
=y
;}
1042 gfxbbox_t
*r
= malloc(sizeof(gfxbbox_t
));
1043 r
->xmin
= x1
; r
->ymin
= y1
;
1044 r
->xmax
= x2
; r
->ymax
= y2
;
1048 void gfximage_transform(gfximage_t
*img
, gfxcxform_t
*cxform
)
1051 int size
= img
->width
*img
->height
;
1053 int rr
,rg
,rb
,ra
, tr
;
1054 int gr
,gg
,gb
,ga
, tg
;
1055 int br
,bg
,bb
,ba
, tb
;
1056 int ar
,ag
,ab
,aa
, ta
;
1057 rr
= (int)(cxform
->rr
*256);gr
= (int)(cxform
->gr
*256);
1058 rg
= (int)(cxform
->rg
*256);gg
= (int)(cxform
->gg
*256);
1059 rb
= (int)(cxform
->rb
*256);gb
= (int)(cxform
->gb
*256);
1060 ra
= (int)(cxform
->ra
*256);ga
= (int)(cxform
->ga
*256);
1061 br
= (int)(cxform
->br
*256);ar
= (int)(cxform
->ar
*256);tr
= (int)(cxform
->tr
*256);
1062 bg
= (int)(cxform
->bg
*256);ag
= (int)(cxform
->ag
*256);tg
= (int)(cxform
->tg
*256);
1063 bb
= (int)(cxform
->bb
*256);ab
= (int)(cxform
->ab
*256);tb
= (int)(cxform
->tb
*256);
1064 ba
= (int)(cxform
->ba
*256);aa
= (int)(cxform
->aa
*256);ta
= (int)(cxform
->ta
*256);
1066 for(t
=0;t
<size
;t
++) {
1067 gfxcolor_t
*pixel
= &img
->data
[t
];
1068 unsigned char r
= (pixel
->r
* rr
+ pixel
->g
* rg
+ pixel
->b
* rb
+ pixel
->a
* ra
+ tr
) / 256;
1069 unsigned char g
= (pixel
->r
* gr
+ pixel
->g
* gg
+ pixel
->b
* gb
+ pixel
->a
* ga
+ tg
) / 256;
1070 unsigned char b
= (pixel
->r
* br
+ pixel
->g
* bg
+ pixel
->b
* bb
+ pixel
->a
* ba
+ tb
) / 256;
1071 unsigned char a
= (pixel
->r
* ar
+ pixel
->g
* ag
+ pixel
->b
* ab
+ pixel
->a
* aa
+ ta
) / 256;
1078 void gfxline_dump(gfxline_t
*line
, FILE*fi
, char*prefix
)
1081 if(line
->type
== gfx_moveTo
) {
1082 fprintf(fi
, "%smoveTo %.2f %.2f\n", prefix
, line
->x
, line
->y
);
1083 } else if(line
->type
== gfx_lineTo
) {
1084 fprintf(fi
, "%slineTo %.2f %.2f\n", prefix
, line
->x
, line
->y
);
1085 } else if(line
->type
== gfx_splineTo
) {
1086 fprintf(fi
, "%ssplineTo (%.2f %.2f) %.2f %.2f\n", prefix
, line
->sx
, line
->sy
, line
->x
, line
->y
);
1092 static char gfxpoint_equals(void*c1
, void*c2
)
1094 return !memcmp(c1
, c2
, sizeof(gfxpoint_t
));
1096 static unsigned int gfxpoint_hash(void*c
)
1098 return string_hash3(c
, sizeof(gfxpoint_t
));
1100 static void* gfxpoint_clone(void*c
)
1102 void*n
= malloc(sizeof(gfxpoint_t
));
1103 memcpy(n
, c
, sizeof(gfxpoint_t
));
1106 static void gfxpoint_destroy(void*c
)
1110 static type_t gfxpoint_type
= {
1111 hash
: (hash_func
)gfxpoint_hash
,
1112 equals
: (equals_func
)gfxpoint_equals
,
1113 dup
: (dup_func
)gfxpoint_clone
,
1114 free
: (free_func
)gfxpoint_destroy
,
1117 /* makes sure that a gfxline is drawn in a single stroke.
1118 E.g. moveto 0,0 lineto 100,0 lineto 100,100
1119 moveto 0,0 lineto 0,100 lineto 100,100
1121 moveto 0,0, lineto 0,100 lineto 100,100 lineto 100,0 lineto 0,0
1123 gfxline_t
* gfxline_restitch(gfxline_t
*line
)
1125 dict_t
*ff
= dict_new2(&gfxpoint_type
);
1126 dict_t
*rev
= dict_new2(&gfxpoint_type
);
1130 gfxline_t
*next
= line
->next
;
1131 if(line
->type
== gfx_moveTo
&& (line
->next
&& line
->next
->type
!= gfx_moveTo
)) {
1132 gfxpoint_t xy
= {line
->x
, line
->y
};
1133 dict_put(ff
, &xy
, line
);
1135 } else if(!line
->next
|| line
->next
->type
== gfx_moveTo
) {
1137 gfxpoint_t xy
= {line
->x
, line
->y
};
1138 dict_put(rev
, &xy
, prev
);
1146 gfxpoint_t pos
= {0,0};
1148 gfxline_t
*result
= 0;
1152 while(dict_count(ff
)) {
1153 char reverse
= 0, stitch
= 1;
1154 gfxline_t
*l
= dict_lookup(ff
, &pos
);
1156 char d
= dict_del2(ff
,&pos
,l
);assert(d
);
1158 l
= dict_lookup(rev
, &pos
);
1161 char d
= dict_del2(rev
,&pos
,l
);assert(d
);
1165 /* try to find *any* entry. this is costly, but
1166 doesn't happen too often */
1168 DICT_ITERATE_DATA(ff
, gfxline_t
*, l2
) {
1173 gfxpoint_t xy
= {l
->x
,l
->y
};
1174 char d
= dict_del2(ff
,&xy
,l
);assert(d
);
1179 while(end
->next
) end
= end
->next
;
1182 char d
= dict_del2(rev
,&pos
,l
);assert(d
);
1184 l
= gfxline_reverse(l
);
1187 char d
= dict_del2(ff
,&pos
,end
);assert(d
);
1190 assert(l
->type
== gfx_moveTo
);
1191 if(stitch
&& !first
) {
1192 /* cut away the moveTo */
1193 gfxline_t
*next
= l
->next
;
1212 gfxline_t
* gfxline_reverse(gfxline_t
*line
)
1216 gfxline_t
*next
= line
->next
;
1217 if(next
&& next
->type
!= gfx_moveTo
) {
1218 line
->type
= next
->type
;
1219 line
->sx
= next
->sx
;
1220 line
->sy
= next
->sy
;
1222 line
->type
= gfx_moveTo
;
1231 void gfxline_normalize(gfxline_t
*line
, double sizex
, double sizey
)
1233 gfxbbox_t b
= gfxline_getbbox(line
);
1234 if(b
.xmax
== b
.xmin
|| b
.ymax
== b
.ymin
)
1237 double w
= b
.xmax
- b
.xmin
;
1238 double h
= b
.ymax
- b
.ymin
;
1239 double fx
= sizex
/w
;
1240 double fy
= sizey
/h
;
1241 double s
= fmin(fx
,fy
);
1248 gfxline_transform(line
, &m
);
1251 void gfxgradient_destroy(gfxgradient_t
*gradient
)
1254 gfxgradient_t
*next
= gradient
->next
;
1260 gfxparams_t
* gfxparams_new()
1262 return (gfxparams_t
*)rfx_calloc(sizeof(gfxparams_t
));
1265 void gfxparams_store(gfxparams_t
*params
, const char*key
, const char*value
)
1267 gfxparam_t
*o
= params
->params
;
1269 if(!strcmp(key
, o
->key
)) {
1270 /* overwrite old value */
1271 free((void*)o
->value
);
1272 o
->value
= strdup(value
);
1277 gfxparam_t
*p
= (gfxparam_t
*)malloc(sizeof(gfxparam_t
));
1278 p
->key
= strdup(key
);
1279 p
->value
= strdup(value
);
1283 params
->last
->next
= p
;
1291 void gfxparams_free(gfxparams_t
*params
)
1293 gfxparam_t
*p
= params
->params
;
1295 gfxparam_t
*next
= p
->next
;
1296 free((void*)p
->key
);
1297 if(p
->value
) free((void*)p
->value
);
1304 static void turnpoint(double x
, double y
, gfxmatrix_t
* m
, double *_x
, double*_y
)
1306 *_x
= m
->m00
*x
+ m
->m10
*y
+ m
->tx
;
1307 *_y
= m
->m01
*x
+ m
->m11
*y
+ m
->ty
;
1310 gfxbbox_t
gfxbbox_transform(gfxbbox_t
*bbox
, gfxmatrix_t
*m
)
1312 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1313 turnpoint(bbox
->xmin
, bbox
->xmin
, m
, &x1
, &y1
);
1314 turnpoint(bbox
->xmax
, bbox
->ymin
, m
, &x2
, &y2
);
1315 turnpoint(bbox
->xmin
, bbox
->ymax
, m
, &x3
, &y3
);
1316 turnpoint(bbox
->xmax
, bbox
->ymax
, m
, &x4
, &y4
);
1318 gfxbbox_t new_bbox
= {x1
, y1
, x1
, y1
};
1319 new_bbox
= gfxbbox_expand_to_point(new_bbox
, x2
, y2
);
1320 new_bbox
= gfxbbox_expand_to_point(new_bbox
, x3
, y3
);
1321 new_bbox
= gfxbbox_expand_to_point(new_bbox
, x4
, y4
);