1/* graphene-rect.c: Rectangular type
2 *
3 * SPDX-License-Identifier: MIT
4 *
5 * Copyright 2014 Emmanuele Bassi
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 */
25
26/**
27 * SECTION:graphene-rect
28 * @title: Rectangle
29 * @short_description: Rectangular shape type
30 *
31 * #graphene_rect_t is a type representing a rectangle through an origin
32 * #graphene_point_t point and a #graphene_size_t size.
33 *
34 * ![](rectangle.png)
35 *
36 * Operations on a #graphene_rect_t will normalize the rectangle, to
37 * ensure that the origin is always the top-left corner of the rectangle
38 * and that the size is always positive.
39 */
40
41#include "graphene-private.h"
42
43#include "graphene-rect.h"
44
45#include <math.h>
46
47/*< private >
48 * graphene_rect_normalize_in_place:
49 * @r: (inout): a #graphene_rect_t
50 *
51 * Normalizes the passed #graphene_rect_t.
52 */
53static inline void
54graphene_rect_normalize_in_place (graphene_rect_t *r)
55{
56 if (r->size.width < 0.f)
57 {
58 float size = fabsf (x: r->size.width);
59
60 r->origin.x -= size;
61 r->size.width = size;
62 }
63
64 if (r->size.height < 0.f)
65 {
66 float size = fabsf (x: r->size.height);
67
68 r->origin.y -= size;
69 r->size.height = size;
70 }
71}
72
73/**
74 * graphene_rect_alloc:
75 *
76 * Allocates a new #graphene_rect_t.
77 *
78 * The contents of the returned rectangle are undefined.
79 *
80 * Returns: (transfer full): the newly allocated rectangle
81 *
82 * Since: 1.0
83 */
84graphene_rect_t *
85graphene_rect_alloc (void)
86{
87 return calloc (nmemb: 1, size: sizeof (graphene_rect_t));
88}
89
90/**
91 * graphene_rect_free:
92 * @r: a #graphene_rect_t
93 *
94 * Frees the resources allocated by graphene_rect_alloc().
95 *
96 * Since: 1.0
97 */
98void
99graphene_rect_free (graphene_rect_t *r)
100{
101 free (ptr: r);
102}
103
104/**
105 * graphene_rect_init:
106 * @r: a #graphene_rect_t
107 * @x: the X coordinate of the @graphene_rect_t.origin
108 * @y: the Y coordinate of the @graphene_rect_t.origin
109 * @width: the width of the @graphene_rect_t.size
110 * @height: the height of the @graphene_rect_t.size
111 *
112 * Initializes the given #graphene_rect_t with the given values.
113 *
114 * This function will implicitly normalize the #graphene_rect_t
115 * before returning.
116 *
117 * Returns: (transfer none): the initialized rectangle
118 *
119 * Since: 1.0
120 */
121graphene_rect_t *
122graphene_rect_init (graphene_rect_t *r,
123 float x,
124 float y,
125 float width,
126 float height)
127{
128 graphene_point_init (p: &r->origin, x, y);
129 graphene_size_init (s: &r->size, width, height);
130
131 graphene_rect_normalize_in_place (r);
132
133 return r;
134}
135
136/**
137 * graphene_rect_init_from_rect:
138 * @r: a #graphene_rect_t
139 * @src: a #graphene_rect_t
140 *
141 * Initializes @r using the given @src rectangle.
142 *
143 * This function will implicitly normalize the #graphene_rect_t
144 * before returning.
145 *
146 * Returns: (transfer none): the initialized rectangle
147 *
148 * Since: 1.0
149 */
150graphene_rect_t *
151graphene_rect_init_from_rect (graphene_rect_t *r,
152 const graphene_rect_t *src)
153{
154 *r = *src;
155
156 graphene_rect_normalize_in_place (r);
157
158 return r;
159}
160
161static bool
162rect_equal (const void *p1,
163 const void *p2)
164{
165 const graphene_rect_t *a = p1;
166 const graphene_rect_t *b = p2;
167
168 graphene_rect_t r_a, r_b;
169
170 graphene_rect_normalize_r (r: a, res: &r_a);
171 graphene_rect_normalize_r (r: b, res: &r_b);
172
173 return graphene_point_equal (a: &r_a.origin, b: &r_b.origin) &&
174 graphene_size_equal (a: &r_a.size, b: &r_b.size);
175}
176
177/**
178 * graphene_rect_equal:
179 * @a: a #graphene_rect_t
180 * @b: a #graphene_rect_t
181 *
182 * Checks whether the two given rectangle are equal.
183 *
184 * Returns: `true` if the rectangles are equal
185 *
186 * Since: 1.0
187 */
188bool
189graphene_rect_equal (const graphene_rect_t *a,
190 const graphene_rect_t *b)
191{
192 return graphene_pointer_equal (p1: a, p2: b, func: rect_equal);
193}
194
195/**
196 * graphene_rect_normalize:
197 * @r: a #graphene_rect_t
198 *
199 * Normalizes the passed rectangle.
200 *
201 * This function ensures that the size of the rectangle is made of
202 * positive values, and that the origin is the top-left corner of
203 * the rectangle.
204 *
205 * Returns: (transfer none): the normalized rectangle
206 *
207 * Since: 1.0
208 */
209graphene_rect_t *
210graphene_rect_normalize (graphene_rect_t *r)
211{
212 graphene_rect_normalize_in_place (r);
213
214 return r;
215}
216
217/**
218 * graphene_rect_normalize_r:
219 * @r: a #graphene_rect_t
220 * @res: (out caller-allocates): the return location for the
221 * normalized rectangle
222 *
223 * Normalizes the passed rectangle.
224 *
225 * This function ensures that the size of the rectangle is made of
226 * positive values, and that the origin is in the top-left corner
227 * of the rectangle.
228 *
229 * Since: 1.4
230 */
231void
232graphene_rect_normalize_r (const graphene_rect_t *r,
233 graphene_rect_t *res)
234{
235 if (res != r)
236 *res = *r;
237
238 graphene_rect_normalize_in_place (r: res);
239}
240
241/**
242 * graphene_rect_get_center:
243 * @r: a #graphene_rect_t
244 * @p: (out caller-allocates): return location for a #graphene_point_t
245 *
246 * Retrieves the coordinates of the center of the given rectangle.
247 *
248 * Since: 1.0
249 */
250void
251graphene_rect_get_center (const graphene_rect_t *r,
252 graphene_point_t *p)
253{
254 graphene_rect_t rr;
255
256 rr = *r;
257 graphene_rect_normalize_in_place (r: &rr);
258
259 graphene_point_init (p,
260 x: rr.origin.x + (rr.size.width / 2.f),
261 y: rr.origin.y + (rr.size.height / 2.f));
262}
263
264/**
265 * graphene_rect_get_top_left:
266 * @r: a #graphene_rect_t
267 * @p: (out caller-allocates): return location for a #graphene_point_t
268 *
269 * Retrieves the coordinates of the top-left corner of the given rectangle.
270 *
271 * Since: 1.0
272 */
273void
274graphene_rect_get_top_left (const graphene_rect_t *r,
275 graphene_point_t *p)
276{
277 graphene_rect_t rr;
278
279 rr = *r;
280 graphene_rect_normalize_in_place (r: &rr);
281
282 graphene_point_init_from_point (p, src: &rr.origin);
283}
284
285/**
286 * graphene_rect_get_top_right:
287 * @r: a #graphene_rect_t
288 * @p: (out caller-allocates): return location for a #graphene_point_t
289 *
290 * Retrieves the coordinates of the top-right corner of the given rectangle.
291 *
292 * Since: 1.0
293 */
294void
295graphene_rect_get_top_right (const graphene_rect_t *r,
296 graphene_point_t *p)
297{
298 graphene_rect_t rr;
299
300 rr = *r;
301 graphene_rect_normalize_in_place (r: &rr);
302
303 graphene_point_init (p, x: rr.origin.x + rr.size.width, y: rr.origin.y);
304}
305
306/**
307 * graphene_rect_get_bottom_left:
308 * @r: a #graphene_rect_t
309 * @p: (out caller-allocates): return location for a #graphene_point_t
310 *
311 * Retrieves the coordinates of the bottom-left corner of the given rectangle.
312 *
313 * Since: 1.0
314 */
315void
316graphene_rect_get_bottom_left (const graphene_rect_t *r,
317 graphene_point_t *p)
318{
319 graphene_rect_t rr;
320
321 rr = *r;
322 graphene_rect_normalize_in_place (r: &rr);
323
324 graphene_point_init (p, x: rr.origin.x, y: rr.origin.y + rr.size.height);
325}
326
327/**
328 * graphene_rect_get_bottom_right:
329 * @r: a #graphene_rect_t
330 * @p: (out caller-allocates): return location for a #graphene_point_t
331 *
332 * Retrieves the coordinates of the bottom-right corner of the given rectangle.
333 *
334 * Since: 1.0
335 */
336void
337graphene_rect_get_bottom_right (const graphene_rect_t *r,
338 graphene_point_t *p)
339{
340 graphene_rect_t rr;
341
342 rr = *r;
343 graphene_rect_normalize_in_place (r: &rr);
344
345 graphene_point_init (p,
346 x: rr.origin.x + rr.size.width,
347 y: rr.origin.y + rr.size.height);
348}
349
350/**
351 * graphene_rect_get_vertices:
352 * @r: a #graphene_rect_t
353 * @vertices: (out) (array fixed-size=4): return location for an array
354 * of 4 #graphene_vec2_t
355 *
356 * Computes the four vertices of a #graphene_rect_t.
357 *
358 * Since: 1.4
359 */
360void
361graphene_rect_get_vertices (const graphene_rect_t *r,
362 graphene_vec2_t vertices[])
363{
364 graphene_rect_t rr;
365
366 graphene_rect_normalize_r (r, res: &rr);
367
368 graphene_vec2_init (v: &vertices[0], x: rr.origin.x, y: rr.origin.y);
369 graphene_vec2_init (v: &vertices[1], x: rr.origin.x + rr.size.width, y: rr.origin.y);
370 graphene_vec2_init (v: &vertices[2], x: rr.origin.x + rr.size.width, y: rr.origin.y + rr.size.height);
371 graphene_vec2_init (v: &vertices[3], x: rr.origin.x, y: rr.origin.y + rr.size.height);
372}
373
374#define GRAPHENE_RECT_GET(arg, part, field) \
375 float \
376 graphene_rect_get_ ## field (const graphene_rect_t * arg) \
377 { \
378 graphene_rect_t rr; \
379\
380 rr = *arg; \
381 graphene_rect_normalize_in_place (&rr); \
382\
383 return rr.part.field; \
384 }
385
386/**
387 * graphene_rect_get_x:
388 * @r: a #graphene_rect_t
389 *
390 * Retrieves the normalized X coordinate of the origin of the given
391 * rectangle.
392 *
393 * Returns: the normalized X coordinate of the rectangle
394 *
395 * Since: 1.0
396 */
397GRAPHENE_RECT_GET (r, origin, x)
398
399/**
400 * graphene_rect_get_y:
401 * @r: a #graphene_rect_t
402 *
403 * Retrieves the normalized Y coordinate of the origin of the given
404 * rectangle.
405 *
406 * Returns: the normalized Y coordinate of the rectangle
407 *
408 * Since: 1.0
409 */
410GRAPHENE_RECT_GET (r, origin, y)
411
412/**
413 * graphene_rect_get_width:
414 * @r: a #graphene_rect_t
415 *
416 * Retrieves the normalized width of the given rectangle.
417 *
418 * Returns: the normalized width of the rectangle
419 *
420 * Since: 1.0
421 */
422GRAPHENE_RECT_GET (r, size, width)
423
424/**
425 * graphene_rect_get_height:
426 * @r: a #graphene_rect_t
427 *
428 * Retrieves the normalized height of the given rectangle.
429 *
430 * Returns: the normalized height of the rectangle
431 *
432 * Since: 1.0
433 */
434GRAPHENE_RECT_GET (r, size, height)
435
436#undef GRAPHENE_RECT_GET
437
438/**
439 * graphene_rect_get_area:
440 * @r: a #graphene_rect_t
441 *
442 * Compute the area of given normalized rectangle.
443 *
444 * Returns: the area of the normalized rectangle
445 *
446 * Since: 1.10
447 */
448float
449graphene_rect_get_area (const graphene_rect_t *r)
450{
451 graphene_rect_t rr;
452
453 graphene_rect_normalize_r (r, res: &rr);
454
455 return rr.size.width * rr.size.height;
456}
457
458/**
459 * graphene_rect_union:
460 * @a: a #graphene_rect_t
461 * @b: a #graphene_rect_t
462 * @res: (out caller-allocates): return location for a #graphene_rect_t
463 *
464 * Computes the union of the two given rectangles.
465 *
466 * ![](rectangle-union.png)
467 *
468 * The union in the image above is the blue outline.
469 *
470 * Since: 1.0
471 */
472void
473graphene_rect_union (const graphene_rect_t *a,
474 const graphene_rect_t *b,
475 graphene_rect_t *res)
476{
477 graphene_rect_t ra, rb;
478
479 ra = *a;
480 rb = *b;
481
482 graphene_rect_normalize_in_place (r: &ra);
483 graphene_rect_normalize_in_place (r: &rb);
484
485 res->origin.x = MIN (ra.origin.x, rb.origin.x);
486 res->origin.y = MIN (ra.origin.y, rb.origin.y);
487
488 res->size.width = MAX (ra.origin.x + ra.size.width, rb.origin.x + rb.size.width) - res->origin.x;
489 res->size.height = MAX (ra.origin.y + ra.size.height, rb.origin.y + rb.size.height) - res->origin.y;
490}
491
492/**
493 * graphene_rect_intersection:
494 * @a: a #graphene_rect_t
495 * @b: a #graphene_rect_t
496 * @res: (out caller-allocates) (optional): return location for
497 * a #graphene_rect_t
498 *
499 * Computes the intersection of the two given rectangles.
500 *
501 * ![](rectangle-intersection.png)
502 *
503 * The intersection in the image above is the blue outline.
504 *
505 * If the two rectangles do not intersect, @res will contain
506 * a degenerate rectangle with origin in (0, 0) and a size of 0.
507 *
508 * Returns: `true` if the two rectangles intersect
509 *
510 * Since: 1.0
511 */
512bool
513graphene_rect_intersection (const graphene_rect_t *a,
514 const graphene_rect_t *b,
515 graphene_rect_t *res)
516{
517 graphene_rect_t ra, rb;
518 float x_1, y_1, x_2, y_2;
519
520 ra = *a;
521 rb = *b;
522
523 graphene_rect_normalize_in_place (r: &ra);
524 graphene_rect_normalize_in_place (r: &rb);
525
526 x_1 = MAX (ra.origin.x, rb.origin.x);
527 y_1 = MAX (ra.origin.y, rb.origin.y);
528 x_2 = MIN (ra.origin.x + ra.size.width, rb.origin.x + rb.size.width);
529 y_2 = MIN (ra.origin.y + ra.size.height, rb.origin.y + rb.size.height);
530
531 if (x_1 >= x_2 || y_1 >= y_2)
532 {
533 if (res != NULL)
534 graphene_rect_init (r: res, x: 0.0f, y: 0.0f, width: 0.0f, height: 0.0f);
535
536 return false;
537 }
538
539 if (res != NULL)
540 graphene_rect_init (r: res, x: x_1, y: y_1, width: x_2 - x_1, height: y_2 - y_1);
541
542 return true;
543}
544
545/**
546 * graphene_rect_contains_point:
547 * @r: a #graphene_rect_t
548 * @p: a #graphene_point_t
549 *
550 * Checks whether a #graphene_rect_t contains the given coordinates.
551 *
552 * Returns: `true` if the rectangle contains the point
553 *
554 * Since: 1.0
555 */
556bool
557graphene_rect_contains_point (const graphene_rect_t *r,
558 const graphene_point_t *p)
559{
560 graphene_rect_t rr;
561
562 rr = *r;
563 graphene_rect_normalize_in_place (r: &rr);
564
565 return p->x >= rr.origin.x &&
566 p->y >= rr.origin.y &&
567 p->x <= (rr.origin.x + rr.size.width) &&
568 p->y <= (rr.origin.y + rr.size.height);
569}
570
571/**
572 * graphene_rect_contains_rect:
573 * @a: a #graphene_rect_t
574 * @b: a #graphene_rect_t
575 *
576 * Checks whether a #graphene_rect_t fully contains the given
577 * rectangle.
578 *
579 * Returns: `true` if the rectangle @a fully contains @b
580 *
581 * Since: 1.0
582 */
583bool
584graphene_rect_contains_rect (const graphene_rect_t *a,
585 const graphene_rect_t *b)
586{
587 graphene_rect_t res;
588
589 graphene_rect_union (a, b, res: &res);
590
591 return graphene_rect_equal (a, b: &res);
592}
593
594/**
595 * graphene_rect_offset:
596 * @r: a #graphene_rect_t
597 * @d_x: the horizontal offset
598 * @d_y: the vertical offset
599 *
600 * Offsets the origin by @d_x and @d_y.
601 *
602 * The size of the rectangle is unchanged.
603 *
604 * Returns: (transfer none): the offset rectangle
605 *
606 * Since: 1.0
607 */
608graphene_rect_t *
609graphene_rect_offset (graphene_rect_t *r,
610 float d_x,
611 float d_y)
612{
613 graphene_rect_offset_r (r, d_x, d_y, res: r);
614
615 return r;
616}
617
618/**
619 * graphene_rect_offset_r:
620 * @r: a #graphene_rect_t
621 * @d_x: the horizontal offset
622 * @d_y: the vertical offset
623 * @res: (out caller-allocates): return location for the offset
624 * rectangle
625 *
626 * Offsets the origin of the given rectangle by @d_x and @d_y.
627 *
628 * The size of the rectangle is left unchanged.
629 *
630 * Since: 1.4
631 */
632void
633graphene_rect_offset_r (const graphene_rect_t *r,
634 float d_x,
635 float d_y,
636 graphene_rect_t *res)
637{
638 graphene_rect_normalize_r (r, res);
639
640 res->origin.x += d_x;
641 res->origin.y += d_y;
642}
643
644/**
645 * graphene_rect_inset:
646 * @r: a #graphene_rect_t
647 * @d_x: the horizontal inset
648 * @d_y: the vertical inset
649 *
650 * Changes the given rectangle to be smaller, or larger depending on the
651 * given inset parameters.
652 *
653 * To create an inset rectangle, use positive @d_x or @d_y values; to
654 * create a larger, encompassing rectangle, use negative @d_x or @d_y
655 * values.
656 *
657 * The origin of the rectangle is offset by @d_x and @d_y, while the size
658 * is adjusted by `(2 * @d_x, 2 * @d_y)`. If @d_x and @d_y are positive
659 * values, the size of the rectangle is decreased; if @d_x and @d_y are
660 * negative values, the size of the rectangle is increased.
661 *
662 * If the size of the resulting inset rectangle has a negative width or
663 * height then the size will be set to zero.
664 *
665 * Returns: (transfer none): the inset rectangle
666 *
667 * Since: 1.0
668 */
669graphene_rect_t *
670graphene_rect_inset (graphene_rect_t *r,
671 float d_x,
672 float d_y)
673{
674 graphene_rect_inset_r (r, d_x, d_y, res: r);
675
676 return r;
677}
678
679/**
680 * graphene_rect_inset_r:
681 * @r: a #graphene_rect_t
682 * @d_x: the horizontal inset
683 * @d_y: the vertical inset
684 * @res: (out caller-allocates): return location for the inset rectangle
685 *
686 * Changes the given rectangle to be smaller, or larger depending on the
687 * given inset parameters.
688 *
689 * To create an inset rectangle, use positive @d_x or @d_y values; to
690 * create a larger, encompassing rectangle, use negative @d_x or @d_y
691 * values.
692 *
693 * The origin of the rectangle is offset by @d_x and @d_y, while the size
694 * is adjusted by `(2 * @d_x, 2 * @d_y)`. If @d_x and @d_y are positive
695 * values, the size of the rectangle is decreased; if @d_x and @d_y are
696 * negative values, the size of the rectangle is increased.
697 *
698 * If the size of the resulting inset rectangle has a negative width or
699 * height then the size will be set to zero.
700 *
701 * Since: 1.4
702 */
703void
704graphene_rect_inset_r (const graphene_rect_t *r,
705 float d_x,
706 float d_y,
707 graphene_rect_t *res)
708{
709 graphene_rect_normalize_r (r, res);
710
711 res->origin.x += d_x;
712 res->origin.y += d_y;
713
714 if (d_x >= 0.f)
715 res->size.width -= (d_x * 2.f);
716 else
717 res->size.width += (d_x * -2.f);
718
719 if (d_y >= 0.f)
720 res->size.height -= (d_y * 2.f);
721 else
722 res->size.height += (d_y * -2.f);
723
724 if (res->size.width < 0.f)
725 res->size.width = 0.f;
726
727 if (res->size.height < 0.f)
728 res->size.height = 0.f;
729}
730
731/**
732 * graphene_rect_round_to_pixel:
733 * @r: a #graphene_rect_t
734 *
735 * Rounds the origin and the size of the given rectangle to
736 * their nearest integer values; the rounding is guaranteed
737 * to be large enough to contain the original rectangle.
738 *
739 * Returns: (transfer none): the pixel-aligned rectangle.
740 *
741 * Since: 1.0
742 *
743 * Deprecated: 1.4: Use graphene_rect_round() instead
744 */
745graphene_rect_t *
746graphene_rect_round_to_pixel (graphene_rect_t *r)
747{
748 graphene_rect_round (r, res: r);
749
750 return r;
751}
752
753/**
754 * graphene_rect_round:
755 * @r: a #graphene_rect_t
756 * @res: (out caller-allocates): return location for the
757 * rounded rectangle
758 *
759 * Rounds the origin and size of the given rectangle to
760 * their nearest integer values; the rounding is guaranteed
761 * to be large enough to have an area bigger or equal to the
762 * original rectangle, but might not fully contain its extents.
763 * Use graphene_rect_round_extents() in case you need to round
764 * to a rectangle that covers fully the original one.
765 *
766 * This function is the equivalent of calling `floor` on
767 * the coordinates of the origin, and `ceil` on the size.
768 *
769 * Since: 1.4
770 *
771 * Deprecated: 1.10: Use graphene_rect_round_extents() instead
772 */
773void
774graphene_rect_round (const graphene_rect_t *r,
775 graphene_rect_t *res)
776{
777 graphene_rect_normalize_r (r, res);
778
779 res->origin.x = floorf (x: res->origin.x);
780 res->origin.y = floorf (x: res->origin.y);
781
782 res->size.width = ceilf (x: res->size.width);
783 res->size.height = ceilf (x: res->size.height);
784}
785
786/**
787 * graphene_rect_round_extents:
788 * @r: a #graphene_rect_t
789 * @res: (out caller-allocates): return location for the
790 * rectangle with rounded extents
791 *
792 * Rounds the origin of the given rectangle to its nearest
793 * integer value and and recompute the size so that the
794 * rectangle is large enough to contain all the conrners
795 * of the original rectangle.
796 *
797 * This function is the equivalent of calling `floor` on
798 * the coordinates of the origin, and recomputing the size
799 * calling `ceil` on the bottom-right coordinates.
800 *
801 * If you want to be sure that the rounded rectangle
802 * completely covers the area that was covered by the
803 * original rectangle — i.e. you want to cover the area
804 * including all its corners — this function will make sure
805 * that the size is recomputed taking into account the ceiling
806 * of the coordinates of the bottom-right corner.
807 * If the difference between the original coordinates and the
808 * coordinates of the rounded rectangle is greater than the
809 * difference between the original size and and the rounded
810 * size, then the move of the origin would not be compensated
811 * by a move in the anti-origin, leaving the corners of the
812 * original rectangle outside the rounded one.
813 *
814 * Since: 1.10
815 */
816void
817graphene_rect_round_extents (const graphene_rect_t *r,
818 graphene_rect_t *res)
819{
820 float x2, y2;
821
822 graphene_rect_normalize_r (r, res);
823
824 x2 = res->origin.x + res->size.width;
825 y2 = res->origin.y + res->size.height;
826
827 res->origin.x = floorf (x: res->origin.x);
828 res->origin.y = floorf (x: res->origin.y);
829
830 res->size.width = ceilf (x: x2) - res->origin.x;
831 res->size.height = ceilf (x: y2) - res->origin.y;
832}
833
834/**
835 * graphene_rect_expand:
836 * @r: a #graphene_rect_t
837 * @p: a #graphene_point_t
838 * @res: (out caller-allocates): return location for the expanded rectangle
839 *
840 * Expands a #graphene_rect_t to contain the given #graphene_point_t.
841 *
842 * Since: 1.4
843 */
844void
845graphene_rect_expand (const graphene_rect_t *r,
846 const graphene_point_t *p,
847 graphene_rect_t *res)
848{
849 graphene_rect_t tmp;
850
851 graphene_rect_init (r: &tmp, x: p->x, y: p->y, width: 0.f, height: 0.f);
852 graphene_rect_union (a: r, b: &tmp, res);
853
854 graphene_rect_normalize_in_place (r: res);
855}
856
857/**
858 * graphene_rect_interpolate:
859 * @a: a #graphene_rect_t
860 * @b: a #graphene_rect_t
861 * @factor: the linear interpolation factor
862 * @res: (out caller-allocates): return location for the
863 * interpolated rectangle
864 *
865 * Linearly interpolates the origin and size of the two given
866 * rectangles.
867 *
868 * Since: 1.0
869 */
870void
871graphene_rect_interpolate (const graphene_rect_t *a,
872 const graphene_rect_t *b,
873 double factor,
874 graphene_rect_t *res)
875{
876 graphene_rect_t ra, rb;
877
878 ra = *a;
879 graphene_rect_normalize_in_place (r: &ra);
880
881 rb = *b;
882 graphene_rect_normalize_in_place (r: &rb);
883
884 res->origin.x = graphene_lerp (a: ra.origin.x, b: rb.origin.x, factor);
885 res->origin.y = graphene_lerp (a: ra.origin.y, b: rb.origin.y, factor);
886 res->size.width = graphene_lerp (a: ra.size.width, b: rb.size.width, factor);
887 res->size.height = graphene_lerp (a: ra.size.height, b: rb.size.height, factor);
888}
889
890static const graphene_rect_t _graphene_rect_zero;
891
892/**
893 * graphene_rect_zero:
894 *
895 * Returns a degenerate rectangle with origin fixed at (0, 0) and
896 * a size of 0, 0.
897 *
898 * Returns: (transfer none): a fixed rectangle
899 *
900 * Since: 1.4
901 */
902const graphene_rect_t *
903graphene_rect_zero (void)
904{
905 return &_graphene_rect_zero;
906}
907
908/**
909 * graphene_rect_scale:
910 * @r: a #graphene_rect_t
911 * @s_h: horizontal scale factor
912 * @s_v: vertical scale factor
913 * @res: (out caller-allocates): return location for the
914 * scaled rectangle
915 *
916 * Scales the size and origin of a rectangle horizontaly by @s_h,
917 * and vertically by @s_v. The result @res is normalized.
918 *
919 * Since: 1.10
920 */
921void
922graphene_rect_scale (const graphene_rect_t *r,
923 float s_h,
924 float s_v,
925 graphene_rect_t *res)
926{
927 graphene_rect_normalize_r (r, res);
928
929 res->origin.x *= s_h;
930 res->origin.y *= s_v;
931 res->size.width *= s_h;
932 res->size.height *= s_v;
933
934 graphene_rect_normalize_r (r: res, res);
935}
936

source code of gtk/subprojects/graphene/src/graphene-rect.c