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
This commit is contained in:
parent
d92b1d8da2
commit
304b48a15d
@ -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);
|
||||
if (radius > 0) { /* skip corners */
|
||||
/* NORTH */
|
||||
cogl_rectangle(max, 0,
|
||||
width - max, border_width);
|
||||
|
||||
/* EAST */
|
||||
cogl_rectangle(width - border_width, max,
|
||||
width, height - max);
|
||||
/* EAST */
|
||||
cogl_rectangle(width - border_width, max,
|
||||
width, height - max);
|
||||
|
||||
/* SOUTH */
|
||||
cogl_rectangle(max, height - border_width,
|
||||
width - max, height);
|
||||
/* SOUTH */
|
||||
cogl_rectangle(max, height - border_width,
|
||||
width - max, height);
|
||||
|
||||
/* WEST */
|
||||
cogl_rectangle(0, max,
|
||||
border_width, height - max);
|
||||
/* 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);
|
||||
}
|
||||
|
@ -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;' }));
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user