[gnome-shell/shell-toolkit: 24/32] Match CSS for background extents
- From: Owen Taylor <otaylor src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [gnome-shell/shell-toolkit: 24/32] Match CSS for background extents
- Date: Wed, 30 Sep 2009 00:03:06 +0000 (UTC)
commit 304b48a15df987cdd7cf2f9c76316a456c096ebe
Author: Owen W. Taylor <otaylor fishsoup net>
Date: Sun Sep 20 18:03:18 2009 -0400
Match CSS for background extents
The CSS specification says that the background extends to the
edge of the border (settable in CSS3 with border-clip), make
BigRectangle match this by computing an "effective border color"
as 'border OVER background'.
(If we don't want this behavior - e.g., to be able to use the
transparent borders as margins, then alternatively transparent
border handling would have to be fixed in st-widget.c, since
prior to this transparent and translucent borders were handled
differently.)
https://bugzilla.gnome.org/show_bug.cgi?id=595993
src/big/rectangle.c | 129 +++++++++++++++++++++++++++++++++---------
tests/interactive/borders.js | 12 +++-
2 files changed, 112 insertions(+), 29 deletions(-)
---
diff --git a/src/big/rectangle.c b/src/big/rectangle.c
index 8ca104d..fa594e6 100644
--- a/src/big/rectangle.c
+++ b/src/big/rectangle.c
@@ -268,6 +268,52 @@ corner_get(guint radius,
return corner;
}
+/* To match the CSS specification, we want the border to look like it was
+ * drawn over the background. But actually drawing the border over the
+ * background will produce slightly bad antialiasing at the edges, so
+ * compute the effective border color instead.
+ */
+#define NORM(x) (t = (x) + 127, (t + (t >> 8)) >> 8)
+#define MULT(c,a) NORM(c*a)
+
+static void
+premultiply (ClutterColor *color)
+{
+ guint t;
+ color->red = MULT (color->red, color->alpha);
+ color->green = MULT (color->green, color->alpha);
+ color->blue = MULT (color->blue, color->alpha);
+}
+
+static void
+unpremultiply (ClutterColor *color)
+{
+ if (color->alpha != 0) {
+ color->red = (color->red * 255 + 127) / color->alpha;
+ color->green = (color->green * 255 + 127) / color->alpha;
+ color->blue = (color->blue * 255 + 127) / color->alpha;
+ }
+}
+
+static void
+over (const ClutterColor *source,
+ const ClutterColor *destination,
+ ClutterColor *result)
+{
+ guint t;
+ ClutterColor src = *source;
+ ClutterColor dst = *destination;
+ premultiply (&src);
+ premultiply (&dst);
+
+ result->alpha = src.alpha + NORM ((255 - src.alpha) * dst.alpha);
+ result->red = src.red + NORM ((255 - src.alpha) * dst.red);
+ result->green = src.green + NORM ((255 - src.alpha) * dst.green);
+ result->blue = src.blue + NORM ((255 - src.alpha) * dst.blue);
+
+ unpremultiply (result);
+}
+
static void
big_rectangle_update_corners(BigRectangle *rectangle)
{
@@ -278,6 +324,7 @@ big_rectangle_update_corners(BigRectangle *rectangle)
if (rectangle->radius != 0) {
ClutterColor *color;
ClutterColor *border_color;
+ ClutterColor effective_border;
guint border_width;
g_object_get(rectangle,
@@ -286,10 +333,12 @@ big_rectangle_update_corners(BigRectangle *rectangle)
"color", &color,
NULL);
+ over (border_color, color, &effective_border);
+
corner = corner_get(rectangle->radius,
color,
border_width,
- border_color);
+ &effective_border);
clutter_color_free(border_color);
clutter_color_free(color);
@@ -329,12 +378,10 @@ big_rectangle_paint(ClutterActor *actor)
rectangle = BIG_RECTANGLE(actor);
- if (rectangle->radius == 0) {
- /* In that case we are no different than our parent class,
- * so don't bother */
- CLUTTER_ACTOR_CLASS(big_rectangle_parent_class)->paint(actor);
- return;
- }
+ /* We can't chain up, even when we the radius is 0, because of the different
+ * interpretation of the border/background relationship here than for
+ * ClutterRectangle.
+ */
if (rectangle->corners_dirty)
big_rectangle_update_corners(rectangle);
@@ -345,6 +392,9 @@ big_rectangle_paint(ClutterActor *actor)
"color", &color,
NULL);
+ if (border_color->alpha == 0 && color->alpha == 0)
+ goto out;
+
actor_opacity = clutter_actor_get_paint_opacity (actor);
clutter_actor_get_allocation_box(actor, &box);
@@ -358,6 +408,11 @@ big_rectangle_paint(ClutterActor *actor)
radius = rectangle->radius;
+ /* Optimization; if the border is transparent, it just looks like part of
+ * the background */
+ if (radius == 0 && border_color->alpha == 0)
+ border_width = 0;
+
max = MAX(border_width, radius);
if (radius != 0) {
@@ -393,33 +448,54 @@ big_rectangle_paint(ClutterActor *actor)
}
if (border_width != 0) {
+ ClutterColor effective_border;
+ over (border_color, color, &effective_border);
+
if (!rectangle->border_material)
rectangle->border_material = cogl_material_new ();
cogl_color_set_from_4ub(&tmp_color,
- border_color->red,
- border_color->green,
- border_color->blue,
- actor_opacity * border_color->alpha / 255);
+ effective_border.red,
+ effective_border.green,
+ effective_border.blue,
+ actor_opacity * effective_border.alpha / 255);
cogl_color_premultiply (&tmp_color);
cogl_material_set_color(rectangle->border_material, &tmp_color);
cogl_set_source(rectangle->border_material);
- /* NORTH */
- cogl_rectangle(max, 0,
- width - max, border_width);
-
- /* EAST */
- cogl_rectangle(width - border_width, max,
- width, height - max);
-
- /* SOUTH */
- cogl_rectangle(max, height - border_width,
- width - max, height);
-
- /* WEST */
- cogl_rectangle(0, max,
- border_width, height - max);
+ if (radius > 0) { /* skip corners */
+ /* NORTH */
+ cogl_rectangle(max, 0,
+ width - max, border_width);
+
+ /* EAST */
+ cogl_rectangle(width - border_width, max,
+ width, height - max);
+
+ /* SOUTH */
+ cogl_rectangle(max, height - border_width,
+ width - max, height);
+
+ /* WEST */
+ cogl_rectangle(0, max,
+ border_width, height - max);
+ } else { /* include corners */
+ /* NORTH */
+ cogl_rectangle(0, 0,
+ width, border_width);
+
+ /* EAST */
+ cogl_rectangle(width - border_width, border_width,
+ width, height - border_width);
+
+ /* SOUTH */
+ cogl_rectangle(0, height - border_width,
+ width, height);
+
+ /* WEST */
+ cogl_rectangle(0, border_width,
+ border_width, height - border_width);
+ }
}
if (!rectangle->background_material)
@@ -455,6 +531,7 @@ big_rectangle_paint(ClutterActor *actor)
cogl_rectangle(border_width, max,
width - border_width, height - max);
+out:
clutter_color_free(border_color);
clutter_color_free(color);
}
diff --git a/tests/interactive/borders.js b/tests/interactive/borders.js
index 258a621..d685345 100644
--- a/tests/interactive/borders.js
+++ b/tests/interactive/borders.js
@@ -8,13 +8,13 @@ const UI = imports.testcommon.ui;
UI.init();
let stage = Clutter.Stage.get_default();
stage.width = 600;
-stage.height = 600;
+stage.height = 700;
let vbox = new St.BoxLayout({ vertical: true,
width: stage.width,
height: stage.height,
spacing: 20,
- style: 'padding: 10px; background: #ffee88' });
+ style: 'padding: 10px; background: #ffee88;' });
stage.add_actor(vbox);
vbox.add(new St.Label({ text: "Hello World",
@@ -43,8 +43,14 @@ vbox.add(b1);
b1.add(new St.BoxLayout({ width: 20, height: 20,
style: 'background: black' }));
-vbox.add(new St.Label({ text: "Translucent blue border",
+vbox.add(new St.Label({ text: "Translucent blue border, with rounding",
style: 'border: 20px solid rgba(0, 0, 255, 0.2); '
+ + 'border-radius: 10px; '
+ + 'background: white; '
+ + 'padding: 10px;' }));
+
+vbox.add(new St.Label({ text: "Transparent border",
+ style: 'border: 20px solid transparent; '
+ 'background: white; '
+ 'padding: 10px;' }));
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]