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
4d55ccff39
commit
d263c12e2e
@ -268,6 +268,52 @@ corner_get(guint radius,
|
|||||||
return corner;
|
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
|
static void
|
||||||
big_rectangle_update_corners(BigRectangle *rectangle)
|
big_rectangle_update_corners(BigRectangle *rectangle)
|
||||||
{
|
{
|
||||||
@ -278,6 +324,7 @@ big_rectangle_update_corners(BigRectangle *rectangle)
|
|||||||
if (rectangle->radius != 0) {
|
if (rectangle->radius != 0) {
|
||||||
ClutterColor *color;
|
ClutterColor *color;
|
||||||
ClutterColor *border_color;
|
ClutterColor *border_color;
|
||||||
|
ClutterColor effective_border;
|
||||||
guint border_width;
|
guint border_width;
|
||||||
|
|
||||||
g_object_get(rectangle,
|
g_object_get(rectangle,
|
||||||
@ -286,10 +333,12 @@ big_rectangle_update_corners(BigRectangle *rectangle)
|
|||||||
"color", &color,
|
"color", &color,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
|
over (border_color, color, &effective_border);
|
||||||
|
|
||||||
corner = corner_get(rectangle->radius,
|
corner = corner_get(rectangle->radius,
|
||||||
color,
|
color,
|
||||||
border_width,
|
border_width,
|
||||||
border_color);
|
&effective_border);
|
||||||
|
|
||||||
clutter_color_free(border_color);
|
clutter_color_free(border_color);
|
||||||
clutter_color_free(color);
|
clutter_color_free(color);
|
||||||
@ -329,12 +378,10 @@ big_rectangle_paint(ClutterActor *actor)
|
|||||||
|
|
||||||
rectangle = BIG_RECTANGLE(actor);
|
rectangle = BIG_RECTANGLE(actor);
|
||||||
|
|
||||||
if (rectangle->radius == 0) {
|
/* We can't chain up, even when we the radius is 0, because of the different
|
||||||
/* In that case we are no different than our parent class,
|
* interpretation of the border/background relationship here than for
|
||||||
* so don't bother */
|
* ClutterRectangle.
|
||||||
CLUTTER_ACTOR_CLASS(big_rectangle_parent_class)->paint(actor);
|
*/
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rectangle->corners_dirty)
|
if (rectangle->corners_dirty)
|
||||||
big_rectangle_update_corners(rectangle);
|
big_rectangle_update_corners(rectangle);
|
||||||
@ -345,6 +392,9 @@ big_rectangle_paint(ClutterActor *actor)
|
|||||||
"color", &color,
|
"color", &color,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
|
if (border_color->alpha == 0 && color->alpha == 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
actor_opacity = clutter_actor_get_paint_opacity (actor);
|
actor_opacity = clutter_actor_get_paint_opacity (actor);
|
||||||
|
|
||||||
clutter_actor_get_allocation_box(actor, &box);
|
clutter_actor_get_allocation_box(actor, &box);
|
||||||
@ -358,6 +408,11 @@ big_rectangle_paint(ClutterActor *actor)
|
|||||||
|
|
||||||
radius = rectangle->radius;
|
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);
|
max = MAX(border_width, radius);
|
||||||
|
|
||||||
if (radius != 0) {
|
if (radius != 0) {
|
||||||
@ -393,33 +448,54 @@ big_rectangle_paint(ClutterActor *actor)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (border_width != 0) {
|
if (border_width != 0) {
|
||||||
|
ClutterColor effective_border;
|
||||||
|
over (border_color, color, &effective_border);
|
||||||
|
|
||||||
if (!rectangle->border_material)
|
if (!rectangle->border_material)
|
||||||
rectangle->border_material = cogl_material_new ();
|
rectangle->border_material = cogl_material_new ();
|
||||||
|
|
||||||
cogl_color_set_from_4ub(&tmp_color,
|
cogl_color_set_from_4ub(&tmp_color,
|
||||||
border_color->red,
|
effective_border.red,
|
||||||
border_color->green,
|
effective_border.green,
|
||||||
border_color->blue,
|
effective_border.blue,
|
||||||
actor_opacity * border_color->alpha / 255);
|
actor_opacity * effective_border.alpha / 255);
|
||||||
cogl_color_premultiply (&tmp_color);
|
cogl_color_premultiply (&tmp_color);
|
||||||
cogl_material_set_color(rectangle->border_material, &tmp_color);
|
cogl_material_set_color(rectangle->border_material, &tmp_color);
|
||||||
cogl_set_source(rectangle->border_material);
|
cogl_set_source(rectangle->border_material);
|
||||||
|
|
||||||
/* NORTH */
|
if (radius > 0) { /* skip corners */
|
||||||
cogl_rectangle(max, 0,
|
/* NORTH */
|
||||||
width - max, border_width);
|
cogl_rectangle(max, 0,
|
||||||
|
width - max, border_width);
|
||||||
|
|
||||||
/* EAST */
|
/* EAST */
|
||||||
cogl_rectangle(width - border_width, max,
|
cogl_rectangle(width - border_width, max,
|
||||||
width, height - max);
|
width, height - max);
|
||||||
|
|
||||||
/* SOUTH */
|
/* SOUTH */
|
||||||
cogl_rectangle(max, height - border_width,
|
cogl_rectangle(max, height - border_width,
|
||||||
width - max, height);
|
width - max, height);
|
||||||
|
|
||||||
/* WEST */
|
/* WEST */
|
||||||
cogl_rectangle(0, max,
|
cogl_rectangle(0, max,
|
||||||
border_width, height - 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)
|
if (!rectangle->background_material)
|
||||||
@ -455,6 +531,7 @@ big_rectangle_paint(ClutterActor *actor)
|
|||||||
cogl_rectangle(border_width, max,
|
cogl_rectangle(border_width, max,
|
||||||
width - border_width, height - max);
|
width - border_width, height - max);
|
||||||
|
|
||||||
|
out:
|
||||||
clutter_color_free(border_color);
|
clutter_color_free(border_color);
|
||||||
clutter_color_free(color);
|
clutter_color_free(color);
|
||||||
}
|
}
|
||||||
|
@ -8,13 +8,13 @@ const UI = imports.testcommon.ui;
|
|||||||
UI.init();
|
UI.init();
|
||||||
let stage = Clutter.Stage.get_default();
|
let stage = Clutter.Stage.get_default();
|
||||||
stage.width = 600;
|
stage.width = 600;
|
||||||
stage.height = 600;
|
stage.height = 700;
|
||||||
|
|
||||||
let vbox = new St.BoxLayout({ vertical: true,
|
let vbox = new St.BoxLayout({ vertical: true,
|
||||||
width: stage.width,
|
width: stage.width,
|
||||||
height: stage.height,
|
height: stage.height,
|
||||||
spacing: 20,
|
spacing: 20,
|
||||||
style: 'padding: 10px; background: #ffee88' });
|
style: 'padding: 10px; background: #ffee88;' });
|
||||||
stage.add_actor(vbox);
|
stage.add_actor(vbox);
|
||||||
|
|
||||||
vbox.add(new St.Label({ text: "Hello World",
|
vbox.add(new St.Label({ text: "Hello World",
|
||||||
@ -43,8 +43,14 @@ vbox.add(b1);
|
|||||||
b1.add(new St.BoxLayout({ width: 20, height: 20,
|
b1.add(new St.BoxLayout({ width: 20, height: 20,
|
||||||
style: 'background: black' }));
|
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); '
|
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; '
|
+ 'background: white; '
|
||||||
+ 'padding: 10px;' }));
|
+ 'padding: 10px;' }));
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user