2009-11-21 03:19:56 +00:00
|
|
|
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
2010-11-10 22:00:45 +00:00
|
|
|
/*
|
|
|
|
* st-shadow.c: Boxed type holding for -st-shadow attributes
|
|
|
|
*
|
|
|
|
* Copyright 2009, 2010 Florian Müllner
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU Lesser General Public License as
|
|
|
|
* published by the Free Software Foundation, either version 2.1 of
|
|
|
|
* the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope it will be useful, but WITHOUT ANY
|
|
|
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
|
|
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
|
|
|
|
* more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2009-11-21 03:19:56 +00:00
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#include "st-shadow.h"
|
2012-08-21 19:13:33 +00:00
|
|
|
#include "st-private.h"
|
|
|
|
|
|
|
|
G_DEFINE_BOXED_TYPE (StShadow, st_shadow, st_shadow_ref, st_shadow_unref)
|
|
|
|
G_DEFINE_BOXED_TYPE (StShadowHelper, st_shadow_helper, st_shadow_helper_copy, st_shadow_helper_free)
|
2009-11-21 03:19:56 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* SECTION: st-shadow
|
|
|
|
* @short_description: Boxed type for -st-shadow attributes
|
|
|
|
*
|
|
|
|
* #StShadow is a boxed type for storing attributes of the -st-shadow
|
|
|
|
* property, modelled liberally after the CSS3 box-shadow property.
|
|
|
|
* See http://www.css3.info/preview/box-shadow/
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* st_shadow_new:
|
|
|
|
* @color: shadow's color
|
|
|
|
* @xoffset: horizontal offset
|
|
|
|
* @yoffset: vertical offset
|
|
|
|
* @blur: blur radius
|
2010-03-19 10:34:32 +00:00
|
|
|
* @spread: spread radius
|
2011-02-14 01:07:14 +00:00
|
|
|
* @inset: whether the shadow should be inset
|
2009-11-21 03:19:56 +00:00
|
|
|
*
|
|
|
|
* Creates a new #StShadow
|
|
|
|
*
|
|
|
|
* Returns: the newly allocated shadow. Use st_shadow_free() when done
|
|
|
|
*/
|
|
|
|
StShadow *
|
|
|
|
st_shadow_new (ClutterColor *color,
|
|
|
|
gdouble xoffset,
|
|
|
|
gdouble yoffset,
|
2010-03-19 10:34:32 +00:00
|
|
|
gdouble blur,
|
2011-02-14 01:07:14 +00:00
|
|
|
gdouble spread,
|
|
|
|
gboolean inset)
|
2009-11-21 03:19:56 +00:00
|
|
|
{
|
|
|
|
StShadow *shadow;
|
|
|
|
|
|
|
|
shadow = g_slice_new (StShadow);
|
|
|
|
|
2010-09-01 09:16:31 +00:00
|
|
|
shadow->color = *color;
|
|
|
|
shadow->xoffset = xoffset;
|
|
|
|
shadow->yoffset = yoffset;
|
|
|
|
shadow->blur = blur;
|
|
|
|
shadow->spread = spread;
|
2011-02-14 01:07:14 +00:00
|
|
|
shadow->inset = inset;
|
2010-09-01 09:16:31 +00:00
|
|
|
shadow->ref_count = 1;
|
2009-11-21 03:19:56 +00:00
|
|
|
|
|
|
|
return shadow;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2010-09-01 09:16:31 +00:00
|
|
|
* st_shadow_ref:
|
2009-11-21 03:19:56 +00:00
|
|
|
* @shadow: a #StShadow
|
|
|
|
*
|
2010-09-01 09:16:31 +00:00
|
|
|
* Atomically increments the reference count of @shadow by one.
|
2009-11-21 03:19:56 +00:00
|
|
|
*
|
2010-09-01 09:16:31 +00:00
|
|
|
* Returns: the passed in #StShadow.
|
2009-11-21 03:19:56 +00:00
|
|
|
*/
|
|
|
|
StShadow *
|
2010-09-01 09:16:31 +00:00
|
|
|
st_shadow_ref (StShadow *shadow)
|
2009-11-21 03:19:56 +00:00
|
|
|
{
|
|
|
|
g_return_val_if_fail (shadow != NULL, NULL);
|
2010-09-01 09:16:31 +00:00
|
|
|
g_return_val_if_fail (shadow->ref_count > 0, shadow);
|
2009-11-21 03:19:56 +00:00
|
|
|
|
2011-06-02 21:05:16 +00:00
|
|
|
g_atomic_int_inc (&shadow->ref_count);
|
2010-09-01 09:16:31 +00:00
|
|
|
return shadow;
|
2009-11-21 03:19:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2010-09-01 09:16:31 +00:00
|
|
|
* st_shadow_unref:
|
2009-11-21 03:19:56 +00:00
|
|
|
* @shadow: a #StShadow
|
|
|
|
*
|
2010-09-01 09:16:31 +00:00
|
|
|
* Atomically decrements the reference count of @shadow by one.
|
|
|
|
* If the reference count drops to 0, all memory allocated by the
|
|
|
|
* #StShadow is released.
|
2009-11-21 03:19:56 +00:00
|
|
|
*/
|
|
|
|
void
|
2010-09-01 09:16:31 +00:00
|
|
|
st_shadow_unref (StShadow *shadow)
|
2009-11-21 03:19:56 +00:00
|
|
|
{
|
|
|
|
g_return_if_fail (shadow != NULL);
|
2010-09-01 09:16:31 +00:00
|
|
|
g_return_if_fail (shadow->ref_count > 0);
|
2009-11-21 03:19:56 +00:00
|
|
|
|
2011-06-02 21:05:16 +00:00
|
|
|
if (g_atomic_int_dec_and_test (&shadow->ref_count))
|
2010-09-01 09:16:31 +00:00
|
|
|
g_slice_free (StShadow, shadow);
|
2009-11-21 03:19:56 +00:00
|
|
|
}
|
|
|
|
|
2010-08-26 18:10:46 +00:00
|
|
|
/**
|
|
|
|
* st_shadow_equal:
|
|
|
|
* @shadow: a #StShadow
|
|
|
|
* @other: a different #StShadow
|
|
|
|
*
|
|
|
|
* Check if two shadow objects are identical. Note that two shadows may
|
|
|
|
* compare non-identically if they differ only by floating point rounding
|
|
|
|
* errors.
|
|
|
|
*
|
|
|
|
* Return value: %TRUE if the two shadows are identical
|
|
|
|
*/
|
|
|
|
gboolean
|
|
|
|
st_shadow_equal (StShadow *shadow,
|
|
|
|
StShadow *other)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (shadow != NULL, FALSE);
|
|
|
|
g_return_val_if_fail (other != NULL, FALSE);
|
|
|
|
|
|
|
|
/* We use strict equality to compare double quantities; this means
|
|
|
|
* that, for example, a shadow offset of 0.25in does not necessarily
|
|
|
|
* compare equal to a shadow offset of 18pt in this test. Assume
|
|
|
|
* that a few false negatives are mostly harmless.
|
|
|
|
*/
|
|
|
|
|
|
|
|
return (clutter_color_equal (&shadow->color, &other->color) &&
|
|
|
|
shadow->xoffset == other->xoffset &&
|
|
|
|
shadow->yoffset == other->yoffset &&
|
|
|
|
shadow->blur == other->blur &&
|
2011-02-14 01:07:14 +00:00
|
|
|
shadow->spread == other->spread &&
|
|
|
|
shadow->inset == other->inset);
|
2010-08-26 18:10:46 +00:00
|
|
|
}
|
|
|
|
|
2010-06-04 13:21:59 +00:00
|
|
|
/**
|
|
|
|
* st_shadow_get_box:
|
|
|
|
* @shadow: a #StShadow
|
|
|
|
* @actor_box: the box allocated to a #ClutterAlctor
|
|
|
|
* @shadow_box: computed box occupied by @shadow
|
|
|
|
*
|
|
|
|
* Gets the box used to paint @shadow, which will be partly
|
|
|
|
* outside of @actor_box
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
st_shadow_get_box (StShadow *shadow,
|
|
|
|
const ClutterActorBox *actor_box,
|
|
|
|
ClutterActorBox *shadow_box)
|
|
|
|
{
|
|
|
|
g_return_if_fail (shadow != NULL);
|
|
|
|
g_return_if_fail (actor_box != NULL);
|
|
|
|
g_return_if_fail (shadow_box != NULL);
|
|
|
|
|
2011-02-14 01:07:14 +00:00
|
|
|
/* Inset shadows are drawn below the border, so returning
|
|
|
|
* the original box is not actually correct; still, it's
|
|
|
|
* good enough for the purpose of determing additional space
|
|
|
|
* required outside the actor box.
|
|
|
|
*/
|
|
|
|
if (shadow->inset)
|
|
|
|
{
|
|
|
|
*shadow_box = *actor_box;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-06-04 13:21:59 +00:00
|
|
|
shadow_box->x1 = actor_box->x1 + shadow->xoffset
|
|
|
|
- shadow->blur - shadow->spread;
|
|
|
|
shadow_box->x2 = actor_box->x2 + shadow->xoffset
|
|
|
|
+ shadow->blur + shadow->spread;
|
|
|
|
shadow_box->y1 = actor_box->y1 + shadow->yoffset
|
|
|
|
- shadow->blur - shadow->spread;
|
|
|
|
shadow_box->y2 = actor_box->y2 + shadow->yoffset
|
|
|
|
+ shadow->blur + shadow->spread;
|
|
|
|
}
|
|
|
|
|
2012-08-21 19:13:33 +00:00
|
|
|
/**
|
|
|
|
* SECTION:st-shadow-helper:
|
|
|
|
*
|
|
|
|
* An helper for implementing a drop shadow on a actor.
|
|
|
|
* The actor is expected to recreate the helper whenever its contents
|
|
|
|
* or size change. Then, it would call st_shadow_helper_paint() inside
|
|
|
|
* its paint() virtual function.
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct _StShadowHelper {
|
|
|
|
StShadow *shadow;
|
|
|
|
CoglMaterial *material;
|
|
|
|
|
|
|
|
gfloat width;
|
|
|
|
gfloat height;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* st_shadow_helper_new:
|
|
|
|
* @shadow: a #StShadow representing the shadow properties
|
|
|
|
*
|
|
|
|
* Builds a #StShadowHelper that will build a drop shadow
|
|
|
|
* using @source as the mask.
|
|
|
|
*
|
|
|
|
* Returns: (transfer full): a new #StShadowHelper
|
|
|
|
*/
|
|
|
|
StShadowHelper *
|
|
|
|
st_shadow_helper_new (StShadow *shadow)
|
|
|
|
{
|
|
|
|
StShadowHelper *helper;
|
|
|
|
|
|
|
|
helper = g_slice_new0 (StShadowHelper);
|
|
|
|
helper->shadow = st_shadow_ref (shadow);
|
|
|
|
|
|
|
|
return helper;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
st_shadow_helper_update (StShadowHelper *helper,
|
|
|
|
ClutterActor *source)
|
|
|
|
{
|
|
|
|
gfloat width, height;
|
|
|
|
|
|
|
|
clutter_actor_get_size (source, &width, &height);
|
|
|
|
|
|
|
|
if (helper->material == NULL ||
|
|
|
|
helper->width != width ||
|
|
|
|
helper->height != height)
|
|
|
|
{
|
|
|
|
if (helper->material)
|
|
|
|
cogl_object_unref (helper->material);
|
|
|
|
|
|
|
|
helper->material = _st_create_shadow_material_from_actor (helper->shadow, source);
|
|
|
|
helper->width = width;
|
|
|
|
helper->height = height;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* st_shadow_helper_copy:
|
|
|
|
* @helper: the #StShadowHelper to copy
|
|
|
|
*
|
|
|
|
* Returns: (transfer full): a copy of @helper
|
|
|
|
*/
|
|
|
|
StShadowHelper *
|
|
|
|
st_shadow_helper_copy (StShadowHelper *helper)
|
2009-11-21 03:19:56 +00:00
|
|
|
{
|
2012-08-21 19:13:33 +00:00
|
|
|
StShadowHelper *copy;
|
|
|
|
|
|
|
|
copy = g_slice_new (StShadowHelper);
|
|
|
|
*copy = *helper;
|
|
|
|
if (copy->material)
|
|
|
|
cogl_object_ref (copy->material);
|
|
|
|
st_shadow_ref (copy->shadow);
|
|
|
|
|
|
|
|
return copy;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* st_shadow_helper_free:
|
|
|
|
* @helper: a #StShadowHelper
|
|
|
|
*
|
|
|
|
* Free resources associated with @helper.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
st_shadow_helper_free (StShadowHelper *helper)
|
|
|
|
{
|
|
|
|
if (helper->material)
|
|
|
|
cogl_object_unref (helper->material);
|
|
|
|
st_shadow_unref (helper->shadow);
|
|
|
|
|
|
|
|
g_slice_free (StShadowHelper, helper);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* st_shadow_helper_paint:
|
|
|
|
* @helper: a #StShadowHelper
|
|
|
|
* @actor_box: the bounding box of the shadow
|
|
|
|
* @paint_opacity: the opacity at which the shadow is painted
|
|
|
|
*
|
|
|
|
* Paints the shadow associated with @helper This must only
|
|
|
|
* be called from the implementation of ClutterActor::paint().
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
st_shadow_helper_paint (StShadowHelper *helper,
|
|
|
|
ClutterActorBox *actor_box,
|
|
|
|
guint8 paint_opacity)
|
|
|
|
{
|
|
|
|
ClutterActorBox allocation;
|
|
|
|
float width, height;
|
|
|
|
|
|
|
|
clutter_actor_box_get_size (actor_box, &width, &height);
|
2009-11-21 03:19:56 +00:00
|
|
|
|
2012-08-21 19:13:33 +00:00
|
|
|
allocation.x1 = (width - helper->width) / 2;
|
|
|
|
allocation.y1 = (height - helper->height) / 2;
|
|
|
|
allocation.x2 = allocation.x1 + helper->width;
|
|
|
|
allocation.y2 = allocation.y1 + helper->height;
|
2009-11-21 03:19:56 +00:00
|
|
|
|
2012-08-21 19:13:33 +00:00
|
|
|
_st_paint_shadow_with_opacity (helper->shadow,
|
|
|
|
helper->material,
|
|
|
|
&allocation,
|
|
|
|
paint_opacity);
|
2009-11-21 03:19:56 +00:00
|
|
|
}
|