summaryrefslogtreecommitdiffstats
path: root/src/st/st-shadow.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/st/st-shadow.c')
-rw-r--r--src/st/st-shadow.c304
1 files changed, 304 insertions, 0 deletions
diff --git a/src/st/st-shadow.c b/src/st/st-shadow.c
new file mode 100644
index 0000000..070e7bf
--- /dev/null
+++ b/src/st/st-shadow.c
@@ -0,0 +1,304 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * 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/>.
+ */
+
+#include "config.h"
+
+#include "st-shadow.h"
+#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)
+
+/**
+ * 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
+ * @spread: spread radius
+ * @inset: whether the shadow should be inset
+ *
+ * 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,
+ gdouble blur,
+ gdouble spread,
+ gboolean inset)
+{
+ StShadow *shadow;
+
+ shadow = g_slice_new (StShadow);
+
+ shadow->color = *color;
+ shadow->xoffset = xoffset;
+ shadow->yoffset = yoffset;
+ shadow->blur = blur;
+ shadow->spread = spread;
+ shadow->inset = inset;
+ shadow->ref_count = 1;
+
+ return shadow;
+}
+
+/**
+ * st_shadow_ref:
+ * @shadow: a #StShadow
+ *
+ * Atomically increments the reference count of @shadow by one.
+ *
+ * Returns: the passed in #StShadow.
+ */
+StShadow *
+st_shadow_ref (StShadow *shadow)
+{
+ g_return_val_if_fail (shadow != NULL, NULL);
+ g_return_val_if_fail (shadow->ref_count > 0, shadow);
+
+ g_atomic_int_inc (&shadow->ref_count);
+ return shadow;
+}
+
+/**
+ * st_shadow_unref:
+ * @shadow: a #StShadow
+ *
+ * Atomically decrements the reference count of @shadow by one.
+ * If the reference count drops to 0, all memory allocated by the
+ * #StShadow is released.
+ */
+void
+st_shadow_unref (StShadow *shadow)
+{
+ g_return_if_fail (shadow != NULL);
+ g_return_if_fail (shadow->ref_count > 0);
+
+ if (g_atomic_int_dec_and_test (&shadow->ref_count))
+ g_slice_free (StShadow, shadow);
+}
+
+/**
+ * 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.
+ *
+ * Returns: %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 &&
+ shadow->spread == other->spread &&
+ shadow->inset == other->inset);
+}
+
+/**
+ * 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);
+
+ /* 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 determining additional space
+ * required outside the actor box.
+ */
+ if (shadow->inset)
+ {
+ *shadow_box = *actor_box;
+ return;
+ }
+
+ 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;
+}
+
+/**
+ * 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;
+ CoglPipeline *pipeline;
+
+ 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;
+}
+
+/**
+ * st_shadow_helper_update:
+ * @helper: a #StShadowHelper
+ * @source: a #ClutterActor
+ *
+ * Update @helper from @source.
+ */
+void
+st_shadow_helper_update (StShadowHelper *helper,
+ ClutterActor *source)
+{
+ gfloat width, height;
+
+ clutter_actor_get_size (source, &width, &height);
+
+ if (helper->pipeline == NULL ||
+ helper->width != width ||
+ helper->height != height)
+ {
+ if (helper->pipeline)
+ cogl_object_unref (helper->pipeline);
+
+ helper->pipeline = _st_create_shadow_pipeline_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)
+{
+ StShadowHelper *copy;
+
+ copy = g_slice_new (StShadowHelper);
+ *copy = *helper;
+ if (copy->pipeline)
+ cogl_object_ref (copy->pipeline);
+ 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->pipeline)
+ cogl_object_unref (helper->pipeline);
+ st_shadow_unref (helper->shadow);
+
+ g_slice_free (StShadowHelper, helper);
+}
+
+/**
+ * st_shadow_helper_paint:
+ * @helper: a #StShadowHelper
+ * @framebuffer: a #CoglFramebuffer
+ * @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,
+ CoglFramebuffer *framebuffer,
+ ClutterActorBox *actor_box,
+ guint8 paint_opacity)
+{
+ _st_paint_shadow_with_opacity (helper->shadow,
+ framebuffer,
+ helper->pipeline,
+ actor_box,
+ paint_opacity);
+}