2 #include "fitz-world.h"
5 enum { BUTT
= 0, ROUND
= 1, SQUARE
= 2, MITER
= 0, BEVEL
= 2 };
30 line(struct sctx
*s
, float x0
, float y0
, float x1
, float y1
)
32 float tx0
= s
->ctm
->a
* x0
+ s
->ctm
->c
* y0
+ s
->ctm
->e
;
33 float ty0
= s
->ctm
->b
* x0
+ s
->ctm
->d
* y0
+ s
->ctm
->f
;
34 float tx1
= s
->ctm
->a
* x1
+ s
->ctm
->c
* y1
+ s
->ctm
->e
;
35 float ty1
= s
->ctm
->b
* x1
+ s
->ctm
->d
* y1
+ s
->ctm
->f
;
36 return fz_insertgel(s
->gel
, tx0
, ty0
, tx1
, ty1
);
51 r
= fabs(s
->linewidth
);
52 theta
= 2 * M_SQRT2
* sqrt(s
->flatness
/ r
);
60 n
= ceil((th0
- th1
) / theta
);
66 n
= ceil((th1
- th0
) / theta
);
71 for (i
= 1; i
< n
; i
++)
73 theta
= th0
+ (th1
- th0
) * i
/ n
;
76 error
= line(s
, xc
+ ox
, yc
+ oy
, xc
+ nx
, yc
+ ny
);
77 if (error
) return error
;
82 error
= line(s
, xc
+ ox
, yc
+ oy
, xc
+ x1
, yc
+ y1
);
83 if (error
) return error
;
89 linestroke(struct sctx
*s
, fz_point a
, fz_point b
)
95 float scale
= s
->linewidth
/ sqrt(dx
* dx
+ dy
* dy
);
96 float dlx
= dy
* scale
;
97 float dly
= -dx
* scale
;
99 error
= line(s
, a
.x
- dlx
, a
.y
- dly
, b
.x
- dlx
, b
.y
- dly
);
100 if (error
) return error
;
102 error
= line(s
, b
.x
+ dlx
, b
.y
+ dly
, a
.x
+ dlx
, a
.y
+ dly
);
103 if (error
) return error
;
109 linejoin(struct sctx
*s
, fz_point a
, fz_point b
, fz_point c
)
112 float miterlimit
= s
->miterlimit
;
113 float linewidth
= s
->linewidth
;
114 int linejoin
= s
->linejoin
;
130 if (dx0
* dx0
+ dy0
* dy0
< FLT_EPSILON
)
132 if (dx1
* dx1
+ dy1
* dy1
< FLT_EPSILON
)
135 scale
= linewidth
/ sqrt(dx0
* dx0
+ dy0
* dy0
);
139 scale
= linewidth
/ sqrt(dx1
* dx1
+ dy1
* dy1
);
143 cross
= dx1
* dy0
- dx0
* dy1
;
145 dmx
= (dlx0
+ dlx1
) * 0.5;
146 dmy
= (dly0
+ dly1
) * 0.5;
147 dmr2
= dmx
* dmx
+ dmy
* dmy
;
149 if (cross
* cross
< FLT_EPSILON
&& dx0
* dx1
+ dy0
* dy1
>= 0)
152 if (linejoin
== MITER
)
153 if (dmr2
* miterlimit
* miterlimit
< linewidth
* linewidth
)
156 if (linejoin
== BEVEL
)
158 error
= line(s
, b
.x
- dlx0
, b
.y
- dly0
, b
.x
- dlx1
, b
.y
- dly1
);
159 if (error
) return error
;
160 error
= line(s
, b
.x
+ dlx1
, b
.y
+ dly1
, b
.x
+ dlx0
, b
.y
+ dly0
);
161 if (error
) return error
;
164 if (linejoin
== MITER
)
166 scale
= linewidth
* linewidth
/ dmr2
;
172 error
= line(s
, b
.x
- dlx0
, b
.y
- dly0
, b
.x
- dlx1
, b
.y
- dly1
);
173 if (error
) return error
;
174 error
= line(s
, b
.x
+ dlx1
, b
.y
+ dly1
, b
.x
+ dmx
, b
.y
+ dmy
);
175 if (error
) return error
;
176 error
= line(s
, b
.x
+ dmx
, b
.y
+ dmy
, b
.x
+ dlx0
, b
.y
+ dly0
);
177 if (error
) return error
;
181 error
= line(s
, b
.x
+ dlx1
, b
.y
+ dly1
, b
.x
+ dlx0
, b
.y
+ dly0
);
182 if (error
) return error
;
183 error
= line(s
, b
.x
- dlx0
, b
.y
- dly0
, b
.x
- dmx
, b
.y
- dmy
);
184 if (error
) return error
;
185 error
= line(s
, b
.x
- dmx
, b
.y
- dmy
, b
.x
- dlx1
, b
.y
- dly1
);
186 if (error
) return error
;
190 if (linejoin
== ROUND
)
194 error
= line(s
, b
.x
- dlx0
, b
.y
- dly0
, b
.x
- dlx1
, b
.y
- dly1
);
195 if (error
) return error
;
196 error
= arc(s
, b
.x
, b
.y
, dlx1
, dly1
, dlx0
, dly0
);
197 if (error
) return error
;
201 error
= line(s
, b
.x
+ dlx1
, b
.y
+ dly1
, b
.x
+ dlx0
, b
.y
+ dly0
);
202 if (error
) return error
;
203 error
= arc(s
, b
.x
, b
.y
, -dlx0
, -dly0
, -dlx1
, -dly1
);
204 if (error
) return error
;
212 linecap(struct sctx
*s
, fz_point a
, fz_point b
)
215 float flatness
= s
->flatness
;
216 float linewidth
= s
->linewidth
;
217 int linecap
= s
->linecap
;
219 float dx
= b
.x
- a
.x
;
220 float dy
= b
.y
- a
.y
;
222 float scale
= linewidth
/ sqrt(dx
* dx
+ dy
* dy
);
223 float dlx
= dy
* scale
;
224 float dly
= -dx
* scale
;
227 return line(s
, b
.x
- dlx
, b
.y
- dly
, b
.x
+ dlx
, b
.y
+ dly
);
229 if (linecap
== ROUND
)
232 int n
= ceil(M_PI
/ (2.0 * M_SQRT2
* sqrt(flatness
/ linewidth
)));
233 float ox
= b
.x
- dlx
;
234 float oy
= b
.y
- dly
;
235 for (i
= 1; i
< n
; i
++)
237 float theta
= M_PI
* i
/ n
;
238 float cth
= cos(theta
);
239 float sth
= sin(theta
);
240 float nx
= b
.x
- dlx
* cth
- dly
* sth
;
241 float ny
= b
.y
- dly
* cth
+ dlx
* sth
;
242 error
= line(s
, ox
, oy
, nx
, ny
);
243 if (error
) return error
;
247 error
= line(s
, ox
, oy
, b
.x
+ dlx
, b
.y
+ dly
);
248 if (error
) return error
;
251 if (linecap
== SQUARE
)
253 error
= line(s
, b
.x
- dlx
, b
.y
- dly
,
256 if (error
) return error
;
257 error
= line(s
, b
.x
- dlx
- dly
,
261 if (error
) return error
;
262 error
= line(s
, b
.x
+ dlx
- dly
,
264 b
.x
+ dlx
, b
.y
+ dly
);
265 if (error
) return error
;
272 linedot(struct sctx
*s
, fz_point a
)
275 float flatness
= s
->flatness
;
276 float linewidth
= s
->linewidth
;
277 int n
= ceil(M_PI
/ (M_SQRT2
* sqrt(flatness
/ linewidth
)));
278 float ox
= a
.x
- linewidth
;
281 for (i
= 1; i
< n
; i
++)
283 float theta
= M_PI
* 2 * i
/ n
;
284 float cth
= cos(theta
);
285 float sth
= sin(theta
);
286 float nx
= a
.x
- cth
* linewidth
;
287 float ny
= a
.y
+ sth
* linewidth
;
288 error
= line(s
, ox
, oy
, nx
, ny
);
289 if (error
) return error
;
293 error
= line(s
, ox
, oy
, a
.x
- linewidth
, a
.y
);
294 if (error
) return error
;
299 strokeflush(struct sctx
*s
)
305 error
= linecap(s
, s
->beg
[1], s
->beg
[0]);
306 if (error
) return error
;
307 error
= linecap(s
, s
->seg
[0], s
->seg
[1]);
308 if (error
) return error
;
312 error
= linedot(s
, s
->beg
[0]);
313 if (error
) return error
;
322 strokemoveto(struct sctx
*s
, fz_point cur
)
326 error
= strokeflush(s
);
327 if (error
) return error
;
338 strokelineto(struct sctx
*s
, fz_point cur
)
342 float dx
= cur
.x
- s
->seg
[s
->sn
-1].x
;
343 float dy
= cur
.y
- s
->seg
[s
->sn
-1].y
;
345 if (dx
* dx
+ dy
* dy
< s
->flatness
* s
->flatness
* 0.25)
351 error
= linestroke(s
, s
->seg
[s
->sn
-1], cur
);
352 if (error
) return error
;
356 error
= linejoin(s
, s
->seg
[0], s
->seg
[1], cur
);
357 if (error
) return error
;
359 s
->seg
[0] = s
->seg
[1];
364 s
->seg
[s
->sn
++] = cur
;
366 s
->beg
[s
->bn
++] = cur
;
372 strokeclosepath(struct sctx
*s
)
378 error
= strokelineto(s
, s
->beg
[0]);
379 if (error
) return error
;
381 if (s
->seg
[1].x
== s
->beg
[0].x
&& s
->seg
[1].y
== s
->beg
[0].y
)
382 error
= linejoin(s
, s
->seg
[0], s
->beg
[0], s
->beg
[1]);
384 error
= linejoin(s
, s
->seg
[1], s
->beg
[0], s
->beg
[1]);
385 if (error
) return error
;
390 error
= linedot(s
, s
->beg
[0]);
391 if (error
) return error
;
402 strokebezier(struct sctx
*s
,
417 /* termination check */
419 dmax
= MAX(dmax
, ABS(ya
- yb
));
420 dmax
= MAX(dmax
, ABS(xd
- xc
));
421 dmax
= MAX(dmax
, ABS(yd
- yc
));
422 if (dmax
< s
->flatness
) {
426 return strokelineto(s
, p
);
444 xab
*= 0.5f
; yab
*= 0.5f
;
445 xbc
*= 0.5f
; ybc
*= 0.5f
;
446 xcd
*= 0.5f
; ycd
*= 0.5f
;
448 xabc
*= 0.25f
; yabc
*= 0.25f
;
449 xbcd
*= 0.25f
; ybcd
*= 0.25f
;
451 xabcd
*= 0.125f
; yabcd
*= 0.125f
;
453 error
= strokebezier(s
, xa
, ya
, xab
, yab
, xabc
, yabc
, xabcd
, yabcd
);
457 return strokebezier(s
, xabcd
, yabcd
, xbcd
, ybcd
, xcd
, ycd
, xd
, yd
);
461 fz_strokepath(fz_gel
*gel
, fz_pathnode
*path
, fz_matrix ctm
, float flatness
)
465 fz_point p0
, p1
, p2
, p3
;
470 s
.flatness
= flatness
;
472 s
.linecap
= path
->linecap
;
473 s
.linejoin
= path
->linejoin
;
474 s
.linewidth
= path
->linewidth
* 0.5;
475 s
.miterlimit
= path
->miterlimit
;
482 while (i
< path
->len
)
484 switch (path
->els
[i
++].k
)
487 p1
.x
= path
->els
[i
++].v
;
488 p1
.y
= path
->els
[i
++].v
;
489 error
= strokemoveto(&s
, p1
);
496 p1
.x
= path
->els
[i
++].v
;
497 p1
.y
= path
->els
[i
++].v
;
498 error
= strokelineto(&s
, p1
);
505 p1
.x
= path
->els
[i
++].v
;
506 p1
.y
= path
->els
[i
++].v
;
507 p2
.x
= path
->els
[i
++].v
;
508 p2
.y
= path
->els
[i
++].v
;
509 p3
.x
= path
->els
[i
++].v
;
510 p3
.y
= path
->els
[i
++].v
;
511 error
= strokebezier(&s
, p0
.x
, p0
.y
, p1
.x
, p1
.y
, p2
.x
, p2
.y
, p3
.x
, p3
.y
);
518 error
= strokeclosepath(&s
);
525 return strokeflush(&s
);
529 dashmoveto(struct sctx
*s
, fz_point a
)
533 s
->phase
= s
->dash
->phase
;
535 while (s
->phase
>= s
->dash
->array
[s
->offset
])
537 s
->toggle
= !s
->toggle
;
538 s
->phase
-= s
->dash
->array
[s
->offset
];
540 if (s
->offset
== s
->dash
->len
)
547 return strokemoveto(s
, a
);
553 dashlineto(struct sctx
*s
, fz_point b
)
557 float total
, used
, ratio
;
564 total
= sqrt(dx
* dx
+ dy
* dy
);
567 while (total
- used
> s
->dash
->array
[s
->offset
] - s
->phase
)
569 used
+= s
->dash
->array
[s
->offset
] - s
->phase
;
570 ratio
= used
/ total
;
571 m
.x
= a
.x
+ ratio
* dx
;
572 m
.y
= a
.y
+ ratio
* dy
;
575 error
= strokelineto(s
, m
);
577 error
= strokemoveto(s
, m
);
581 s
->toggle
= !s
->toggle
;
584 if (s
->offset
== s
->dash
->len
)
588 s
->phase
+= total
- used
;
593 return strokelineto(s
, b
);
599 dashbezier(struct sctx
*s
,
614 /* termination check */
616 dmax
= MAX(dmax
, ABS(ya
- yb
));
617 dmax
= MAX(dmax
, ABS(xd
- xc
));
618 dmax
= MAX(dmax
, ABS(yd
- yc
));
619 if (dmax
< s
->flatness
) {
623 return dashlineto(s
, p
);
641 xab
*= 0.5f
; yab
*= 0.5f
;
642 xbc
*= 0.5f
; ybc
*= 0.5f
;
643 xcd
*= 0.5f
; ycd
*= 0.5f
;
645 xabc
*= 0.25f
; yabc
*= 0.25f
;
646 xbcd
*= 0.25f
; ybcd
*= 0.25f
;
648 xabcd
*= 0.125f
; yabcd
*= 0.125f
;
650 error
= dashbezier(s
, xa
, ya
, xab
, yab
, xabc
, yabc
, xabcd
, yabcd
);
651 if (error
) return error
;
652 return dashbezier(s
, xabcd
, yabcd
, xbcd
, ybcd
, xcd
, ycd
, xd
, yd
);
656 fz_dashpath(fz_gel
*gel
, fz_pathnode
*path
, fz_matrix ctm
, float flatness
)
660 fz_point p0
, p1
, p2
, p3
, beg
;
665 s
.flatness
= flatness
;
667 s
.linecap
= path
->linecap
;
668 s
.linejoin
= path
->linejoin
;
669 s
.linewidth
= path
->linewidth
* 0.5;
670 s
.miterlimit
= path
->miterlimit
;
682 while (i
< path
->len
)
684 switch (path
->els
[i
++].k
)
687 p1
.x
= path
->els
[i
++].v
;
688 p1
.y
= path
->els
[i
++].v
;
689 error
= dashmoveto(&s
, p1
);
696 p1
.x
= path
->els
[i
++].v
;
697 p1
.y
= path
->els
[i
++].v
;
698 error
= dashlineto(&s
, p1
);
705 p1
.x
= path
->els
[i
++].v
;
706 p1
.y
= path
->els
[i
++].v
;
707 p2
.x
= path
->els
[i
++].v
;
708 p2
.y
= path
->els
[i
++].v
;
709 p3
.x
= path
->els
[i
++].v
;
710 p3
.y
= path
->els
[i
++].v
;
711 error
= dashbezier(&s
, p0
.x
, p0
.y
, p1
.x
, p1
.y
, p2
.x
, p2
.y
, p3
.x
, p3
.y
);
718 error
= dashlineto(&s
, beg
);
725 return strokeflush(&s
);