1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * moon-path.c: Path-based API, similar to cairo but without requiring a cairo_context_t
6 * Sebastien Pouliot <sebastien@ximian.com>
8 * Copyright 2007, 2008 Novell, Inc. (http://www.novell.com)
10 * See the LICENSE file included with the distribution for details.
14 #include "moon-path.h"
19 * @size: the number of items to hold
21 * The number of items varies for each operation (MOVE_TO, LINE_TO,
22 * CURVE_TO and CLOSE_PATH). The caller has the responsability to
23 * calculate the required number of items.
25 * Return value: the allocated #moon_path
28 moon_path_new (int size
)
30 moon_path
* path
= g_new0 (moon_path
, 1);
31 path
->allocated
= size
;
32 path
->cairo
.status
= CAIRO_STATUS_SUCCESS
;
33 path
->cairo
.data
= g_new0 (cairo_path_data_t
, size
);
34 path
->cairo
.num_data
= 0;
40 * @path: an existing #moon_path or NULL
41 * @size: the number of items to hold
43 * The number of items varies for each operation (MOVE_TO, LINE_TO,
44 * CURVE_TO and CLOSE_PATH). The caller has the responsability to
45 * calculate the required number of items.
47 * Return value: the existing #moon_path (if large enough) or a new one
50 moon_path_renew (moon_path
* path
, int size
)
53 return moon_path_new (size
);
55 if (path
->allocated
< size
) {
56 /* not enough space, destroy and recreate */
57 moon_path_destroy (path
);
58 return moon_path_new (size
);
61 /* we can reuse the already allocated structure */
62 moon_path_clear (path
);
68 * @path: an existing #moon_path
70 * Clear the #moon_path structure so it can be reused for a path
74 moon_path_clear (moon_path
* path
)
76 g_return_if_fail (path
!= NULL
);
78 path
->cairo
.status
= CAIRO_STATUS_SUCCESS
;
79 memset (path
->cairo
.data
, 0, path
->allocated
* sizeof (cairo_path_data_t
));
80 path
->cairo
.num_data
= 0;
87 * Free the specified #moon_path
90 moon_path_destroy (moon_path
* path
)
92 g_return_if_fail (path
!= NULL
);
94 if (path
->allocated
> 0)
95 g_free (path
->cairo
.data
);
100 * moon_get_current_point:
101 * @path: a #moon_path
102 * @x: pointer to a double (x coordinate)
103 * @y: pointer to a double (y coordinate)
105 * Get the current point (x,y) on the moon_path. By default (empty path)
109 moon_get_current_point (moon_path
*path
, double *x
, double *y
)
111 if (!path
|| !x
|| !y
) {
112 g_warning ("moon_get_current_point(%p,%p,%p)", path
, x
, y
);
116 int pos
= path
->cairo
.num_data
- 1;
118 cairo_path_data_t
*data
= path
->cairo
.data
;
119 *x
= data
[pos
].point
.x
;
120 *y
= data
[pos
].point
.y
;
127 /* this is a total soptimization, but I don't care ;-) */
128 static inline guint32
129 nearest_pow2 (guint32 num
)
137 #if defined (__GNUC__) && defined (__i386__)
138 __asm__("bsrl %1,%0\n\t"
141 "1:" : "=r" (n
) : "rm" (n
));
155 static inline gboolean
156 moon_path_ensure_space (moon_path
*path
, int need
)
161 if (path
->cairo
.num_data
+ need
<= path
->allocated
)
164 n
= nearest_pow2 (path
->cairo
.num_data
+ need
);
165 if (!(data
= g_try_realloc (path
->cairo
.data
, sizeof (cairo_path_data_t
) * n
)))
168 path
->cairo
.data
= (cairo_path_data_t
*) data
;
176 * @path: a #moon_path
177 * @x: a double with the x coordinate
178 * @y: a double with the y coordinate
180 * Record a move operation to x,y in the #moon_path.
183 moon_move_to (moon_path
*path
, double x
, double y
)
185 g_return_if_fail (path
!= NULL
);
187 if (!moon_path_ensure_space (path
, MOON_PATH_MOVE_TO_LENGTH
))
190 cairo_path_data_t
*data
= path
->cairo
.data
;
191 int pos
= path
->cairo
.num_data
;
193 data
[pos
].header
.type
= CAIRO_PATH_MOVE_TO
;
194 data
[pos
].header
.length
= MOON_PATH_MOVE_TO_LENGTH
;
196 data
[pos
].point
.x
= x
;
197 data
[pos
].point
.y
= y
;
198 path
->cairo
.num_data
+= MOON_PATH_MOVE_TO_LENGTH
;
203 * @path: a #moon_path
204 * @x: a double with the x coordinate
205 * @y: a double with the y coordinate
207 * Record a line operation to x,y in the #moon_path.
210 moon_line_to (moon_path
*path
, double x
, double y
)
212 g_return_if_fail (path
!= NULL
);
214 if (!moon_path_ensure_space (path
, MOON_PATH_LINE_TO_LENGTH
))
217 cairo_path_data_t
*data
= path
->cairo
.data
;
218 int pos
= path
->cairo
.num_data
;
220 data
[pos
].header
.type
= CAIRO_PATH_LINE_TO
;
221 data
[pos
].header
.length
= MOON_PATH_LINE_TO_LENGTH
;
223 data
[pos
].point
.x
= x
;
224 data
[pos
].point
.y
= y
;
225 path
->cairo
.num_data
+= MOON_PATH_LINE_TO_LENGTH
;
230 * @path: a #moon_path
231 * @x1: a double with the x coordinate of the first point
232 * @y1: a double with the y coordinate of the first point
233 * @x2: a double with the x coordinate of the second point
234 * @y2: a double with the y coordinate of the second point
235 * @x3: a double with the x coordinate of the third point
236 * @y3: a double with the y coordinate of the third point
238 * Record a cubic bezier curve operation (x1,y1 x2,y2 x3,y3)
242 moon_curve_to (moon_path
*path
, double x1
, double y1
, double x2
, double y2
, double x3
, double y3
)
244 g_return_if_fail (path
!= NULL
);
246 if (!moon_path_ensure_space (path
, MOON_PATH_CURVE_TO_LENGTH
))
249 cairo_path_data_t
*data
= path
->cairo
.data
;
250 int pos
= path
->cairo
.num_data
;
252 data
[pos
].header
.type
= CAIRO_PATH_CURVE_TO
;
253 data
[pos
].header
.length
= MOON_PATH_CURVE_TO_LENGTH
;
255 data
[pos
].point
.x
= x1
;
256 data
[pos
].point
.y
= y1
;
258 data
[pos
].point
.x
= x2
;
259 data
[pos
].point
.y
= y2
;
261 data
[pos
].point
.x
= x3
;
262 data
[pos
].point
.y
= y3
;
263 path
->cairo
.num_data
+= MOON_PATH_CURVE_TO_LENGTH
;
267 * moon_quad_curve_to:
268 * @path: a #moon_path
269 * @x1: a double with the x coordinate of the first point
270 * @y1: a double with the y coordinate of the first point
271 * @x2: a double with the x coordinate of the second point
272 * @y2: a double with the y coordinate of the second point
274 * Record the quadratic bezier curve operation (x1,y1 x2,y2)
275 * as a (transformed into) cubic bezier curve in the #moon_path.
277 * quadratic to cubic bezier, the original control point and the end control point are the same
278 * http://web.archive.org/web/20020209100930/http://www.icce.rug.nl/erikjan/bluefuzz/beziers/beziers/node2.html
281 moon_quad_curve_to (moon_path
* path
, double x1
, double y1
, double x2
, double y2
)
283 g_return_if_fail (path
!= NULL
);
289 moon_get_current_point (path
, &x0
, &y0
);
291 x2
= x1
+ (x2
- x1
) / 3;
292 y2
= y1
+ (y2
- y1
) / 3;
293 x1
= x0
+ 2 * (x1
- x0
) / 3;
294 y1
= y0
+ 2 * (y1
- y0
) / 3;
296 moon_curve_to (path
, x1
, y1
, x2
, y2
, x3
, y3
);
301 * @path: a #moon_path
302 * @width: a double with the horizontal size of the arc
303 * @height: a double with the vertical size of the arc
304 * @large: a boolean to indicate if this is a large arc
305 * @sweep: a boolean to indicate the sweep direction
306 * @ex: a double with the x coordinate of the end point
307 * @ey: a double with the y coordinate of the end point
309 * Record the arc as multiple cubic curves operation
313 moon_arc_to (moon_path
*path
, double width
, double height
, double angle
, gboolean large
, gboolean sweep
, double ex
, double ey
)
315 g_return_if_fail (path
!= NULL
);
317 // from tests it seems that Silverlight closely follows SVG arc
318 // behavior (which is very different from the model used with GDI+)
319 // some helpful stuff is available here:
320 // http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes
322 // get start point from the existing path
324 moon_get_current_point (path
, &sx
, &sy
);
326 // if start and end points are identical, then no arc is drawn
327 // FIXME: what's the logic (if any) to compare points
328 // e.g. 60 and 60.000002 are drawn while 80 and 80.000003 aren't
329 if (IS_ZERO (ex
- sx
) && IS_ZERO (ey
- sy
))
332 // Correction of out-of-range radii, see F6.6 (step 1)
333 if (IS_ZERO (width
) || IS_ZERO (height
)) {
334 // treat this as a straight line (to end point)
335 moon_line_to (path
, ex
, ey
);
339 // Silverlight "too small to be useful"
340 if (IS_TOO_SMALL (width
) || IS_TOO_SMALL (height
)) {
341 // yes it does mean there's a hole between "normal" FP values and "zero" FP values
342 // and SL doesn't render anything in this twilight sonze
346 // Correction of out-of-range radii, see F6.6.1 (step 2)
347 double rx
= fabs (width
);
348 double ry
= fabs (height
);
350 // convert angle into radians
351 angle
= angle
* M_PI
/ 180.0;
353 // variables required for F6.3.1
354 double cos_phi
= cos (angle
);
355 double sin_phi
= sin (angle
);
356 double dx2
= (sx
- ex
) / 2.0;
357 double dy2
= (sy
- ey
) / 2.0;
358 double x1p
= cos_phi
* dx2
+ sin_phi
* dy2
;
359 double y1p
= cos_phi
* dy2
- sin_phi
* dx2
;
360 double x1p2
= x1p
* x1p
;
361 double y1p2
= y1p
* y1p
;
362 double rx2
= rx
* rx
;
363 double ry2
= ry
* ry
;
365 // Correction of out-of-range radii, see F6.6.2 (step 4)
366 double lambda
= (x1p2
/ rx2
) + (y1p2
/ ry2
);
369 double lambda_root
= sqrt (lambda
);
372 // update rx2 and ry2
377 double cxp
, cyp
, cx
, cy
;
378 double c
= (rx2
* ry2
) - (rx2
* y1p2
) - (ry2
* x1p2
);
380 // check if there is no possible solution (i.e. we can't do a square root of a negative value)
382 // scale uniformly until we have a single solution (see F6.2) i.e. when c == 0.0
383 double scale
= sqrt (1.0 - c
/ (rx2
* ry2
));
386 // update rx2 and ry2
390 // step 2 (F6.5.2) - simplified since c == 0.0
394 // step 3 (F6.5.3 first part) - simplified since cxp and cyp == 0.0
398 // complete c calculation
399 c
= sqrt (c
/ ((rx2
* y1p2
) + (ry2
* x1p2
)));
401 // inverse sign if Fa == Fs
406 cxp
= c
* ( rx
* y1p
/ ry
);
407 cyp
= c
* (-ry
* x1p
/ rx
);
409 // step 3 (F6.5.3 first part)
410 cx
= cos_phi
* cxp
- sin_phi
* cyp
;
411 cy
= sin_phi
* cxp
+ cos_phi
* cyp
;
414 // step 3 (F6.5.3 second part) we now have the center point of the ellipse
415 cx
+= (sx
+ ex
) / 2.0;
416 cy
+= (sy
+ ey
) / 2.0;
419 // we dont' use arccos (as per w3c doc), see http://www.euclideanspace.com/maths/algebra/vectors/angleBetween/index.htm
420 // note: atan2 (0.0, 1.0) == 0.0
421 double at
= atan2 (((y1p
- cyp
) / ry
), ((x1p
- cxp
) / rx
));
422 double theta1
= (at
< 0.0) ? 2.0 * M_PI
+ at
: at
;
424 double nat
= atan2 (((-y1p
- cyp
) / ry
), ((-x1p
- cxp
) / rx
));
425 double delta_theta
= (nat
< at
) ? 2.0 * M_PI
- at
+ nat
: nat
- at
;
428 // ensure delta theta < 0 or else add 360 degrees
429 if (delta_theta
< 0.0)
430 delta_theta
+= 2.0 * M_PI
;
432 // ensure delta theta > 0 or else substract 360 degrees
433 if (delta_theta
> 0.0)
434 delta_theta
-= 2.0 * M_PI
;
437 // add several cubic bezier to approximate the arc (smaller than 90 degrees)
438 // we add one extra segment because we want something smaller than 90deg (i.e. not 90 itself)
439 int segments
= (int) (fabs (delta_theta
/ M_PI_2
)) + 1;
440 double delta
= delta_theta
/ segments
;
442 // http://www.stillhq.com/ctpfaq/2001/comp.text.pdf-faq-2001-04.txt (section 2.13)
443 double bcp
= 4.0 / 3 * (1 - cos (delta
/ 2)) / sin (delta
/ 2);
445 double cos_phi_rx
= cos_phi
* rx
;
446 double cos_phi_ry
= cos_phi
* ry
;
447 double sin_phi_rx
= sin_phi
* rx
;
448 double sin_phi_ry
= sin_phi
* ry
;
450 double cos_theta1
= cos (theta1
);
451 double sin_theta1
= sin (theta1
);
453 if (!moon_path_ensure_space (path
, segments
* MOON_PATH_CURVE_TO_LENGTH
))
457 for (i
= 0; i
< segments
; ++i
) {
458 // end angle (for this segment) = current + delta
459 double theta2
= theta1
+ delta
;
460 double cos_theta2
= cos (theta2
);
461 double sin_theta2
= sin (theta2
);
463 // first control point (based on start point sx,sy)
464 double c1x
= sx
- bcp
* (cos_phi_rx
* sin_theta1
+ sin_phi_ry
* cos_theta1
);
465 double c1y
= sy
+ bcp
* (cos_phi_ry
* cos_theta1
- sin_phi_rx
* sin_theta1
);
467 // end point (for this segment)
468 double ex
= cx
+ (cos_phi_rx
* cos_theta2
- sin_phi_ry
* sin_theta2
);
469 double ey
= cy
+ (sin_phi_rx
* cos_theta2
+ cos_phi_ry
* sin_theta2
);
471 // second control point (based on end point ex,ey)
472 double c2x
= ex
+ bcp
* (cos_phi_rx
* sin_theta2
+ sin_phi_ry
* cos_theta2
);
473 double c2y
= ey
+ bcp
* (sin_phi_rx
* sin_theta2
- cos_phi_ry
* cos_theta2
);
475 moon_curve_to (path
, c1x
, c1y
, c2x
, c2y
, ex
, ey
);
477 // next start point is the current end point (same for angle)
481 // avoid recomputations
482 cos_theta1
= cos_theta2
;
483 sin_theta1
= sin_theta2
;
489 * @path: a #moon_path
490 * @x: a double with the left-most coordinate of the ellipse
491 * @y: a double with the top-most coordinate of the ellipse
492 * @w: a double with the width of the ellipse
493 * @h: a double with the height of the ellipse
495 * Record a series of basic operations that correspond to an ellipse in
496 * the #moon_path. Note that the x,y aren't the center of the ellipse.
499 moon_ellipse (moon_path
*path
, double x
, double y
, double w
, double h
)
501 g_return_if_fail (path
!= NULL
);
507 double brx
= ARC_TO_BEZIER
* rx
;
508 double bry
= ARC_TO_BEZIER
* ry
;
510 if (!moon_path_ensure_space (path
, MOON_PATH_ELLIPSE_LENGTH
))
513 cairo_path_data_t
*data
= path
->cairo
.data
;
514 int pos
= path
->cairo
.num_data
;
516 data
[pos
].header
.type
= CAIRO_PATH_MOVE_TO
;
517 data
[pos
].header
.length
= MOON_PATH_MOVE_TO_LENGTH
;
519 data
[pos
].point
.x
= cx
+ rx
;
520 data
[pos
].point
.y
= cy
;
522 data
[pos
].header
.type
= CAIRO_PATH_CURVE_TO
;
523 data
[pos
].header
.length
= MOON_PATH_CURVE_TO_LENGTH
;
525 data
[pos
].point
.x
= cx
+ rx
;
526 data
[pos
].point
.y
= cy
+ bry
;
528 data
[pos
].point
.x
= cx
+ brx
;
529 data
[pos
].point
.y
= cy
+ ry
;
531 data
[pos
].point
.x
= cx
;
532 data
[pos
].point
.y
= cy
+ ry
;
534 data
[pos
].header
.type
= CAIRO_PATH_CURVE_TO
;
535 data
[pos
].header
.length
= MOON_PATH_CURVE_TO_LENGTH
;
537 data
[pos
].point
.x
= cx
- brx
;
538 data
[pos
].point
.y
= cy
+ ry
;
540 data
[pos
].point
.x
= cx
- rx
;
541 data
[pos
].point
.y
= cy
+ bry
;
543 data
[pos
].point
.x
= cx
- rx
;
544 data
[pos
].point
.y
= cy
;
546 data
[pos
].header
.type
= CAIRO_PATH_CURVE_TO
;
547 data
[pos
].header
.length
= MOON_PATH_CURVE_TO_LENGTH
;
549 data
[pos
].point
.x
= cx
- rx
;
550 data
[pos
].point
.y
= cy
- bry
;
552 data
[pos
].point
.x
= cx
- brx
;
553 data
[pos
].point
.y
= cy
- ry
;
555 data
[pos
].point
.x
= cx
;
556 data
[pos
].point
.y
= cy
- ry
;
558 data
[pos
].header
.type
= CAIRO_PATH_CURVE_TO
;
559 data
[pos
].header
.length
= MOON_PATH_CURVE_TO_LENGTH
;
561 data
[pos
].point
.x
= cx
+ brx
;
562 data
[pos
].point
.y
= cy
- ry
;
564 data
[pos
].point
.x
= cx
+ rx
;
565 data
[pos
].point
.y
= cy
- bry
;
567 data
[pos
].point
.x
= cx
+ rx
;
568 data
[pos
].point
.y
= cy
;
569 path
->cairo
.num_data
+= MOON_PATH_ELLIPSE_LENGTH
;
574 * @path: a #moon_path
575 * @x: a double with the left-most coordinate of the rectangle
576 * @y: a double with the top-most coordinate of the rectangle
577 * @w: a double with the width of the rectangle
578 * @h: a double with the height of the rectangle
580 * Record a series of basic operations that correspond to a rectangle
584 moon_rectangle (moon_path
*path
, double x
, double y
, double w
, double h
)
586 g_return_if_fail (path
!= NULL
);
588 if (!moon_path_ensure_space (path
, MOON_PATH_RECTANGLE_LENGTH
))
591 cairo_path_data_t
*data
= path
->cairo
.data
;
592 int pos
= path
->cairo
.num_data
;
594 data
[pos
].header
.type
= CAIRO_PATH_MOVE_TO
;
595 data
[pos
].header
.length
= MOON_PATH_MOVE_TO_LENGTH
;
597 data
[pos
].point
.x
= x
;
598 data
[pos
].point
.y
= y
;
600 data
[pos
].header
.type
= CAIRO_PATH_LINE_TO
;
601 data
[pos
].header
.length
= MOON_PATH_LINE_TO_LENGTH
;
603 data
[pos
].point
.x
= x
+ w
;
604 data
[pos
].point
.y
= y
;
606 data
[pos
].header
.type
= CAIRO_PATH_LINE_TO
;
607 data
[pos
].header
.length
= MOON_PATH_LINE_TO_LENGTH
;
609 data
[pos
].point
.x
= x
+ w
;
610 data
[pos
].point
.y
= y
+ h
;
612 data
[pos
].header
.type
= CAIRO_PATH_LINE_TO
;
613 data
[pos
].header
.length
= MOON_PATH_LINE_TO_LENGTH
;
615 data
[pos
].point
.x
= x
;
616 data
[pos
].point
.y
= y
+ h
;
618 data
[pos
].header
.type
= CAIRO_PATH_CLOSE_PATH
;
619 data
[pos
].header
.length
= MOON_PATH_CLOSE_PATH_LENGTH
;
620 path
->cairo
.num_data
+= MOON_PATH_RECTANGLE_LENGTH
;
624 * moon_rounded_rectangle:
625 * @path: a #moon_path
626 * @x: a double with the left-most coordinate of the rectangle
627 * @y: a double with the top-most coordinate of the rectangle
628 * @w: a double with the width of the rectangle
629 * @h: a double with the height of the rectangle
630 * @radius_x: a double with the x radius of the rounded corner
631 * @radius_y: a double with the y radius of the rounded corner
633 * Record a series of basic operations that correspond to a rectangle
634 * with rounded corners in the #moon_path.
637 moon_rounded_rectangle (moon_path
*path
, double x
, double y
, double w
, double h
, double radius_x
, double radius_y
)
639 g_return_if_fail (path
!= NULL
);
641 if (!moon_path_ensure_space (path
, MOON_PATH_ROUNDED_RECTANGLE_LENGTH
))
645 radius_x
= -radius_x
;
647 radius_y
= -radius_y
;
649 // test limits (without using multiplications)
650 if (radius_x
> w
- radius_x
)
652 if (radius_y
> h
- radius_y
)
655 // approximate (quite close) the arc using a bezier curve
656 double c1
= ARC_TO_BEZIER
* radius_x
;
657 double c2
= ARC_TO_BEZIER
* radius_y
;
659 cairo_path_data_t
*data
= path
->cairo
.data
;
660 int pos
= path
->cairo
.num_data
;
662 data
[pos
].header
.type
= CAIRO_PATH_MOVE_TO
;
663 data
[pos
].header
.length
= MOON_PATH_MOVE_TO_LENGTH
;
665 data
[pos
].point
.x
= x
+ radius_x
;
666 data
[pos
].point
.y
= y
;
668 data
[pos
].header
.type
= CAIRO_PATH_LINE_TO
;
669 data
[pos
].header
.length
= MOON_PATH_LINE_TO_LENGTH
;
671 data
[pos
].point
.x
= x
+ w
- radius_x
;
672 data
[pos
].point
.y
= y
;
674 data
[pos
].header
.type
= CAIRO_PATH_CURVE_TO
;
675 data
[pos
].header
.length
= MOON_PATH_CURVE_TO_LENGTH
;
677 data
[pos
].point
.x
= x
+ w
- radius_x
+ c1
;
678 data
[pos
].point
.y
= y
;
680 data
[pos
].point
.x
= x
+ w
;
681 data
[pos
].point
.y
= y
+ c2
;
683 data
[pos
].point
.x
= x
+ w
;
684 data
[pos
].point
.y
= y
+ radius_y
;
686 data
[pos
].header
.type
= CAIRO_PATH_LINE_TO
;
687 data
[pos
].header
.length
= MOON_PATH_LINE_TO_LENGTH
;
689 data
[pos
].point
.x
= x
+ w
;
690 data
[pos
].point
.y
= y
+ h
- radius_y
;
692 data
[pos
].header
.type
= CAIRO_PATH_CURVE_TO
;
693 data
[pos
].header
.length
= MOON_PATH_CURVE_TO_LENGTH
;
695 data
[pos
].point
.x
= x
+ w
;
696 data
[pos
].point
.y
= y
+ h
- radius_y
+ c2
;
698 data
[pos
].point
.x
= x
+ w
+ c1
- radius_x
;
699 data
[pos
].point
.y
= y
+ h
;
701 data
[pos
].point
.x
= x
+ w
- radius_x
;
702 data
[pos
].point
.y
= y
+ h
;
704 data
[pos
].header
.type
= CAIRO_PATH_LINE_TO
;
705 data
[pos
].header
.length
= MOON_PATH_LINE_TO_LENGTH
;
707 data
[pos
].point
.x
= x
+ radius_x
;
708 data
[pos
].point
.y
= y
+ h
;
710 data
[pos
].header
.type
= CAIRO_PATH_CURVE_TO
;
711 data
[pos
].header
.length
= MOON_PATH_CURVE_TO_LENGTH
;
713 data
[pos
].point
.x
= x
+ radius_x
- c1
;
714 data
[pos
].point
.y
= y
+ h
;
716 data
[pos
].point
.x
= x
;
717 data
[pos
].point
.y
= y
+ h
- c2
;
719 data
[pos
].point
.x
= x
;
720 data
[pos
].point
.y
= y
+ h
- radius_y
;
722 data
[pos
].header
.type
= CAIRO_PATH_LINE_TO
;
723 data
[pos
].header
.length
= MOON_PATH_LINE_TO_LENGTH
;
725 data
[pos
].point
.x
= x
;
726 data
[pos
].point
.y
= y
+ radius_y
;
728 data
[pos
].header
.type
= CAIRO_PATH_CURVE_TO
;
729 data
[pos
].header
.length
= MOON_PATH_CURVE_TO_LENGTH
;
731 data
[pos
].point
.x
= x
;
732 data
[pos
].point
.y
= y
+ radius_y
- c2
;
734 data
[pos
].point
.x
= x
+ radius_x
- c1
;
735 data
[pos
].point
.y
= y
;
737 data
[pos
].point
.x
= x
+ radius_x
;
738 data
[pos
].point
.y
= y
;
740 data
[pos
].header
.type
= CAIRO_PATH_CLOSE_PATH
;
741 data
[pos
].header
.length
= MOON_PATH_CLOSE_PATH_LENGTH
;
743 path
->cairo
.num_data
+= MOON_PATH_ROUNDED_RECTANGLE_LENGTH
;
748 * @path: a #moon_path
750 * Record a close operation in the #moon_path.
753 moon_close_path (moon_path
*path
)
755 g_return_if_fail (path
!= NULL
);
757 if (!moon_path_ensure_space (path
, MOON_PATH_CLOSE_PATH_LENGTH
))
760 cairo_path_data_t
*data
= path
->cairo
.data
;
761 int pos
= path
->cairo
.num_data
;
763 data
[pos
].header
.type
= CAIRO_PATH_CLOSE_PATH
;
764 data
[pos
].header
.length
= MOON_PATH_CLOSE_PATH_LENGTH
;
765 path
->cairo
.num_data
+= MOON_PATH_CLOSE_PATH_LENGTH
;
771 * @path: a #moon_path
772 * @ox: a pointer to the double for the minimal X value of the path
773 * @oy: a pointer to the double for the minimal Y value of the path
775 * Get the origin point of the path.
778 moon_get_origin (moon_path
*path
, double *ox
, double *oy
)
780 g_return_if_fail (path
!= NULL
);
783 double x
= 0.0, y
= 0.0;
784 cairo_path_t
*c_path
;
786 c_path
= &path
->cairo
;
787 for (; i
< c_path
->num_data
; i
+= c_path
->data
[i
].header
.length
) {
788 cairo_path_data_t
*data
= &c_path
->data
[i
];
789 switch (data
->header
.type
) {
790 case CAIRO_PATH_CURVE_TO
:
795 x
= MIN (x
, data
[1].point
.x
);
796 y
= MIN (y
, data
[1].point
.y
);
798 x
= MIN (x
, data
[2].point
.x
);
799 y
= MIN (y
, data
[2].point
.y
);
800 x
= MIN (x
, data
[3].point
.x
);
801 y
= MIN (y
, data
[3].point
.y
);
803 case CAIRO_PATH_LINE_TO
:
804 case CAIRO_PATH_MOVE_TO
:
809 x
= MIN (x
, data
[1].point
.x
);
810 y
= MIN (y
, data
[1].point
.y
);
825 * @path: a #moon_path
826 * @subpath: the #moon_path to merge into path
828 * Merge 'subpath' into 'path'.
831 moon_merge (moon_path
*path
, moon_path
*subpath
)
833 g_return_if_fail (path
!= NULL
);
834 g_return_if_fail (subpath
!= NULL
);
836 if (!moon_path_ensure_space (path
, subpath
->cairo
.num_data
))
839 cairo_path_data_t
*data
= path
->cairo
.data
;
840 int pos
= path
->cairo
.num_data
;
842 memcpy (&data
[pos
], subpath
->cairo
.data
, subpath
->cairo
.num_data
* sizeof (cairo_path_data_t
));
843 path
->cairo
.num_data
+= subpath
->cairo
.num_data
;
847 * cairo_path_display:
848 * @path: a #cairo_path_t
850 * Display the content of the #cairo_path_t on the console.
851 * For debugging purpose only.
854 cairo_path_display (cairo_path_t
*path
)
857 g_return_if_fail (path
!= NULL
);
860 g_warning ("path %p status %d, num_data %d", path
, path
->status
, path
->num_data
);
861 for (; i
< path
->num_data
; i
+= path
->data
[i
].header
.length
) {
862 cairo_path_data_t
*data
= &path
->data
[i
];
863 switch (data
->header
.type
) {
864 case CAIRO_PATH_CURVE_TO
:
865 g_warning ("\tCAIRO_PATH_CURVE_TO (size %d) (%g, %g) (%g, %g) (%g, %g)", data
->header
.length
,
866 data
[1].point
.x
, data
[1].point
.y
, data
[2].point
.x
, data
[2].point
.y
, data
[3].point
.x
, data
[3].point
.y
);
868 case CAIRO_PATH_LINE_TO
:
869 g_warning ("\tCAIRO_PATH_LINE_TO (size %d) (%g, %g)", data
->header
.length
, data
[1].point
.x
, data
[1].point
.y
);
871 case CAIRO_PATH_MOVE_TO
:
872 g_warning ("\tCAIRO_PATH_MOVE_TO (size %d) (%g, %g)", data
->header
.length
, data
[1].point
.x
, data
[1].point
.y
);
874 case CAIRO_PATH_CLOSE_PATH
:
875 g_warning ("\tCAIRO_PATH_CLOSE_PATH (size %d)", data
->header
.length
);
884 * @path: a #moon_path
886 * Display the content of the #moon_path on the console.
887 * For debugging purpose only.
890 moon_path_display (moon_path
*path
)
892 cairo_path_display (&path
->cairo
);