st-theme-node: Support non-uniform border widths

While non-uniform border widths were parsed correctly, an arbitrary
side's width was picked when painting, so that each border ended up
with the same width and the widths specified in CSS were ignored.

At least for sides between non-rounded corners, using a different
border width can be reasonable, for instance at screen edges.

Different border widths around rounded corners are kind of crack,
but then it would be lame not to support it ...

https://bugzilla.gnome.org/show_bug.cgi?id=607500
This commit is contained in:
Florian Müllner 2010-11-23 15:10:57 +01:00
parent cb2babb1a0
commit cb5c18c783
3 changed files with 306 additions and 128 deletions

View File

@ -49,6 +49,22 @@ typedef struct {
guint border_width_2; guint border_width_2;
} StCornerSpec; } StCornerSpec;
static void
elliptical_arc (cairo_t *cr,
double x_center,
double y_center,
double x_radius,
double y_radius,
double angle1,
double angle2)
{
cairo_save (cr);
cairo_translate (cr, x_center, y_center);
cairo_scale (cr, x_radius, y_radius);
cairo_arc (cr, 0, 0, 1.0, angle1, angle2);
cairo_restore (cr);
}
static CoglHandle static CoglHandle
create_corner_material (StCornerSpec *corner) create_corner_material (StCornerSpec *corner)
{ {
@ -73,13 +89,11 @@ create_corner_material (StCornerSpec *corner)
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
cairo_scale (cr, size, size); cairo_scale (cr, size, size);
/* TODO support nonuniform border widths */ if (max_border_width <= corner->radius)
if (corner->border_width_1 < corner->radius)
{ {
double internal_radius = 0.5 * (1.0 - (double) corner->border_width_1 / corner->radius); double x_radius, y_radius;
if (corner->border_width_1 != 0) if (max_border_width != 0)
{ {
cairo_set_source_rgba (cr, cairo_set_source_rgba (cr,
corner->border_color_1.red / 255., corner->border_color_1.red / 255.,
@ -96,14 +110,41 @@ create_corner_material (StCornerSpec *corner)
corner->color.green / 255., corner->color.green / 255.,
corner->color.blue / 255., corner->color.blue / 255.,
corner->color.alpha / 255.); corner->color.alpha / 255.);
cairo_arc (cr, 0.5, 0.5, internal_radius, 0, 2 * M_PI);
x_radius = 0.5 * (1.0 - (double) corner->border_width_2 / corner->radius);
y_radius = 0.5 * (1.0 - (double) corner->border_width_1 / corner->radius);
/* TOPRIGHT */
elliptical_arc (cr,
0.5, 0.5,
x_radius, y_radius,
3 * M_PI / 2, 2 * M_PI);
/* BOTTOMRIGHT */
elliptical_arc (cr,
0.5, 0.5,
x_radius, y_radius,
0, M_PI / 2);
/* TOPLEFT */
elliptical_arc (cr,
0.5, 0.5,
x_radius, y_radius,
M_PI, 3 * M_PI / 2);
/* BOTTOMLEFT */
elliptical_arc (cr,
0.5, 0.5,
x_radius, y_radius,
M_PI / 2, M_PI);
cairo_fill (cr); cairo_fill (cr);
} }
else else
{ {
double radius; double radius;
radius = (gdouble)corner->radius / corner->border_width_1; radius = (gdouble)corner->radius / max_border_width;
cairo_set_source_rgba (cr, cairo_set_source_rgba (cr,
corner->border_color_1.red / 255., corner->border_color_1.red / 255.,
@ -216,6 +257,41 @@ over (const ClutterColor *source,
unpremultiply (result); unpremultiply (result);
} }
static void
st_theme_node_get_corner_border_widths (StThemeNode *node,
StCorner corner_id,
guint *border_width_1,
guint *border_width_2)
{
switch (corner_id)
{
case ST_CORNER_TOPLEFT:
if (border_width_1)
*border_width_1 = node->border_width[ST_SIDE_TOP];
if (border_width_2)
*border_width_2 = node->border_width[ST_SIDE_LEFT];
break;
case ST_CORNER_TOPRIGHT:
if (border_width_1)
*border_width_1 = node->border_width[ST_SIDE_TOP];
if (border_width_2)
*border_width_2 = node->border_width[ST_SIDE_RIGHT];
break;
case ST_CORNER_BOTTOMRIGHT:
if (border_width_1)
*border_width_1 = node->border_width[ST_SIDE_BOTTOM];
if (border_width_2)
*border_width_2 = node->border_width[ST_SIDE_RIGHT];
break;
case ST_CORNER_BOTTOMLEFT:
if (border_width_1)
*border_width_1 = node->border_width[ST_SIDE_BOTTOM];
if (border_width_2)
*border_width_2 = node->border_width[ST_SIDE_LEFT];
break;
}
}
static CoglHandle static CoglHandle
st_theme_node_lookup_corner (StThemeNode *node, st_theme_node_lookup_corner (StThemeNode *node,
StCorner corner_id) StCorner corner_id)
@ -233,30 +309,25 @@ st_theme_node_lookup_corner (StThemeNode *node,
corner.radius = node->border_radius[corner_id]; corner.radius = node->border_radius[corner_id];
corner.color = node->background_color; corner.color = node->background_color;
st_theme_node_get_corner_border_widths (node, corner_id,
&corner.border_width_1,
&corner.border_width_2);
switch (corner_id) switch (corner_id)
{ {
case ST_CORNER_TOPLEFT: case ST_CORNER_TOPLEFT:
corner.border_width_1 = node->border_width[ST_SIDE_TOP];
corner.border_width_2 = node->border_width[ST_SIDE_LEFT];
over (&node->border_color[ST_SIDE_TOP], &corner.color, &corner.border_color_1); over (&node->border_color[ST_SIDE_TOP], &corner.color, &corner.border_color_1);
over (&node->border_color[ST_SIDE_LEFT], &corner.color, &corner.border_color_2); over (&node->border_color[ST_SIDE_LEFT], &corner.color, &corner.border_color_2);
break; break;
case ST_CORNER_TOPRIGHT: case ST_CORNER_TOPRIGHT:
corner.border_width_1 = node->border_width[ST_SIDE_TOP];
corner.border_width_2 = node->border_width[ST_SIDE_RIGHT];
over (&node->border_color[ST_SIDE_TOP], &corner.color, &corner.border_color_1); over (&node->border_color[ST_SIDE_TOP], &corner.color, &corner.border_color_1);
over (&node->border_color[ST_SIDE_RIGHT], &corner.color, &corner.border_color_2); over (&node->border_color[ST_SIDE_RIGHT], &corner.color, &corner.border_color_2);
break; break;
case ST_CORNER_BOTTOMRIGHT: case ST_CORNER_BOTTOMRIGHT:
corner.border_width_1 = node->border_width[ST_SIDE_BOTTOM];
corner.border_width_2 = node->border_width[ST_SIDE_RIGHT];
over (&node->border_color[ST_SIDE_BOTTOM], &corner.color, &corner.border_color_1); over (&node->border_color[ST_SIDE_BOTTOM], &corner.color, &corner.border_color_1);
over (&node->border_color[ST_SIDE_RIGHT], &corner.color, &corner.border_color_2); over (&node->border_color[ST_SIDE_RIGHT], &corner.color, &corner.border_color_2);
break; break;
case ST_CORNER_BOTTOMLEFT: case ST_CORNER_BOTTOMLEFT:
corner.border_width_1 = node->border_width[ST_SIDE_BOTTOM];
corner.border_width_2 = node->border_width[ST_SIDE_LEFT];
over (&node->border_color[ST_SIDE_BOTTOM], &corner.color, &corner.border_color_1); over (&node->border_color[ST_SIDE_BOTTOM], &corner.color, &corner.border_color_1);
over (&node->border_color[ST_SIDE_LEFT], &corner.color, &corner.border_color_2); over (&node->border_color[ST_SIDE_LEFT], &corner.color, &corner.border_color_2);
break; break;
@ -346,28 +417,14 @@ get_background_position (StThemeNode *self,
} }
/* Use of this function marks code which doesn't support /* Use of this function marks code which doesn't support
* non-uniform widths and/or colors. * non-uniform colors.
*/ */
static gboolean static void
get_arbitrary_border (StThemeNode *node, get_arbitrary_border_color (StThemeNode *node,
int *width, ClutterColor *color)
ClutterColor *color)
{ {
int w; if (color)
st_theme_node_get_border_color (node, ST_SIDE_TOP, color);
w = st_theme_node_get_border_width (node, ST_SIDE_TOP);
if (w > 0)
{
if (width)
*width = w;
if (color)
st_theme_node_get_border_color (node, ST_SIDE_TOP, color);
return TRUE;
}
if (width)
*width = 0;
return FALSE;
} }
static CoglHandle static CoglHandle
@ -379,7 +436,7 @@ st_theme_node_render_gradient (StThemeNode *node)
cairo_surface_t *surface; cairo_surface_t *surface;
cairo_pattern_t *pattern; cairo_pattern_t *pattern;
ClutterColor border_color; ClutterColor border_color;
int border_width; int border_width[4];
guint rowstride; guint rowstride;
guchar *data; guchar *data;
@ -392,11 +449,15 @@ st_theme_node_render_gradient (StThemeNode *node)
rowstride); rowstride);
cr = cairo_create (surface); cr = cairo_create (surface);
/* TODO - support non-uniform border colors and widths */ /* TODO - support non-uniform border colors */
get_arbitrary_border (node, &border_width, &border_color); get_arbitrary_border_color (node, &border_color);
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
radius[i] = st_theme_node_get_border_radius (node, i); {
border_width[i] = st_theme_node_get_border_width (node, i);
radius[i] = st_theme_node_get_border_radius (node, i);
}
if (node->background_gradient_type == ST_GRADIENT_VERTICAL) if (node->background_gradient_type == ST_GRADIENT_VERTICAL)
pattern = cairo_pattern_create_linear (0, 0, 0, node->alloc_height); pattern = cairo_pattern_create_linear (0, 0, 0, node->alloc_height);
@ -437,13 +498,13 @@ st_theme_node_render_gradient (StThemeNode *node)
radius[ST_CORNER_TOPRIGHT], radius[ST_CORNER_TOPRIGHT],
radius[ST_CORNER_TOPRIGHT], 3 * M_PI / 2, 2 * M_PI); radius[ST_CORNER_TOPRIGHT], 3 * M_PI / 2, 2 * M_PI);
cairo_line_to (cr, node->alloc_width, node->alloc_height - radius[ST_CORNER_BOTTOMRIGHT]); cairo_line_to (cr, node->alloc_width, node->alloc_height - radius[ST_CORNER_BOTTOMRIGHT]);
if (radius[ST_CORNER_BOTTOMRIGHT]) if (radius[ST_CORNER_BOTTOMRIGHT] > 0)
cairo_arc (cr, cairo_arc (cr,
node->alloc_width - radius[ST_CORNER_BOTTOMRIGHT], node->alloc_width - radius[ST_CORNER_BOTTOMRIGHT],
node->alloc_height - radius[ST_CORNER_BOTTOMRIGHT], node->alloc_height - radius[ST_CORNER_BOTTOMRIGHT],
radius[ST_CORNER_BOTTOMRIGHT], 0, M_PI / 2); radius[ST_CORNER_BOTTOMRIGHT], 0, M_PI / 2);
cairo_line_to (cr, radius[ST_CORNER_BOTTOMLEFT], node->alloc_height); cairo_line_to (cr, radius[ST_CORNER_BOTTOMLEFT], node->alloc_height);
if (radius[ST_CORNER_BOTTOMLEFT]) if (radius[ST_CORNER_BOTTOMLEFT] > 0)
cairo_arc (cr, cairo_arc (cr,
radius[ST_CORNER_BOTTOMLEFT], radius[ST_CORNER_BOTTOMLEFT],
node->alloc_height - radius[ST_CORNER_BOTTOMLEFT], node->alloc_height - radius[ST_CORNER_BOTTOMLEFT],
@ -456,7 +517,10 @@ st_theme_node_render_gradient (StThemeNode *node)
* otherwise the outline shape is filled with the background * otherwise the outline shape is filled with the background
* gradient directly * gradient directly
*/ */
if (border_width > 0) if (border_width[ST_SIDE_TOP] > 0 ||
border_width[ST_SIDE_RIGHT] > 0 ||
border_width[ST_SIDE_BOTTOM] > 0 ||
border_width[ST_SIDE_LEFT] > 0)
{ {
cairo_set_source_rgba (cr, cairo_set_source_rgba (cr,
border_color.red / 255., border_color.red / 255.,
@ -465,47 +529,70 @@ st_theme_node_render_gradient (StThemeNode *node)
border_color.alpha / 255.); border_color.alpha / 255.);
cairo_fill (cr); cairo_fill (cr);
if (radius[ST_CORNER_TOPLEFT] > border_width) if (radius[ST_CORNER_TOPLEFT] > MAX(border_width[ST_SIDE_TOP],
cairo_arc (cr, border_width[ST_SIDE_LEFT]))
radius[ST_CORNER_TOPLEFT], elliptical_arc (cr,
radius[ST_CORNER_TOPLEFT], radius[ST_CORNER_TOPLEFT],
radius[ST_CORNER_TOPLEFT] - border_width, radius[ST_CORNER_TOPLEFT],
M_PI, 3 * M_PI / 2); radius[ST_CORNER_TOPLEFT] - border_width[ST_SIDE_LEFT],
radius[ST_CORNER_TOPLEFT] - border_width[ST_SIDE_TOP],
M_PI, 3 * M_PI / 2);
else else
cairo_move_to (cr, border_width, border_width); cairo_move_to (cr,
border_width[ST_SIDE_LEFT],
border_width[ST_SIDE_TOP]);
cairo_line_to (cr, cairo_line_to (cr,
node->alloc_width - MAX(radius[ST_CORNER_TOPRIGHT], border_width), node->alloc_width - MAX(radius[ST_CORNER_TOPRIGHT], border_width[ST_SIDE_RIGHT]),
border_width); border_width[ST_SIDE_TOP]);
if (radius[ST_CORNER_TOPRIGHT] > border_width) if (radius[ST_CORNER_TOPRIGHT] > MAX(border_width[ST_SIDE_TOP],
cairo_arc (cr, border_width[ST_SIDE_RIGHT]))
node->alloc_width - radius[ST_CORNER_TOPRIGHT], elliptical_arc (cr,
radius[ST_CORNER_TOPRIGHT], node->alloc_width - radius[ST_CORNER_TOPRIGHT],
radius[ST_CORNER_TOPRIGHT] - border_width, radius[ST_CORNER_TOPRIGHT],
3 * M_PI / 2, 2 * M_PI); radius[ST_CORNER_TOPRIGHT] - border_width[ST_SIDE_RIGHT],
radius[ST_CORNER_TOPRIGHT] - border_width[ST_SIDE_TOP],
3 * M_PI / 2, 2 * M_PI);
else
cairo_line_to (cr,
node->alloc_width - border_width[ST_SIDE_RIGHT],
border_width[ST_SIDE_TOP]);
cairo_line_to (cr, cairo_line_to (cr,
node->alloc_width - border_width, node->alloc_width - border_width[ST_SIDE_RIGHT],
node->alloc_height - MAX(radius[ST_CORNER_BOTTOMRIGHT], border_width)); node->alloc_height - MAX(radius[ST_CORNER_BOTTOMRIGHT], border_width[ST_SIDE_BOTTOM]));
if (radius[ST_CORNER_BOTTOMRIGHT] > border_width) if (radius[ST_CORNER_BOTTOMRIGHT] > MAX(border_width[ST_SIDE_BOTTOM],
cairo_arc (cr, border_width[ST_SIDE_RIGHT]))
node->alloc_width - radius[ST_CORNER_BOTTOMRIGHT], elliptical_arc (cr,
node->alloc_height - radius[ST_CORNER_BOTTOMRIGHT], node->alloc_width - radius[ST_CORNER_BOTTOMRIGHT],
radius[ST_CORNER_BOTTOMRIGHT] - border_width, node->alloc_height - radius[ST_CORNER_BOTTOMRIGHT],
0, M_PI / 2); radius[ST_CORNER_BOTTOMRIGHT] - border_width[ST_SIDE_RIGHT],
radius[ST_CORNER_BOTTOMRIGHT] - border_width[ST_SIDE_BOTTOM],
0, M_PI / 2);
else
cairo_line_to (cr,
node->alloc_width - border_width[ST_SIDE_RIGHT],
node->alloc_height - border_width[ST_SIDE_BOTTOM]);
cairo_line_to (cr, cairo_line_to (cr,
MAX(radius[ST_CORNER_BOTTOMLEFT], border_width), MAX(radius[ST_CORNER_BOTTOMLEFT], border_width[ST_SIDE_LEFT]),
node->alloc_height - border_width); node->alloc_height - border_width[ST_SIDE_BOTTOM]);
if (radius[ST_CORNER_BOTTOMLEFT] > MAX(border_width[ST_SIDE_BOTTOM],
border_width[ST_SIDE_LEFT]))
elliptical_arc (cr,
radius[ST_CORNER_BOTTOMLEFT],
node->alloc_height - radius[ST_CORNER_BOTTOMLEFT],
radius[ST_CORNER_BOTTOMLEFT] - border_width[ST_SIDE_LEFT],
radius[ST_CORNER_BOTTOMLEFT] - border_width[ST_SIDE_BOTTOM],
M_PI / 2, M_PI);
else
cairo_line_to (cr,
border_width[ST_SIDE_LEFT],
node->alloc_height - border_width[ST_SIDE_BOTTOM]);
if (radius[ST_CORNER_BOTTOMLEFT] > border_width)
cairo_arc (cr,
radius[ST_CORNER_BOTTOMLEFT],
node->alloc_height - radius[ST_CORNER_BOTTOMLEFT],
radius[ST_CORNER_BOTTOMLEFT] - border_width,
M_PI / 2, M_PI);
cairo_close_path (cr); cairo_close_path (cr);
} }
@ -706,27 +793,40 @@ st_theme_node_paint_borders (StThemeNode *node,
{ {
float width, height; float width, height;
int border_width; int border_width[4];
int max_border_radius = 0; int max_border_radius = 0;
int max_width_radius[4]; int max_width_radius[4];
int corner_id; int corner_id, side_id;
ClutterColor border_color; ClutterColor border_color;
guint8 alpha; guint8 alpha;
width = box->x2 - box->x1; width = box->x2 - box->x1;
height = box->y2 - box->y1; height = box->y2 - box->y1;
get_arbitrary_border (node, &border_width, &border_color); /* TODO - support non-uniform border colors */
get_arbitrary_border_color (node, &border_color);
for (side_id = 0; side_id < 4; side_id++)
border_width[side_id] = st_theme_node_get_border_width(node, side_id);
for (corner_id = 0; corner_id < 4; corner_id++) for (corner_id = 0; corner_id < 4; corner_id++)
{ {
guint border_width_1, border_width_2;
st_theme_node_get_corner_border_widths (node, corner_id,
&border_width_1, &border_width_2);
if (node->border_radius[corner_id] > max_border_radius) if (node->border_radius[corner_id] > max_border_radius)
max_border_radius = node->border_radius[corner_id]; max_border_radius = node->border_radius[corner_id];
max_width_radius[corner_id] = MAX(border_width, max_width_radius[corner_id] = MAX(MAX(border_width_1, border_width_2),
node->border_radius[corner_id]); node->border_radius[corner_id]);
} }
/* borders */ /* borders */
if (border_width > 0) if (border_width[ST_SIDE_TOP] > 0 ||
border_width[ST_SIDE_RIGHT] > 0 ||
border_width[ST_SIDE_BOTTOM] > 0 ||
border_width[ST_SIDE_LEFT] > 0)
{ {
ClutterColor effective_border; ClutterColor effective_border;
gboolean skip_corner_1, skip_corner_2; gboolean skip_corner_1, skip_corner_2;
@ -749,18 +849,19 @@ st_theme_node_paint_borders (StThemeNode *node,
x1 = skip_corner_1 ? max_width_radius[ST_CORNER_TOPLEFT] : 0; x1 = skip_corner_1 ? max_width_radius[ST_CORNER_TOPLEFT] : 0;
y1 = 0; y1 = 0;
x2 = skip_corner_2 ? width - max_width_radius[ST_CORNER_TOPRIGHT] : width; x2 = skip_corner_2 ? width - max_width_radius[ST_CORNER_TOPRIGHT] : width;
y2 = border_width; y2 = border_width[ST_SIDE_TOP];
cogl_rectangle (x1, y1, x2, y2); cogl_rectangle (x1, y1, x2, y2);
/* EAST */ /* EAST */
skip_corner_1 = node->border_radius[ST_CORNER_TOPRIGHT] > 0; skip_corner_1 = node->border_radius[ST_CORNER_TOPRIGHT] > 0;
skip_corner_2 = node->border_radius[ST_CORNER_BOTTOMRIGHT] > 0; skip_corner_2 = node->border_radius[ST_CORNER_BOTTOMRIGHT] > 0;
x1 = width - border_width; x1 = width - border_width[ST_SIDE_RIGHT];
y1 = skip_corner_1 ? max_width_radius[ST_CORNER_TOPRIGHT] : border_width; y1 = skip_corner_1 ? max_width_radius[ST_CORNER_TOPRIGHT]
: border_width[ST_SIDE_TOP];
x2 = width; x2 = width;
y2 = skip_corner_2 ? height - max_width_radius[ST_CORNER_BOTTOMRIGHT] y2 = skip_corner_2 ? height - max_width_radius[ST_CORNER_BOTTOMRIGHT]
: height - border_width; : height - border_width[ST_SIDE_BOTTOM];
cogl_rectangle (x1, y1, x2, y2); cogl_rectangle (x1, y1, x2, y2);
/* SOUTH */ /* SOUTH */
@ -768,7 +869,7 @@ st_theme_node_paint_borders (StThemeNode *node,
skip_corner_2 = node->border_radius[ST_CORNER_BOTTOMRIGHT] > 0; skip_corner_2 = node->border_radius[ST_CORNER_BOTTOMRIGHT] > 0;
x1 = skip_corner_1 ? max_width_radius[ST_CORNER_BOTTOMLEFT] : 0; x1 = skip_corner_1 ? max_width_radius[ST_CORNER_BOTTOMLEFT] : 0;
y1 = height - border_width; y1 = height - border_width[ST_SIDE_BOTTOM];
x2 = skip_corner_2 ? width - max_width_radius[ST_CORNER_BOTTOMRIGHT] x2 = skip_corner_2 ? width - max_width_radius[ST_CORNER_BOTTOMRIGHT]
: width; : width;
y2 = height; y2 = height;
@ -779,10 +880,11 @@ st_theme_node_paint_borders (StThemeNode *node,
skip_corner_2 = node->border_radius[ST_CORNER_BOTTOMLEFT] > 0; skip_corner_2 = node->border_radius[ST_CORNER_BOTTOMLEFT] > 0;
x1 = 0; x1 = 0;
y1 = skip_corner_1 ? max_width_radius[ST_CORNER_TOPLEFT] : border_width; y1 = skip_corner_1 ? max_width_radius[ST_CORNER_TOPLEFT]
x2 = border_width; : border_width[ST_SIDE_TOP];
x2 = border_width[ST_SIDE_LEFT];
y2 = skip_corner_2 ? height - max_width_radius[ST_CORNER_BOTTOMLEFT] y2 = skip_corner_2 ? height - max_width_radius[ST_CORNER_BOTTOMLEFT]
: height - border_width; : height - border_width[ST_SIDE_BOTTOM];
cogl_rectangle (x1, y1, x2, y2); cogl_rectangle (x1, y1, x2, y2);
} }
} }
@ -853,82 +955,99 @@ st_theme_node_paint_borders (StThemeNode *node,
switch (corner_id) switch (corner_id)
{ {
case ST_CORNER_TOPLEFT: case ST_CORNER_TOPLEFT:
verts[0] = border_width; verts[0] = border_width[ST_SIDE_LEFT];
verts[1] = max_width_radius[ST_CORNER_TOPLEFT]; verts[1] = MAX(node->border_radius[corner_id],
border_width[ST_SIDE_TOP]);
verts[2] = max_border_radius; verts[2] = max_border_radius;
verts[3] = max_border_radius; verts[3] = max_border_radius;
if (n_rects == 2) if (n_rects == 2)
{ {
verts[4] = max_width_radius[ST_CORNER_TOPLEFT]; verts[4] = MAX(node->border_radius[corner_id],
verts[5] = border_width; border_width[ST_SIDE_LEFT]);
verts[5] = border_width[ST_SIDE_TOP];
verts[6] = max_border_radius; verts[6] = max_border_radius;
verts[7] = max_width_radius[ST_CORNER_TOPLEFT]; verts[7] = MAX(node->border_radius[corner_id],
border_width[ST_SIDE_TOP]);
} }
break; break;
case ST_CORNER_TOPRIGHT: case ST_CORNER_TOPRIGHT:
verts[0] = width - max_border_radius; verts[0] = width - max_border_radius;
verts[1] = max_width_radius[ST_CORNER_TOPRIGHT]; verts[1] = MAX(node->border_radius[corner_id],
verts[2] = width - border_width; border_width[ST_SIDE_TOP]);
verts[2] = width - border_width[ST_SIDE_RIGHT];
verts[3] = max_border_radius; verts[3] = max_border_radius;
if (n_rects == 2) if (n_rects == 2)
{ {
verts[4] = width - max_border_radius; verts[4] = width - max_border_radius;
verts[5] = border_width; verts[5] = border_width[ST_SIDE_TOP];
verts[6] = width - max_width_radius[ST_CORNER_TOPRIGHT]; verts[6] = width - MAX(node->border_radius[corner_id],
verts[7] = max_width_radius[ST_CORNER_TOPRIGHT]; border_width[ST_SIDE_RIGHT]);
verts[7] = MAX(node->border_radius[corner_id],
border_width[ST_SIDE_TOP]);
} }
break; break;
case ST_CORNER_BOTTOMRIGHT: case ST_CORNER_BOTTOMRIGHT:
verts[0] = width - max_border_radius; verts[0] = width - max_border_radius;
verts[1] = height - max_border_radius; verts[1] = height - max_border_radius;
verts[2] = width - border_width; verts[2] = width - border_width[ST_SIDE_RIGHT];
verts[3] = height - max_width_radius[ST_CORNER_BOTTOMRIGHT]; verts[3] = height - MAX(node->border_radius[corner_id],
border_width[ST_SIDE_BOTTOM]);
if (n_rects == 2) if (n_rects == 2)
{ {
verts[4] = width - max_border_radius; verts[4] = width - max_border_radius;
verts[5] = height - max_width_radius[ST_CORNER_BOTTOMRIGHT]; verts[5] = height - MAX(node->border_radius[corner_id],
verts[6] = width - max_width_radius[ST_CORNER_BOTTOMRIGHT]; border_width[ST_SIDE_BOTTOM]);
verts[7] = height - border_width; verts[6] = width - MAX(node->border_radius[corner_id],
border_width[ST_SIDE_RIGHT]);
verts[7] = height - border_width[ST_SIDE_BOTTOM];
} }
break; break;
case ST_CORNER_BOTTOMLEFT: case ST_CORNER_BOTTOMLEFT:
verts[0] = border_width; verts[0] = border_width[ST_SIDE_LEFT];
verts[1] = height - max_border_radius; verts[1] = height - max_border_radius;
verts[2] = max_border_radius; verts[2] = max_border_radius;
verts[3] = height - max_width_radius[ST_CORNER_BOTTOMLEFT]; verts[3] = height - MAX(node->border_radius[corner_id],
border_width[ST_SIDE_BOTTOM]);
if (n_rects == 2) if (n_rects == 2)
{ {
verts[4] = max_width_radius[ST_CORNER_BOTTOMLEFT]; verts[4] = MAX(node->border_radius[corner_id],
verts[5] = height - max_width_radius[ST_CORNER_BOTTOMLEFT]; border_width[ST_SIDE_LEFT]);
verts[5] = height - MAX(node->border_radius[corner_id],
border_width[ST_SIDE_BOTTOM]);
verts[6] = max_border_radius; verts[6] = max_border_radius;
verts[7] = height - border_width; verts[7] = height - border_width[ST_SIDE_BOTTOM];
} }
break; break;
} }
cogl_rectangles (verts, n_rects); cogl_rectangles (verts, n_rects);
} }
if (max_border_radius > border_width) /* Once we've drawn the borders and corners, if the corners are bigger
{ * then the border width, the remaining area is shaped like
/* Once we've drawn the borders and corners, if the corners are bigger *
* the the border width, the remaining area is shaped like * ########
* * ##########
* ######## * ##########
* ########## * ########
* ########## *
* ######## * We draw it in at most 3 pieces - first the top and bottom if
* * necessary, then the main rectangle
* We draw it in 3 pieces - first the top and bottom, then the main */
* rectangle if (max_border_radius > border_width[ST_SIDE_TOP])
*/ cogl_rectangle (MAX(max_border_radius, border_width[ST_SIDE_LEFT]),
cogl_rectangle (max_border_radius, border_width, border_width[ST_SIDE_TOP],
width - max_border_radius, max_border_radius); width - MAX(max_border_radius, border_width[ST_SIDE_RIGHT]),
cogl_rectangle (max_border_radius, height - max_border_radius, max_border_radius);
width - max_border_radius, height - border_width); if (max_border_radius > border_width[ST_SIDE_BOTTOM])
} cogl_rectangle (MAX(max_border_radius, border_width[ST_SIDE_LEFT]),
height - max_border_radius,
width - MAX(max_border_radius, border_width[ST_SIDE_RIGHT]),
height - border_width[ST_SIDE_BOTTOM]);
cogl_rectangle (border_width, MAX(border_width, max_border_radius), cogl_rectangle (border_width[ST_SIDE_LEFT],
width - border_width, height - MAX(border_width, max_border_radius)); MAX(border_width[ST_SIDE_TOP], max_border_radius),
width - border_width[ST_SIDE_RIGHT],
height - MAX(border_width[ST_SIDE_BOTTOM], max_border_radius));
} }
} }
@ -1108,8 +1227,6 @@ st_theme_node_paint (StThemeNode *node,
* zero width or a border image is being used. * zero width or a border image is being used.
* *
* Deviations from the above as implemented here: * Deviations from the above as implemented here:
* - Nonuniform border widths combined with a non-zero border radius result
* in the border radius being ignored
* - The combination of border image and a non-zero border radius is * - The combination of border image and a non-zero border radius is
* not supported; the background color will be drawn with square * not supported; the background color will be drawn with square
* corners. * corners.

View File

@ -4,6 +4,7 @@ EXTRA_DIST = run-test.sh.in
TEST_JS = \ TEST_JS = \
interactive/borders.js \ interactive/borders.js \
interactive/border-radius.js \ interactive/border-radius.js \
interactive/border-width.js \
interactive/box-layout.js \ interactive/box-layout.js \
interactive/calendar.js \ interactive/calendar.js \
interactive/css-fonts.js \ interactive/css-fonts.js \

View File

@ -0,0 +1,60 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const St = imports.gi.St;
const UI = imports.testcommon.ui;
UI.init();
let stage = Clutter.Stage.get_default();
stage.width = 640;
stage.height = 480;
let vbox = new St.BoxLayout({ width: stage.width,
height: stage.height,
style: 'padding: 10px; background: #ffee88;'
});
stage.add_actor(vbox);
let scroll = new St.ScrollView();
vbox.add(scroll, { expand: true });
let box = new St.BoxLayout({ vertical: true,
style: 'spacing: 20px;' });
scroll.add_actor(box);
function addTestCase(borders, useGradient) {
let background;
if (useGradient)
background = 'background-gradient-direction: vertical;'
+ 'background-gradient-start: white;'
+ 'background-gradient-end: gray;';
else
background = 'background: white;';
let border_style = "border-top: " + borders[St.Side.TOP] + " solid black;\n" +
"border-right: " + borders[St.Side.RIGHT] + " solid black;\n" +
"border-bottom: " + borders[St.Side.BOTTOM] + " solid black;\n" +
"border-left: " + borders[St.Side.LEFT] + " solid black;";
box.add(new St.Label({ text: border_style,
style: border_style
+ 'border-radius: 0px 5px 15px 25px;'
+ 'padding: 5px;' + background }),
{ x_fill: false });
}
// uniform backgrounds
addTestCase([" 0px", " 5px", "10px", "15px"], false);
addTestCase([" 5px", "10px", "15px", " 0px"], false);
addTestCase(["10px", "15px", " 0px", " 5px"], false);
addTestCase(["15px", " 0px", " 5px", "10px"], false);
// gradient backgrounds
addTestCase([" 0px", " 5px", "10px", "15px"], true);
addTestCase([" 5px", "10px", "15px", " 0px"], true);
addTestCase(["10px", "15px", " 0px", " 5px"], true);
addTestCase(["15px", " 0px", " 5px", "10px"], true);
stage.show();
Clutter.main();
stage.destroy();