mirror of
https://github.com/brl/mutter.git
synced 2024-11-28 11:00:54 -05:00
8b977e9046
It has been inofficially deprecated for years, is known to cause issues with valgrind and potentially hides memory corruption. Lets stop using it. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1512>
648 lines
16 KiB
C
648 lines
16 KiB
C
#include "clutter-build-config.h"
|
|
|
|
#include <math.h>
|
|
|
|
#include "clutter-types.h"
|
|
#include "clutter-interval.h"
|
|
#include "clutter-private.h"
|
|
#include "clutter-actor-box-private.h"
|
|
|
|
/**
|
|
* clutter_actor_box_new:
|
|
* @x_1: X coordinate of the top left point
|
|
* @y_1: Y coordinate of the top left point
|
|
* @x_2: X coordinate of the bottom right point
|
|
* @y_2: Y coordinate of the bottom right point
|
|
*
|
|
* Allocates a new #ClutterActorBox using the passed coordinates
|
|
* for the top left and bottom right points.
|
|
*
|
|
* This function is the logical equivalent of:
|
|
*
|
|
* |[
|
|
* clutter_actor_box_init (clutter_actor_box_alloc (),
|
|
* x_1, y_1,
|
|
* x_2, y_2);
|
|
* ]|
|
|
*
|
|
* Return value: (transfer full): the newly allocated #ClutterActorBox.
|
|
* Use clutter_actor_box_free() to free the resources
|
|
*
|
|
* Since: 1.0
|
|
*/
|
|
ClutterActorBox *
|
|
clutter_actor_box_new (gfloat x_1,
|
|
gfloat y_1,
|
|
gfloat x_2,
|
|
gfloat y_2)
|
|
{
|
|
return clutter_actor_box_init (clutter_actor_box_alloc (),
|
|
x_1, y_1,
|
|
x_2, y_2);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_box_alloc:
|
|
*
|
|
* Allocates a new #ClutterActorBox.
|
|
*
|
|
* Return value: (transfer full): the newly allocated #ClutterActorBox.
|
|
* Use clutter_actor_box_free() to free its resources
|
|
*
|
|
* Since: 1.12
|
|
*/
|
|
ClutterActorBox *
|
|
clutter_actor_box_alloc (void)
|
|
{
|
|
return g_new0 (ClutterActorBox, 1);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_box_init:
|
|
* @box: a #ClutterActorBox
|
|
* @x_1: X coordinate of the top left point
|
|
* @y_1: Y coordinate of the top left point
|
|
* @x_2: X coordinate of the bottom right point
|
|
* @y_2: Y coordinate of the bottom right point
|
|
*
|
|
* Initializes @box with the given coordinates.
|
|
*
|
|
* Return value: (transfer none): the initialized #ClutterActorBox
|
|
*
|
|
* Since: 1.10
|
|
*/
|
|
ClutterActorBox *
|
|
clutter_actor_box_init (ClutterActorBox *box,
|
|
gfloat x_1,
|
|
gfloat y_1,
|
|
gfloat x_2,
|
|
gfloat y_2)
|
|
{
|
|
g_return_val_if_fail (box != NULL, NULL);
|
|
|
|
box->x1 = x_1;
|
|
box->y1 = y_1;
|
|
box->x2 = x_2;
|
|
box->y2 = y_2;
|
|
|
|
return box;
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_box_init_rect:
|
|
* @box: a #ClutterActorBox
|
|
* @x: X coordinate of the origin
|
|
* @y: Y coordinate of the origin
|
|
* @width: width of the box
|
|
* @height: height of the box
|
|
*
|
|
* Initializes @box with the given origin and size.
|
|
*
|
|
* Since: 1.10
|
|
*/
|
|
void
|
|
clutter_actor_box_init_rect (ClutterActorBox *box,
|
|
gfloat x,
|
|
gfloat y,
|
|
gfloat width,
|
|
gfloat height)
|
|
{
|
|
g_return_if_fail (box != NULL);
|
|
|
|
box->x1 = x;
|
|
box->y1 = y;
|
|
box->x2 = box->x1 + width;
|
|
box->y2 = box->y1 + height;
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_box_copy:
|
|
* @box: a #ClutterActorBox
|
|
*
|
|
* Copies @box
|
|
*
|
|
* Return value: a newly allocated copy of #ClutterActorBox. Use
|
|
* clutter_actor_box_free() to free the allocated resources
|
|
*
|
|
* Since: 1.0
|
|
*/
|
|
ClutterActorBox *
|
|
clutter_actor_box_copy (const ClutterActorBox *box)
|
|
{
|
|
if (G_LIKELY (box != NULL))
|
|
return g_memdup2 (box, sizeof (ClutterActorBox));
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_box_free:
|
|
* @box: a #ClutterActorBox
|
|
*
|
|
* Frees a #ClutterActorBox allocated using clutter_actor_box_new()
|
|
* or clutter_actor_box_copy()
|
|
*
|
|
* Since: 1.0
|
|
*/
|
|
void
|
|
clutter_actor_box_free (ClutterActorBox *box)
|
|
{
|
|
if (G_LIKELY (box != NULL))
|
|
g_free (box);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_box_equal:
|
|
* @box_a: a #ClutterActorBox
|
|
* @box_b: a #ClutterActorBox
|
|
*
|
|
* Checks @box_a and @box_b for equality
|
|
*
|
|
* Return value: %TRUE if the passed #ClutterActorBox are equal
|
|
*
|
|
* Since: 1.0
|
|
*/
|
|
gboolean
|
|
clutter_actor_box_equal (const ClutterActorBox *box_a,
|
|
const ClutterActorBox *box_b)
|
|
{
|
|
g_return_val_if_fail (box_a != NULL && box_b != NULL, FALSE);
|
|
|
|
if (box_a == box_b)
|
|
return TRUE;
|
|
|
|
return box_a->x1 == box_b->x1 && box_a->y1 == box_b->y1 &&
|
|
box_a->x2 == box_b->x2 && box_a->y2 == box_b->y2;
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_box_get_x:
|
|
* @box: a #ClutterActorBox
|
|
*
|
|
* Retrieves the X coordinate of the origin of @box
|
|
*
|
|
* Return value: the X coordinate of the origin
|
|
*
|
|
* Since: 1.0
|
|
*/
|
|
gfloat
|
|
clutter_actor_box_get_x (const ClutterActorBox *box)
|
|
{
|
|
g_return_val_if_fail (box != NULL, 0.);
|
|
|
|
return box->x1;
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_box_get_y:
|
|
* @box: a #ClutterActorBox
|
|
*
|
|
* Retrieves the Y coordinate of the origin of @box
|
|
*
|
|
* Return value: the Y coordinate of the origin
|
|
*
|
|
* Since: 1.0
|
|
*/
|
|
gfloat
|
|
clutter_actor_box_get_y (const ClutterActorBox *box)
|
|
{
|
|
g_return_val_if_fail (box != NULL, 0.);
|
|
|
|
return box->y1;
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_box_get_width:
|
|
* @box: a #ClutterActorBox
|
|
*
|
|
* Retrieves the width of the @box
|
|
*
|
|
* Return value: the width of the box
|
|
*
|
|
* Since: 1.0
|
|
*/
|
|
gfloat
|
|
clutter_actor_box_get_width (const ClutterActorBox *box)
|
|
{
|
|
g_return_val_if_fail (box != NULL, 0.);
|
|
|
|
return box->x2 - box->x1;
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_box_get_height:
|
|
* @box: a #ClutterActorBox
|
|
*
|
|
* Retrieves the height of the @box
|
|
*
|
|
* Return value: the height of the box
|
|
*
|
|
* Since: 1.0
|
|
*/
|
|
gfloat
|
|
clutter_actor_box_get_height (const ClutterActorBox *box)
|
|
{
|
|
g_return_val_if_fail (box != NULL, 0.);
|
|
|
|
return box->y2 - box->y1;
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_box_get_origin:
|
|
* @box: a #ClutterActorBox
|
|
* @x: (out) (allow-none): return location for the X coordinate, or %NULL
|
|
* @y: (out) (allow-none): return location for the Y coordinate, or %NULL
|
|
*
|
|
* Retrieves the origin of @box
|
|
*
|
|
* Since: 1.0
|
|
*/
|
|
void
|
|
clutter_actor_box_get_origin (const ClutterActorBox *box,
|
|
gfloat *x,
|
|
gfloat *y)
|
|
{
|
|
g_return_if_fail (box != NULL);
|
|
|
|
if (x)
|
|
*x = box->x1;
|
|
|
|
if (y)
|
|
*y = box->y1;
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_box_get_size:
|
|
* @box: a #ClutterActorBox
|
|
* @width: (out) (allow-none): return location for the width, or %NULL
|
|
* @height: (out) (allow-none): return location for the height, or %NULL
|
|
*
|
|
* Retrieves the size of @box
|
|
*
|
|
* Since: 1.0
|
|
*/
|
|
void
|
|
clutter_actor_box_get_size (const ClutterActorBox *box,
|
|
gfloat *width,
|
|
gfloat *height)
|
|
{
|
|
g_return_if_fail (box != NULL);
|
|
|
|
if (width)
|
|
*width = box->x2 - box->x1;
|
|
|
|
if (height)
|
|
*height = box->y2 - box->y1;
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_box_get_area:
|
|
* @box: a #ClutterActorBox
|
|
*
|
|
* Retrieves the area of @box
|
|
*
|
|
* Return value: the area of a #ClutterActorBox, in pixels
|
|
*
|
|
* Since: 1.0
|
|
*/
|
|
gfloat
|
|
clutter_actor_box_get_area (const ClutterActorBox *box)
|
|
{
|
|
g_return_val_if_fail (box != NULL, 0.);
|
|
|
|
return (box->x2 - box->x1) * (box->y2 - box->y1);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_box_contains:
|
|
* @box: a #ClutterActorBox
|
|
* @x: X coordinate of the point
|
|
* @y: Y coordinate of the point
|
|
*
|
|
* Checks whether a point with @x, @y coordinates is contained
|
|
* within @box
|
|
*
|
|
* Return value: %TRUE if the point is contained by the #ClutterActorBox
|
|
*
|
|
* Since: 1.0
|
|
*/
|
|
gboolean
|
|
clutter_actor_box_contains (const ClutterActorBox *box,
|
|
gfloat x,
|
|
gfloat y)
|
|
{
|
|
g_return_val_if_fail (box != NULL, FALSE);
|
|
|
|
return (x > box->x1 && x < box->x2) &&
|
|
(y > box->y1 && y < box->y2);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_box_from_vertices:
|
|
* @box: a #ClutterActorBox
|
|
* @verts: (array fixed-size=4): array of four #graphene_point3d_t
|
|
*
|
|
* Calculates the bounding box represented by the four vertices; for details
|
|
* of the vertex array see clutter_actor_get_abs_allocation_vertices().
|
|
*
|
|
* Since: 1.0
|
|
*/
|
|
void
|
|
clutter_actor_box_from_vertices (ClutterActorBox *box,
|
|
const graphene_point3d_t verts[])
|
|
{
|
|
gfloat x_1, x_2, y_1, y_2;
|
|
|
|
g_return_if_fail (box != NULL);
|
|
g_return_if_fail (verts != NULL);
|
|
|
|
/* 4-way min/max */
|
|
x_1 = verts[0].x;
|
|
y_1 = verts[0].y;
|
|
|
|
if (verts[1].x < x_1)
|
|
x_1 = verts[1].x;
|
|
|
|
if (verts[2].x < x_1)
|
|
x_1 = verts[2].x;
|
|
|
|
if (verts[3].x < x_1)
|
|
x_1 = verts[3].x;
|
|
|
|
if (verts[1].y < y_1)
|
|
y_1 = verts[1].y;
|
|
|
|
if (verts[2].y < y_1)
|
|
y_1 = verts[2].y;
|
|
|
|
if (verts[3].y < y_1)
|
|
y_1 = verts[3].y;
|
|
|
|
x_2 = verts[0].x;
|
|
y_2 = verts[0].y;
|
|
|
|
if (verts[1].x > x_2)
|
|
x_2 = verts[1].x;
|
|
|
|
if (verts[2].x > x_2)
|
|
x_2 = verts[2].x;
|
|
|
|
if (verts[3].x > x_2)
|
|
x_2 = verts[3].x;
|
|
|
|
if (verts[1].y > y_2)
|
|
y_2 = verts[1].y;
|
|
|
|
if (verts[2].y > y_2)
|
|
y_2 = verts[2].y;
|
|
|
|
if (verts[3].y > y_2)
|
|
y_2 = verts[3].y;
|
|
|
|
box->x1 = x_1;
|
|
box->x2 = x_2;
|
|
box->y1 = y_1;
|
|
box->y2 = y_2;
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_box_interpolate:
|
|
* @initial: the initial #ClutterActorBox
|
|
* @final: the final #ClutterActorBox
|
|
* @progress: the interpolation progress
|
|
* @result: (out): return location for the interpolation
|
|
*
|
|
* Interpolates between @initial and @final #ClutterActorBox<!-- -->es
|
|
* using @progress
|
|
*
|
|
* Since: 1.2
|
|
*/
|
|
void
|
|
clutter_actor_box_interpolate (const ClutterActorBox *initial,
|
|
const ClutterActorBox *final,
|
|
gdouble progress,
|
|
ClutterActorBox *result)
|
|
{
|
|
g_return_if_fail (initial != NULL);
|
|
g_return_if_fail (final != NULL);
|
|
g_return_if_fail (result != NULL);
|
|
|
|
result->x1 = initial->x1 + (final->x1 - initial->x1) * progress;
|
|
result->y1 = initial->y1 + (final->y1 - initial->y1) * progress;
|
|
result->x2 = initial->x2 + (final->x2 - initial->x2) * progress;
|
|
result->y2 = initial->y2 + (final->y2 - initial->y2) * progress;
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_box_clamp_to_pixel:
|
|
* @box: (inout): the #ClutterActorBox to clamp
|
|
*
|
|
* Clamps the components of @box to the nearest integer
|
|
*
|
|
* Since: 1.2
|
|
*/
|
|
void
|
|
clutter_actor_box_clamp_to_pixel (ClutterActorBox *box)
|
|
{
|
|
g_return_if_fail (box != NULL);
|
|
|
|
box->x1 = floorf (box->x1);
|
|
box->y1 = floorf (box->y1);
|
|
box->x2 = ceilf (box->x2);
|
|
box->y2 = ceilf (box->y2);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_box_union:
|
|
* @a: (in): the first #ClutterActorBox
|
|
* @b: (in): the second #ClutterActorBox
|
|
* @result: (out): the #ClutterActorBox representing a union
|
|
* of @a and @b
|
|
*
|
|
* Unions the two boxes @a and @b and stores the result in @result.
|
|
*
|
|
* Since: 1.4
|
|
*/
|
|
void
|
|
clutter_actor_box_union (const ClutterActorBox *a,
|
|
const ClutterActorBox *b,
|
|
ClutterActorBox *result)
|
|
{
|
|
g_return_if_fail (a != NULL);
|
|
g_return_if_fail (b != NULL);
|
|
g_return_if_fail (result != NULL);
|
|
|
|
result->x1 = MIN (a->x1, b->x1);
|
|
result->y1 = MIN (a->y1, b->y1);
|
|
|
|
result->x2 = MAX (a->x2, b->x2);
|
|
result->y2 = MAX (a->y2, b->y2);
|
|
}
|
|
|
|
static gboolean
|
|
clutter_actor_box_progress (const GValue *a,
|
|
const GValue *b,
|
|
gdouble factor,
|
|
GValue *retval)
|
|
{
|
|
ClutterActorBox res = { 0, };
|
|
|
|
clutter_actor_box_interpolate (g_value_get_boxed (a),
|
|
g_value_get_boxed (b),
|
|
factor,
|
|
&res);
|
|
|
|
g_value_set_boxed (retval, &res);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_box_set_origin:
|
|
* @box: a #ClutterActorBox
|
|
* @x: the X coordinate of the new origin
|
|
* @y: the Y coordinate of the new origin
|
|
*
|
|
* Changes the origin of @box, maintaining the size of the #ClutterActorBox.
|
|
*
|
|
* Since: 1.6
|
|
*/
|
|
void
|
|
clutter_actor_box_set_origin (ClutterActorBox *box,
|
|
gfloat x,
|
|
gfloat y)
|
|
{
|
|
gfloat width, height;
|
|
|
|
g_return_if_fail (box != NULL);
|
|
|
|
width = box->x2 - box->x1;
|
|
height = box->y2 - box->y1;
|
|
|
|
clutter_actor_box_init_rect (box, x, y, width, height);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_box_set_size:
|
|
* @box: a #ClutterActorBox
|
|
* @width: the new width
|
|
* @height: the new height
|
|
*
|
|
* Sets the size of @box, maintaining the origin of the #ClutterActorBox.
|
|
*
|
|
* Since: 1.6
|
|
*/
|
|
void
|
|
clutter_actor_box_set_size (ClutterActorBox *box,
|
|
gfloat width,
|
|
gfloat height)
|
|
{
|
|
g_return_if_fail (box != NULL);
|
|
|
|
box->x2 = box->x1 + width;
|
|
box->y2 = box->y1 + height;
|
|
}
|
|
|
|
void
|
|
_clutter_actor_box_enlarge_for_effects (ClutterActorBox *box)
|
|
{
|
|
float width, height;
|
|
|
|
/* The aim here is that for a given rectangle defined with floating point
|
|
* coordinates we want to determine a stable quantized size in pixels
|
|
* that doesn't vary due to the original box's sub-pixel position.
|
|
*
|
|
* The reason this is important is because effects will use this
|
|
* API to determine the size of offscreen framebuffers and so for
|
|
* a fixed-size object that may be animated across the screen we
|
|
* want to make sure that the stage paint-box has an equally stable
|
|
* size so that effects aren't made to continuously re-allocate
|
|
* a corresponding fbo.
|
|
*
|
|
* The other thing we consider is that the calculation of this box is
|
|
* subject to floating point precision issues that might be slightly
|
|
* different to the precision issues involved with actually painting the
|
|
* actor, which might result in painting slightly leaking outside the
|
|
* user's calculated paint-volume. For this we simply aim to pad out the
|
|
* paint-volume by at least half a pixel all the way around.
|
|
*/
|
|
width = box->x2 - box->x1;
|
|
height = box->y2 - box->y1;
|
|
width = CLUTTER_NEARBYINT (width);
|
|
height = CLUTTER_NEARBYINT (height);
|
|
/* XXX: NB the width/height may now be up to 0.5px too small so we
|
|
* must also pad by 0.25px all around to account for this. In total we
|
|
* must padd by at least 0.75px around all sides. */
|
|
|
|
/* XXX: The furthest that we can overshoot the bottom right corner by
|
|
* here is 1.75px in total if you consider that the 0.75 padding could
|
|
* just cross an integer boundary and so ceil will effectively add 1.
|
|
*/
|
|
box->x2 = ceilf (box->x2 + 0.75);
|
|
box->y2 = ceilf (box->y2 + 0.75);
|
|
|
|
/* Now we redefine the top-left relative to the bottom right based on the
|
|
* rounded width/height determined above + a constant so that the overall
|
|
* size of the box will be stable and not dependent on the box's
|
|
* position.
|
|
*
|
|
* Adding 3px to the width/height will ensure we cover the maximum of
|
|
* 1.75px padding on the bottom/right and still ensure we have > 0.75px
|
|
* padding on the top/left.
|
|
*/
|
|
box->x1 = box->x2 - width - 3;
|
|
box->y1 = box->y2 - height - 3;
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_box_scale:
|
|
* @box: a #ClutterActorBox
|
|
* @scale: scale factor for resizing this box
|
|
*
|
|
* Rescale the @box by provided @scale factor.
|
|
*
|
|
* Since: 1.6
|
|
*/
|
|
void
|
|
clutter_actor_box_scale (ClutterActorBox *box,
|
|
gfloat scale)
|
|
{
|
|
g_return_if_fail (box != NULL);
|
|
|
|
box->x1 *= scale;
|
|
box->x2 *= scale;
|
|
box->y1 *= scale;
|
|
box->y2 *= scale;
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_box_is_initialized:
|
|
* @box: a #ClutterActorBox
|
|
*
|
|
* Checks if @box has been initialized, a #ClutterActorBox is uninitialized
|
|
* if it has a size of -1 at an origin of 0, 0.
|
|
*
|
|
* Returns: %TRUE if the box is uninitialized, %FALSE if it isn't
|
|
*/
|
|
gboolean
|
|
clutter_actor_box_is_initialized (ClutterActorBox *box)
|
|
{
|
|
gboolean x1_uninitialized, x2_uninitialized;
|
|
gboolean y1_uninitialized, y2_uninitialized;
|
|
|
|
g_return_val_if_fail (box != NULL, TRUE);
|
|
|
|
x1_uninitialized = isinf (box->x1);
|
|
x2_uninitialized = isinf (box->x2) && signbit (box->x2);
|
|
y1_uninitialized = isinf (box->y1);
|
|
y2_uninitialized = isinf (box->y2) && signbit (box->y2);
|
|
|
|
return !x1_uninitialized || !x2_uninitialized ||
|
|
!y1_uninitialized || !y2_uninitialized;
|
|
}
|
|
|
|
G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterActorBox, clutter_actor_box,
|
|
clutter_actor_box_copy,
|
|
clutter_actor_box_free,
|
|
CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_actor_box_progress));
|