base-types: Don't free zero point and rect
[profile/ivi/clutter.git] / clutter / clutter-base-types.c
1 /*
2  * Clutter.
3  *
4  * An OpenGL based 'interactive canvas' library.
5  *
6  * Authored By Matthew Allum  <mallum@openedhand.com>
7  *
8  * Copyright (C) 2006 OpenedHand
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library 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 GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
22  */
23
24 /**
25  * SECTION:clutter-geometric-types
26  * @Title: Base geometric types
27  * @Short_Description: Common geometric data types used by Clutter
28  *
29  * Clutter defines a set of geometric data structures that are commonly used
30  * across the whole API.
31  */
32
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
36
37 #include "clutter-types.h"
38 #include "clutter-private.h"
39
40 #include <math.h>
41
42 #define FLOAT_EPSILON   (1e-15)
43
44 \f
45
46 /*
47  * ClutterGeometry
48  */
49
50 static ClutterGeometry*
51 clutter_geometry_copy (const ClutterGeometry *geometry)
52 {
53   return g_slice_dup (ClutterGeometry, geometry);
54 }
55
56 static void
57 clutter_geometry_free (ClutterGeometry *geometry)
58 {
59   if (G_LIKELY (geometry != NULL))
60     g_slice_free (ClutterGeometry, geometry);
61 }
62
63 /**
64  * clutter_geometry_union:
65  * @geometry_a: a #ClutterGeometry
66  * @geometry_b: another #ClutterGeometry
67  * @result: (out): location to store the result
68  *
69  * Find the union of two rectangles represented as #ClutterGeometry.
70  *
71  * Since: 1.4
72  */
73 void
74 clutter_geometry_union (const ClutterGeometry *geometry_a,
75                         const ClutterGeometry *geometry_b,
76                         ClutterGeometry       *result)
77 {
78   /* We don't try to handle rectangles that can't be represented
79    * as a signed integer box */
80   gint x_1 = MIN (geometry_a->x, geometry_b->x);
81   gint y_1 = MIN (geometry_a->y, geometry_b->y);
82   gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
83                   geometry_b->x + (gint)geometry_b->width);
84   gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
85                   geometry_b->y + (gint)geometry_b->height);
86   result->x = x_1;
87   result->y = y_1;
88   result->width = x_2 - x_1;
89   result->height = y_2 - y_1;
90 }
91
92 /**
93  * clutter_geometry_intersects:
94  * @geometry0: The first geometry to test
95  * @geometry1: The second geometry to test
96  *
97  * Determines if @geometry0 and geometry1 intersect returning %TRUE if
98  * they do else %FALSE.
99  *
100  * Return value: %TRUE of @geometry0 and geometry1 intersect else
101  * %FALSE.
102  *
103  * Since: 1.4
104  */
105 gboolean
106 clutter_geometry_intersects (const ClutterGeometry *geometry0,
107                              const ClutterGeometry *geometry1)
108 {
109   if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
110       geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
111       (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
112       (geometry1->y + (gint)geometry1->height) <= geometry0->y)
113     return FALSE;
114   else
115     return TRUE;
116 }
117
118 static gboolean
119 clutter_geometry_progress (const GValue *a,
120                            const GValue *b,
121                            gdouble       progress,
122                            GValue       *retval)
123 {
124   const ClutterGeometry *a_geom = g_value_get_boxed (a);
125   const ClutterGeometry *b_geom = g_value_get_boxed (b);
126   ClutterGeometry res = { 0, };
127   gint a_width = a_geom->width;
128   gint b_width = b_geom->width;
129   gint a_height = a_geom->height;
130   gint b_height = b_geom->height;
131
132   res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
133   res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
134
135   res.width = a_width + (b_width - a_width) * progress;
136   res.height = a_height + (b_height - a_height) * progress;
137
138   g_value_set_boxed (retval, &res);
139
140   return TRUE;
141 }
142
143 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
144                                clutter_geometry_copy,
145                                clutter_geometry_free,
146                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
147
148 \f
149
150 /*
151  * ClutterVertices
152  */
153
154 /**
155  * clutter_vertex_new:
156  * @x: X coordinate
157  * @y: Y coordinate
158  * @z: Z coordinate
159  *
160  * Creates a new #ClutterVertex for the point in 3D space
161  * identified by the 3 coordinates @x, @y, @z.
162  *
163  * This function is the logical equivalent of:
164  *
165  * |[
166  *   clutter_vertex_init (clutter_vertex_alloc (), x, y, z);
167  * ]|
168  *
169  * Return value: (transfer full): the newly allocated #ClutterVertex.
170  *   Use clutter_vertex_free() to free the resources
171  *
172  * Since: 1.0
173  */
174 ClutterVertex *
175 clutter_vertex_new (gfloat x,
176                     gfloat y,
177                     gfloat z)
178 {
179   return clutter_vertex_init (clutter_vertex_alloc (), x, y, z);
180 }
181
182 /**
183  * clutter_vertex_alloc:
184  *
185  * Allocates a new, empty #ClutterVertex.
186  *
187  * Return value: (transfer full): the newly allocated #ClutterVertex.
188  *   Use clutter_vertex_free() to free its resources
189  *
190  * Since: 1.12
191  */
192 ClutterVertex *
193 clutter_vertex_alloc (void)
194 {
195   return g_slice_new0 (ClutterVertex);
196 }
197
198 /**
199  * clutter_vertex_init:
200  * @vertex: a #ClutterVertex
201  * @x: X coordinate
202  * @y: Y coordinate
203  * @z: Z coordinate
204  *
205  * Initializes @vertex with the given coordinates.
206  *
207  * Return value: (transfer none): the initialized #ClutterVertex
208  *
209  * Since: 1.10
210  */
211 ClutterVertex *
212 clutter_vertex_init (ClutterVertex *vertex,
213                      gfloat         x,
214                      gfloat         y,
215                      gfloat         z)
216 {
217   g_return_val_if_fail (vertex != NULL, NULL);
218
219   vertex->x = x;
220   vertex->y = y;
221   vertex->z = z;
222
223   return vertex;
224 }
225
226 /**
227  * clutter_vertex_copy:
228  * @vertex: a #ClutterVertex
229  *
230  * Copies @vertex
231  *
232  * Return value: (transfer full): a newly allocated copy of #ClutterVertex.
233  *   Use clutter_vertex_free() to free the allocated resources
234  *
235  * Since: 1.0
236  */
237 ClutterVertex *
238 clutter_vertex_copy (const ClutterVertex *vertex)
239 {
240   if (G_LIKELY (vertex != NULL))
241     return g_slice_dup (ClutterVertex, vertex);
242
243   return NULL;
244 }
245
246 /**
247  * clutter_vertex_free:
248  * @vertex: a #ClutterVertex
249  *
250  * Frees a #ClutterVertex allocated using clutter_vertex_alloc() or
251  * clutter_vertex_copy().
252  *
253  * Since: 1.0
254  */
255 void
256 clutter_vertex_free (ClutterVertex *vertex)
257 {
258   if (G_UNLIKELY (vertex != NULL))
259     g_slice_free (ClutterVertex, vertex);
260 }
261
262 /**
263  * clutter_vertex_equal:
264  * @vertex_a: a #ClutterVertex
265  * @vertex_b: a #ClutterVertex
266  *
267  * Compares @vertex_a and @vertex_b for equality
268  *
269  * Return value: %TRUE if the passed #ClutterVertex are equal
270  *
271  * Since: 1.0
272  */
273 gboolean
274 clutter_vertex_equal (const ClutterVertex *vertex_a,
275                       const ClutterVertex *vertex_b)
276 {
277   g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
278
279   if (vertex_a == vertex_b)
280     return TRUE;
281
282   return fabsf (vertex_a->x - vertex_b->x) < FLOAT_EPSILON &&
283          fabsf (vertex_a->y - vertex_b->y) < FLOAT_EPSILON &&
284          fabsf (vertex_a->z - vertex_b->z) < FLOAT_EPSILON;
285 }
286
287 static gboolean
288 clutter_vertex_progress (const GValue *a,
289                          const GValue *b,
290                          gdouble       progress,
291                          GValue       *retval)
292 {
293   const ClutterVertex *av = g_value_get_boxed (a);
294   const ClutterVertex *bv = g_value_get_boxed (b);
295   ClutterVertex res;
296
297   res.x = av->x + (bv->x - av->x) * progress;
298   res.y = av->y + (bv->y - av->y) * progress;
299   res.z = av->z + (bv->z - av->z) * progress;
300
301   g_value_set_boxed (retval, &res);
302
303   return TRUE;
304 }
305
306 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
307                                clutter_vertex_copy,
308                                clutter_vertex_free,
309                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
310
311 \f
312
313 /*
314  * ClutterMargin
315  */
316
317 /**
318  * clutter_margin_new:
319  *
320  * Creates a new #ClutterMargin.
321  *
322  * Return value: (transfer full): a newly allocated #ClutterMargin. Use
323  *   clutter_margin_free() to free the resources associated with it when
324  *   done.
325  *
326  * Since: 1.10
327  */
328 ClutterMargin *
329 clutter_margin_new (void)
330 {
331   return g_slice_new0 (ClutterMargin);
332 }
333
334 /**
335  * clutter_margin_copy:
336  * @margin_: a #ClutterMargin
337  *
338  * Creates a new #ClutterMargin and copies the contents of @margin_ into
339  * the newly created structure.
340  *
341  * Return value: (transfer full): a copy of the #ClutterMargin.
342  *
343  * Since: 1.10
344  */
345 ClutterMargin *
346 clutter_margin_copy (const ClutterMargin *margin_)
347 {
348   if (G_LIKELY (margin_ != NULL))
349     return g_slice_dup (ClutterMargin, margin_);
350
351   return NULL;
352 }
353
354 /**
355  * clutter_margin_free:
356  * @margin_: a #ClutterMargin
357  *
358  * Frees the resources allocated by clutter_margin_new() and
359  * clutter_margin_copy().
360  *
361  * Since: 1.10
362  */
363 void
364 clutter_margin_free (ClutterMargin *margin_)
365 {
366   if (G_LIKELY (margin_ != NULL))
367     g_slice_free (ClutterMargin, margin_);
368 }
369
370 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
371                      clutter_margin_copy,
372                      clutter_margin_free)
373
374 \f
375
376 /*
377  * ClutterPoint
378  */
379
380 static const ClutterPoint _clutter_point_zero = CLUTTER_POINT_INIT_ZERO;
381
382 /**
383  * clutter_point_zero:
384  *
385  * A point centered at (0, 0).
386  *
387  * The returned value can be used as a guard.
388  *
389  * Return value: a point centered in (0, 0); the returned #ClutterPoint
390  *   is owned by Clutter and it should not be modified or freed.
391  *
392  * Since: 1.12
393  */
394 const ClutterPoint *
395 clutter_point_zero (void)
396 {
397   return &_clutter_point_zero;
398 }
399
400 /**
401  * clutter_point_alloc:
402  *
403  * Allocates a new #ClutterPoint.
404  *
405  * Return value: (transfer full): the newly allocated #ClutterPoint.
406  *   Use clutter_point_free() to free its resources.
407  *
408  * Since: 1.12
409  */
410 ClutterPoint *
411 clutter_point_alloc (void)
412 {
413   return g_slice_new0 (ClutterPoint);
414 }
415
416 /**
417  * clutter_point_init:
418  * @point: a #ClutterPoint
419  * @x: the X coordinate of the point
420  * @y: the Y coordinate of the point
421  *
422  * Initializes @point with the given coordinates.
423  *
424  * Return value: (transfer none): the initialized #ClutterPoint
425  *
426  * Since: 1.12
427  */
428 ClutterPoint *
429 clutter_point_init (ClutterPoint *point,
430                     float         x,
431                     float         y)
432 {
433   g_return_val_if_fail (point != NULL, NULL);
434
435   point->x = x;
436   point->y = y;
437
438   return point;
439 }
440
441 /**
442  * clutter_point_copy:
443  * @point: a #ClutterPoint
444  *
445  * Creates a new #ClutterPoint with the same coordinates of @point.
446  *
447  * Return value: (transfer full): a newly allocated #ClutterPoint.
448  *   Use clutter_point_free() to free its resources.
449  *
450  * Since: 1.12
451  */
452 ClutterPoint *
453 clutter_point_copy (const ClutterPoint *point)
454 {
455   return g_slice_dup (ClutterPoint, point);
456 }
457
458 /**
459  * clutter_point_free:
460  * @point: a #ClutterPoint
461  *
462  * Frees the resources allocated for @point.
463  *
464  * Since: 1.12
465  */
466 void
467 clutter_point_free (ClutterPoint *point)
468 {
469   if (point != NULL && point != &_clutter_point_zero)
470     g_slice_free (ClutterPoint, point);
471 }
472
473 /**
474  * clutter_point_equals:
475  * @a: the first #ClutterPoint to compare
476  * @b: the second #ClutterPoint to compare
477  *
478  * Compares two #ClutterPoint for equality.
479  *
480  * Return value: %TRUE if the #ClutterPoints are equal
481  *
482  * Since: 1.12
483  */
484 gboolean
485 clutter_point_equals (const ClutterPoint *a,
486                       const ClutterPoint *b)
487 {
488   if (a == b)
489     return TRUE;
490
491   if (a == NULL || b == NULL)
492     return FALSE;
493
494   return fabsf (a->x - b->x) < FLOAT_EPSILON &&
495          fabsf (a->y - b->y) < FLOAT_EPSILON;
496 }
497
498 /**
499  * clutter_point_distance:
500  * @a: a #ClutterPoint
501  * @b: a #ClutterPoint
502  * @x_distance: (out) (allow-none): return location for the horizontal
503  *   distance between the points
504  * @y_distance: (out) (allow-none): return location for the vertical
505  *   distance between the points
506  *
507  * Computes the distance between two #ClutterPoint.
508  *
509  * Return value: the distance between the points.
510  *
511  * Since: 1.12
512  */
513 float
514 clutter_point_distance (const ClutterPoint *a,
515                         const ClutterPoint *b,
516                         float              *x_distance,
517                         float              *y_distance)
518 {
519   float x_d, y_d;
520
521   g_return_val_if_fail (a != NULL, 0.f);
522   g_return_val_if_fail (b != NULL, 0.f);
523
524   if (clutter_point_equals (a, b))
525     return 0.f;
526
527   x_d = (a->x - b->x);
528   y_d = (a->y - b->y);
529
530   if (x_distance != NULL)
531     *x_distance = fabsf (x_d);
532
533   if (y_distance != NULL)
534     *y_distance = fabsf (y_d);
535
536   return sqrt ((x_d * x_d) + (y_d * y_d));
537 }
538
539 static gboolean
540 clutter_point_progress (const GValue *a,
541                         const GValue *b,
542                         gdouble       progress,
543                         GValue       *retval)
544 {
545   const ClutterPoint *ap = g_value_get_boxed (a);
546   const ClutterPoint *bp = g_value_get_boxed (b);
547   ClutterPoint res = CLUTTER_POINT_INIT (0, 0);
548
549   res.x = ap->x + (bp->x - ap->x) * progress;
550   res.y = ap->y + (bp->y - ap->y) * progress;
551
552   g_value_set_boxed (retval, &res);
553
554   return TRUE;
555 }
556
557 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterPoint, clutter_point,
558                                clutter_point_copy,
559                                clutter_point_free,
560                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_point_progress))
561
562 \f
563
564 /*
565  * ClutterSize
566  */
567
568 /**
569  * clutter_size_alloc:
570  *
571  * Allocates a new #ClutterSize.
572  *
573  * Return value: (transfer full): the newly allocated #ClutterSize.
574  *   Use clutter_size_free() to free its resources.
575  *
576  * Since: 1.12
577  */
578 ClutterSize *
579 clutter_size_alloc (void)
580 {
581   return g_slice_new0 (ClutterSize);
582 }
583
584 /**
585  * clutter_size_init:
586  * @size: a #ClutterSize
587  * @width: the width
588  * @height: the height
589  *
590  * Initializes a #ClutterSize with the given dimensions.
591  *
592  * Return value: (transfer none): the initialized #ClutterSize
593  *
594  * Since: 1.12
595  */
596 ClutterSize *
597 clutter_size_init (ClutterSize *size,
598                    float        width,
599                    float        height)
600 {
601   g_return_val_if_fail (size != NULL, NULL);
602
603   size->width = width;
604   size->height = height;
605
606   return size;
607 }
608
609 /**
610  * clutter_size_copy:
611  * @size: a #ClutterSize
612  *
613  * Creates a new #ClutterSize and duplicates @size.
614  *
615  * Return value: (transfer full): the newly allocated #ClutterSize.
616  *   Use clutter_size_free() to free its resources.
617  *
618  * Since: 1.12
619  */
620 ClutterSize *
621 clutter_size_copy (const ClutterSize *size)
622 {
623   return g_slice_dup (ClutterSize, size);
624 }
625
626 /**
627  * clutter_size_free:
628  * @size: a #ClutterSize
629  *
630  * Frees the resources allocated for @size.
631  *
632  * Since: 1.12
633  */
634 void
635 clutter_size_free (ClutterSize *size)
636 {
637   if (size != NULL)
638     g_slice_free (ClutterSize, size);
639 }
640
641 /**
642  * clutter_size_equals:
643  * @a: a #ClutterSize to compare
644  * @b: a #ClutterSize to compare
645  *
646  * Compares two #ClutterSize for equality.
647  *
648  * Return value: %TRUE if the two #ClutterSize are equal
649  *
650  * Since: 1.12
651  */
652 gboolean
653 clutter_size_equals (const ClutterSize *a,
654                      const ClutterSize *b)
655 {
656   if (a == b)
657     return TRUE;
658
659   if (a == NULL || b == NULL)
660     return FALSE;
661
662   return fabsf (a->width - b->width) < FLOAT_EPSILON &&
663          fabsf (a->height - b->height) < FLOAT_EPSILON;
664 }
665
666 static gboolean
667 clutter_size_progress (const GValue *a,
668                        const GValue *b,
669                        gdouble       progress,
670                        GValue       *retval)
671 {
672   const ClutterSize *as = g_value_get_boxed (a);
673   const ClutterSize *bs = g_value_get_boxed (b);
674   ClutterSize res = CLUTTER_SIZE_INIT (0, 0);
675
676   res.width = as->width + (bs->width - as->width) * progress;
677   res.height = as->height + (bs->height - as->height) * progress;
678
679   g_value_set_boxed (retval, &res);
680
681   return TRUE;
682 }
683
684 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterSize, clutter_size,
685                                clutter_size_copy,
686                                clutter_size_free,
687                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_size_progress))
688
689 \f
690
691 /*
692  * ClutterRect
693  */
694
695 static const ClutterRect _clutter_rect_zero = CLUTTER_RECT_INIT_ZERO;
696
697 static gboolean clutter_rect_progress (const GValue *a,
698                                        const GValue *b,
699                                        gdouble       progress,
700                                        GValue       *res);
701
702 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterRect, clutter_rect,
703                                clutter_rect_copy,
704                                clutter_rect_free,
705                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_rect_progress))
706
707 static inline void
708 clutter_rect_normalize_internal (ClutterRect *rect)
709 {
710   if (rect->size.width >= 0.f && rect->size.height >= 0.f)
711     return;
712
713   if (rect->size.width < 0.f)
714     {
715       float size = fabsf (rect->size.width);
716
717       rect->origin.x -= size;
718       rect->size.width = size;
719     }
720
721   if (rect->size.height < 0.f)
722     {
723       float size = fabsf (rect->size.height);
724
725       rect->origin.y -= size;
726       rect->size.height = size;
727     }
728 }
729
730 /**
731  * clutter_rect_zero:
732  *
733  * A #ClutterRect with #ClutterRect.origin set at (0, 0) and a size
734  * of 0.
735  *
736  * The returned value can be used as a guard.
737  *
738  * Return value: a rectangle with origin in (0, 0) and a size of 0.
739  *   The returned #ClutterRect is owned by Clutter and it should not
740  *   be modified or freed.
741  *
742  * Since: 1.12
743  */
744 const ClutterRect *
745 clutter_rect_zero (void)
746 {
747   return &_clutter_rect_zero;
748 }
749
750 /**
751  * clutter_rect_alloc:
752  *
753  * Creates a new, empty #ClutterRect.
754  *
755  * You can use clutter_rect_init() to initialize the returned rectangle,
756  * for instance:
757  *
758  * |[
759  *   rect = clutter_rect_init (clutter_rect_alloc (), x, y, width, height);
760  * ]|
761  *
762  * Return value: (transfer full): the newly allocated #ClutterRect.
763  *   Use clutter_rect_free() to free its resources
764  *
765  * Since: 1.12
766  */
767 ClutterRect *
768 clutter_rect_alloc (void)
769 {
770   return g_slice_new0 (ClutterRect);
771 }
772
773 /**
774  * clutter_rect_init:
775  * @rect: a #ClutterRect
776  * @x: X coordinate of the origin
777  * @y: Y coordinate of the origin
778  * @width: width of the rectangle
779  * @height: height of the rectangle
780  *
781  * Initializes a #ClutterRect with the given origin and size.
782  *
783  * Return value: (transfer none): the updated rectangle
784  *
785  * Since: 1.12
786  */
787 ClutterRect *
788 clutter_rect_init (ClutterRect *rect,
789                    float        x,
790                    float        y,
791                    float        width,
792                    float        height)
793 {
794   g_return_val_if_fail (rect != NULL, NULL);
795
796   rect->origin.x = x;
797   rect->origin.y = y;
798
799   rect->size.width = width;
800   rect->size.height = height;
801
802   return rect;
803 }
804
805 /**
806  * clutter_rect_copy:
807  * @rect: a #ClutterRect
808  *
809  * Copies @rect into a new #ClutterRect instance.
810  *
811  * Return value: (transfer full): the newly allocate copy of @rect.
812  *   Use clutter_rect_free() to free the associated resources
813  *
814  * Since: 1.12
815  */
816 ClutterRect *
817 clutter_rect_copy (const ClutterRect *rect)
818 {
819   if (rect != NULL)
820     {
821       ClutterRect *res;
822
823       res = g_slice_dup (ClutterRect, rect);
824       clutter_rect_normalize_internal (res);
825
826       return res;
827     }
828
829   return NULL;
830 }
831
832 /**
833  * clutter_rect_free:
834  * @rect: a #ClutterRect
835  *
836  * Frees the resources allocated by @rect.
837  *
838  * Since: 1.12
839  */
840 void
841 clutter_rect_free (ClutterRect *rect)
842 {
843   if (rect != NULL && rect != &_clutter_rect_zero)
844     g_slice_free (ClutterRect, rect);
845 }
846
847 /**
848  * clutter_rect_equals:
849  * @a: a #ClutterRect
850  * @b: a #ClutterRect
851  *
852  * Checks whether @a and @b are equals.
853  *
854  * This function will normalize both @a and @b before comparing
855  * their origin and size.
856  *
857  * Return value: %TRUE if the rectangles match in origin and size.
858  *
859  * Since: 1.12
860  */
861 gboolean
862 clutter_rect_equals (ClutterRect *a,
863                      ClutterRect *b)
864 {
865   if (a == b)
866     return TRUE;
867
868   if (a == NULL || b == NULL)
869     return FALSE;
870
871   clutter_rect_normalize_internal (a);
872   clutter_rect_normalize_internal (b);
873
874   return clutter_point_equals (&a->origin, &b->origin) &&
875          clutter_size_equals (&a->size, &b->size);
876 }
877
878 /**
879  * clutter_rect_normalize:
880  * @rect: a #ClutterRect
881  *
882  * Normalizes a #ClutterRect.
883  *
884  * A #ClutterRect is defined by the area covered by its size; this means
885  * that a #ClutterRect with #ClutterRect.origin in [ 0, 0 ] and a
886  * #ClutterRect.size of [ 10, 10 ] is equivalent to a #ClutterRect with
887  * #ClutterRect.origin in [ 10, 10 ] and a #ClutterRect.size of [ -10, -10 ].
888  *
889  * This function is useful to ensure that a rectangle has positive width
890  * and height; it will modify the passed @rect and normalize its size.
891  *
892  * Since: 1.12
893  */
894 ClutterRect *
895 clutter_rect_normalize (ClutterRect *rect)
896 {
897   g_return_val_if_fail (rect != NULL, NULL);
898
899   clutter_rect_normalize_internal (rect);
900
901   return rect;
902 }
903
904 /**
905  * clutter_rect_get_center:
906  * @rect: a #ClutterRect
907  * @center: (out caller-allocates): a #ClutterPoint
908  *
909  * Retrieves the center of @rect, after normalizing the rectangle,
910  * and updates @center with the correct coordinates.
911  *
912  * Since: 1.12
913  */
914 void
915 clutter_rect_get_center (ClutterRect  *rect,
916                          ClutterPoint *center)
917 {
918   g_return_if_fail (rect != NULL);
919   g_return_if_fail (center != NULL);
920
921   clutter_rect_normalize_internal (rect);
922
923   center->x = rect->origin.x + (rect->size.width / 2.0f);
924   center->y = rect->origin.y + (rect->size.height / 2.0f);
925 }
926
927 /**
928  * clutter_rect_contains_point:
929  * @rect: a #ClutterRect
930  * @point: the point to check
931  *
932  * Checks whether @point is contained by @rect, after normalizing the
933  * rectangle.
934  *
935  * Return value: %TRUE if the @point is contained by @rect.
936  *
937  * Since: 1.12
938  */
939 gboolean
940 clutter_rect_contains_point (ClutterRect  *rect,
941                              ClutterPoint *point)
942 {
943   g_return_val_if_fail (rect != NULL, FALSE);
944   g_return_val_if_fail (point != NULL, FALSE);
945
946   clutter_rect_normalize_internal (rect);
947
948   return (point->x >= rect->origin.x) &&
949          (point->y >= rect->origin.y) &&
950          (point->x <= (rect->origin.x + rect->size.width)) &&
951          (point->y <= (rect->origin.y + rect->size.height));
952 }
953
954 /**
955  * clutter_rect_contains_rect:
956  * @a: a #ClutterRect
957  * @b: a #ClutterRect
958  *
959  * Checks whether @a contains @b.
960  *
961  * The first rectangle contains the second if the union of the
962  * two #ClutterRect is equal to the first rectangle.
963  *
964  * Return value: %TRUE if the first rectangle contains the second.
965  *
966  * Since: 1.12
967  */
968 gboolean
969 clutter_rect_contains_rect (ClutterRect *a,
970                             ClutterRect *b)
971 {
972   ClutterRect res;
973
974   g_return_val_if_fail (a != NULL, FALSE);
975   g_return_val_if_fail (b != NULL, FALSE);
976
977   clutter_rect_union (a, b, &res);
978
979   return clutter_rect_equals (a, &res);
980 }
981
982 /**
983  * clutter_rect_union:
984  * @a: a #ClutterRect
985  * @b: a #ClutterRect
986  * @res: (out caller-allocates): a #ClutterRect
987  *
988  * Computes the smallest possible rectangle capable of fully containing
989  * both @a and @b, and places it into @res.
990  *
991  * This function will normalize both @a and @b prior to computing their
992  * union.
993  *
994  * Since: 1.12
995  */
996 void
997 clutter_rect_union (ClutterRect *a,
998                     ClutterRect *b,
999                     ClutterRect *res)
1000 {
1001   g_return_if_fail (a != NULL);
1002   g_return_if_fail (b != NULL);
1003   g_return_if_fail (res != NULL);
1004
1005   clutter_rect_normalize_internal (a);
1006   clutter_rect_normalize_internal (b);
1007
1008   res->origin.x = MIN (a->origin.x, b->origin.x);
1009   res->origin.y = MIN (a->origin.y, b->origin.y);
1010
1011   res->size.width = MAX (a->size.width, b->size.width);
1012   res->size.height = MAX (a->size.height, b->size.height);
1013 }
1014
1015 /**
1016  * clutter_rect_intersection:
1017  * @a: a #ClutterRect
1018  * @b: a #ClutterRect
1019  * @res: (out caller-allocates) (allow-none): a #ClutterRect, or %NULL
1020  *
1021  * Computes the intersection of @a and @b, and places it in @res, if @res
1022  * is not %NULL.
1023  *
1024  * This function will normalize both @a and @b prior to computing their
1025  * intersection.
1026  *
1027  * This function can be used to simply check if the intersection of @a and @b
1028  * is not empty, by using %NULL for @res.
1029  *
1030  * Return value: %TRUE if the intersection of @a and @b is not empty
1031  *
1032  * Since: 1.12
1033  */
1034 gboolean
1035 clutter_rect_intersection (ClutterRect *a,
1036                            ClutterRect *b,
1037                            ClutterRect *res)
1038 {
1039   float x_1, y_1, x_2, y_2;
1040
1041   g_return_val_if_fail (a != NULL, FALSE);
1042   g_return_val_if_fail (b != NULL, FALSE);
1043
1044   clutter_rect_normalize_internal (a);
1045   clutter_rect_normalize_internal (b);
1046
1047   x_1 = MAX (a->origin.x, b->origin.y);
1048   y_1 = MAX (a->origin.y, b->origin.y);
1049   x_2 = MIN (a->origin.x + a->size.width, b->origin.x + b->size.width);
1050   y_2 = MIN (a->origin.y + a->size.height, b->origin.y + b->size.height);
1051
1052   if (x_1 >= x_2 || y_1 >= y_2)
1053     {
1054       if (res != NULL)
1055         clutter_rect_init (res, 0.f, 0.f, 0.f, 0.f);
1056
1057       return FALSE;
1058     }
1059
1060   if (res != NULL)
1061     clutter_rect_init (res, x_1, y_1, x_2 - x_1, y_2 - y_1);
1062
1063   return TRUE;
1064 }
1065
1066 /**
1067  * clutter_rect_offset:
1068  * @rect: a #ClutterRect
1069  * @d_x: the horizontal offset value
1070  * @d_y: the vertical offset value
1071  *
1072  * Offsets the origin of @rect by the given values, after normalizing
1073  * the rectangle.
1074  *
1075  * Since: 1.12
1076  */
1077 void
1078 clutter_rect_offset (ClutterRect *rect,
1079                      float        d_x,
1080                      float        d_y)
1081 {
1082   g_return_if_fail (rect != NULL);
1083
1084   clutter_rect_normalize_internal (rect);
1085
1086   rect->origin.x += d_x;
1087   rect->origin.y += d_y;
1088 }
1089
1090 /**
1091  * clutter_rect_inset:
1092  * @rect: a #ClutterRect
1093  * @d_x: an horizontal value; a positive @d_x will create an inset rectangle,
1094  *   and a negative value will create a larger rectangle
1095  * @d_y: a vertical value; a positive @d_x will create an inset rectangle,
1096  *   and a negative value will create a larger rectangle
1097  *
1098  * Normalizes the @rect and offsets its origin by the @d_x and @d_y values;
1099  * the size is adjusted by (2 * @d_x, 2 * @d_y).
1100  *
1101  * If @d_x and @d_y are positive the size of the rectangle is decreased; if
1102  * the values are negative, the size of the rectangle is increased.
1103  *
1104  * If the resulting rectangle has a negative width or height, the size is
1105  * set to 0.
1106  *
1107  * Since: 1.12
1108  */
1109 void
1110 clutter_rect_inset (ClutterRect *rect,
1111                     float        d_x,
1112                     float        d_y)
1113 {
1114   g_return_if_fail (rect != NULL);
1115
1116   clutter_rect_normalize_internal (rect);
1117
1118   rect->origin.x += d_x;
1119   rect->origin.y += d_y;
1120
1121   if (d_x >= 0.f)
1122     rect->size.width -= (d_x * 2.f);
1123   else
1124     rect->size.width += (d_x * -2.f);
1125
1126   if (d_y >= 0.f)
1127     rect->size.height -= (d_y * 2.f);
1128   else
1129     rect->size.height += (d_y * -2.f);
1130
1131   if (rect->size.width < 0.f)
1132     rect->size.width = 0.f;
1133
1134   if (rect->size.height < 0.f)
1135     rect->size.height = 0.f;
1136 }
1137
1138 /**
1139  * clutter_rect_clamp_to_pixel:
1140  * @rect: a #ClutterRect
1141  *
1142  * Rounds the origin of @rect downwards to the nearest integer, and rounds
1143  * the size of @rect upwards to the nearest integer, so that @rect is
1144  * updated to the smallest rectangle capable of fully containing the
1145  * original, fractional rectangle.
1146  *
1147  * Since: 1.12
1148  */
1149 void
1150 clutter_rect_clamp_to_pixel (ClutterRect *rect)
1151 {
1152   g_return_if_fail (rect != NULL);
1153
1154   clutter_rect_normalize_internal (rect);
1155
1156   rect->origin.x = floorf (rect->origin.x);
1157   rect->origin.y = floorf (rect->origin.y);
1158
1159   rect->size.width = ceilf (rect->size.width);
1160   rect->size.height = ceilf (rect->size.height);
1161 }
1162
1163 /**
1164  * clutter_rect_get_x:
1165  * @rect: a #ClutterRect
1166  *
1167  * Retrieves the X coordinate of the origin of @rect.
1168  *
1169  * Return value: the X coordinate of the origin of the rectangle
1170  *
1171  * Since: 1.12
1172  */
1173 float
1174 clutter_rect_get_x (ClutterRect *rect)
1175 {
1176   g_return_val_if_fail (rect != NULL, 0.f);
1177
1178   clutter_rect_normalize_internal (rect);
1179
1180   return rect->origin.x;
1181 }
1182
1183 /**
1184  * clutter_rect_get_y:
1185  * @rect: a #ClutterRect
1186  *
1187  * Retrieves the Y coordinate of the origin of @rect.
1188  *
1189  * Return value: the Y coordinate of the origin of the rectangle
1190  *
1191  * Since: 1.12
1192  */
1193 float
1194 clutter_rect_get_y (ClutterRect *rect)
1195 {
1196   g_return_val_if_fail (rect != NULL, 0.f);
1197
1198   clutter_rect_normalize_internal (rect);
1199
1200   return rect->origin.y;
1201 }
1202
1203 /**
1204  * clutter_rect_get_width:
1205  * @rect: a #ClutterRect
1206  *
1207  * Retrieves the width of @rect.
1208  *
1209  * Return value: the width of the rectangle
1210  *
1211  * Since: 1.12
1212  */
1213 float
1214 clutter_rect_get_width (ClutterRect *rect)
1215 {
1216   g_return_val_if_fail (rect != NULL, 0.f);
1217
1218   clutter_rect_normalize_internal (rect);
1219
1220   return rect->size.width;
1221 }
1222
1223 /**
1224  * clutter_rect_get_height:
1225  * @rect: a #ClutterRect
1226  *
1227  * Retrieves the height of @rect.
1228  *
1229  * Return value: the height of the rectangle
1230  *
1231  * Since: 1.12
1232  */
1233 float
1234 clutter_rect_get_height (ClutterRect *rect)
1235 {
1236   g_return_val_if_fail (rect != NULL, 0.f);
1237
1238   clutter_rect_normalize_internal (rect);
1239
1240   return rect->size.height;
1241 }
1242
1243 static gboolean
1244 clutter_rect_progress (const GValue *a,
1245                        const GValue *b,
1246                        gdouble       progress,
1247                        GValue       *retval)
1248 {
1249   const ClutterRect *rect_a = g_value_get_boxed (a);
1250   const ClutterRect *rect_b = g_value_get_boxed (b);
1251   ClutterRect res = CLUTTER_RECT_INIT_ZERO;
1252
1253 #define INTERPOLATE(r_a,r_b,member,field,factor)     ((r_a)->member.field + (((r_b)->member.field - ((r_b)->member.field)) * (factor)))
1254
1255   res.origin.x = INTERPOLATE (rect_a, rect_b, origin, x, progress);
1256   res.origin.y = INTERPOLATE (rect_a, rect_b, origin, y, progress);
1257
1258   res.size.width = INTERPOLATE (rect_a, rect_b, size, width, progress);
1259   res.size.height = INTERPOLATE (rect_a, rect_b, size, height, progress);
1260
1261 #undef INTERPOLATE
1262
1263   clutter_rect_normalize_internal (&res);
1264
1265   g_value_set_boxed (retval, &res);
1266
1267   return TRUE;
1268 }