St: Implement CSS3 specification for reducing border-radius
Currently, any cases of overlapping corners were just ignored and rendered incorrectly. Implement the corner overlap algorithm as specified by the W3C to fix this. https://bugzilla.gnome.org/show_bug.cgi?id=649513
This commit is contained in:
parent
153768ef7f
commit
ee4ae62946
@ -257,6 +257,57 @@ over (const ClutterColor *source,
|
||||
unpremultiply (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* st_theme_node_reduce_border_radius:
|
||||
* @node: a #StThemeNode
|
||||
* @corners: (array length=4) (out): reduced corners
|
||||
*
|
||||
* Implements the corner overlap algorithm mentioned at
|
||||
* http://www.w3.org/TR/css3-background/#corner-overlap
|
||||
*/
|
||||
static void
|
||||
st_theme_node_reduce_border_radius (StThemeNode *node,
|
||||
guint *corners)
|
||||
{
|
||||
gfloat scale;
|
||||
guint sum;
|
||||
|
||||
scale = 1.0;
|
||||
|
||||
/* top */
|
||||
sum = node->border_radius[ST_CORNER_TOPLEFT]
|
||||
+ node->border_radius[ST_CORNER_TOPRIGHT];
|
||||
|
||||
if (sum > 0)
|
||||
scale = MIN (node->alloc_width / sum, scale);
|
||||
|
||||
/* right */
|
||||
sum = node->border_radius[ST_CORNER_TOPRIGHT]
|
||||
+ node->border_radius[ST_CORNER_BOTTOMRIGHT];
|
||||
|
||||
if (sum > 0)
|
||||
scale = MIN (node->alloc_height / sum, scale);
|
||||
|
||||
/* bottom */
|
||||
sum = node->border_radius[ST_CORNER_BOTTOMLEFT]
|
||||
+ node->border_radius[ST_CORNER_BOTTOMRIGHT];
|
||||
|
||||
if (sum > 0)
|
||||
scale = MIN (node->alloc_width / sum, scale);
|
||||
|
||||
/* left */
|
||||
sum = node->border_radius[ST_CORNER_BOTTOMLEFT]
|
||||
+ node->border_radius[ST_CORNER_TOPLEFT];
|
||||
|
||||
if (sum > 0)
|
||||
scale = MIN (node->alloc_height / sum, scale);
|
||||
|
||||
corners[ST_CORNER_TOPLEFT] = node->border_radius[ST_CORNER_TOPLEFT] * scale;
|
||||
corners[ST_CORNER_TOPRIGHT] = node->border_radius[ST_CORNER_TOPRIGHT] * scale;
|
||||
corners[ST_CORNER_BOTTOMLEFT] = node->border_radius[ST_CORNER_BOTTOMLEFT] * scale;
|
||||
corners[ST_CORNER_BOTTOMRIGHT] = node->border_radius[ST_CORNER_BOTTOMRIGHT] * scale;
|
||||
}
|
||||
|
||||
static void
|
||||
st_theme_node_get_corner_border_widths (StThemeNode *node,
|
||||
StCorner corner_id,
|
||||
@ -301,13 +352,15 @@ st_theme_node_lookup_corner (StThemeNode *node,
|
||||
StTextureCache *cache;
|
||||
StCornerSpec corner;
|
||||
LoadCornerData data;
|
||||
guint radius[4];
|
||||
|
||||
if (node->border_radius[corner_id] == 0)
|
||||
return COGL_INVALID_HANDLE;
|
||||
|
||||
cache = st_texture_cache_get_default ();
|
||||
|
||||
corner.radius = node->border_radius[corner_id];
|
||||
st_theme_node_reduce_border_radius (node, radius);
|
||||
corner.radius = radius[corner_id];
|
||||
corner.color = node->background_color;
|
||||
st_theme_node_get_corner_border_widths (node, corner_id,
|
||||
&corner.border_width_1,
|
||||
@ -877,7 +930,8 @@ st_theme_node_prerender_background (StThemeNode *node)
|
||||
{
|
||||
StBorderImage *border_image;
|
||||
CoglHandle texture;
|
||||
int radius[4], i;
|
||||
guint radius[4];
|
||||
int i;
|
||||
cairo_t *cr;
|
||||
cairo_surface_t *surface;
|
||||
StShadow *shadow_spec;
|
||||
@ -944,12 +998,10 @@ st_theme_node_prerender_background (StThemeNode *node)
|
||||
/* TODO - support non-uniform border colors */
|
||||
get_arbitrary_border_color (node, &border_color);
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
border_width[i] = st_theme_node_get_border_width (node, i);
|
||||
st_theme_node_reduce_border_radius (node, radius);
|
||||
|
||||
radius[i] = st_theme_node_get_border_radius (node, i);
|
||||
}
|
||||
for (i = 0; i < 4; i++)
|
||||
border_width[i] = st_theme_node_get_border_width (node, i);
|
||||
|
||||
/* Note we don't support translucent background images on top
|
||||
* of gradients. It's strictly either/or.
|
||||
@ -1457,6 +1509,7 @@ st_theme_node_paint_borders (StThemeNode *node,
|
||||
{
|
||||
float width, height;
|
||||
int border_width[4];
|
||||
guint border_radius[4];
|
||||
int max_border_radius = 0;
|
||||
int max_width_radius[4];
|
||||
int corner_id, side_id;
|
||||
@ -1472,6 +1525,8 @@ st_theme_node_paint_borders (StThemeNode *node,
|
||||
for (side_id = 0; side_id < 4; side_id++)
|
||||
border_width[side_id] = st_theme_node_get_border_width(node, side_id);
|
||||
|
||||
st_theme_node_reduce_border_radius (node, border_radius);
|
||||
|
||||
for (corner_id = 0; corner_id < 4; corner_id++)
|
||||
{
|
||||
guint border_width_1, border_width_2;
|
||||
@ -1479,10 +1534,10 @@ st_theme_node_paint_borders (StThemeNode *node,
|
||||
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)
|
||||
max_border_radius = node->border_radius[corner_id];
|
||||
if (border_radius[corner_id] > max_border_radius)
|
||||
max_border_radius = border_radius[corner_id];
|
||||
max_width_radius[corner_id] = MAX(MAX(border_width_1, border_width_2),
|
||||
node->border_radius[corner_id]);
|
||||
border_radius[corner_id]);
|
||||
}
|
||||
|
||||
/* borders */
|
||||
@ -1506,8 +1561,8 @@ st_theme_node_paint_borders (StThemeNode *node,
|
||||
alpha);
|
||||
|
||||
/* NORTH */
|
||||
skip_corner_1 = node->border_radius[ST_CORNER_TOPLEFT] > 0;
|
||||
skip_corner_2 = node->border_radius[ST_CORNER_TOPRIGHT] > 0;
|
||||
skip_corner_1 = border_radius[ST_CORNER_TOPLEFT] > 0;
|
||||
skip_corner_2 = border_radius[ST_CORNER_TOPRIGHT] > 0;
|
||||
|
||||
x1 = skip_corner_1 ? max_width_radius[ST_CORNER_TOPLEFT] : 0;
|
||||
y1 = 0;
|
||||
@ -1516,8 +1571,8 @@ st_theme_node_paint_borders (StThemeNode *node,
|
||||
cogl_rectangle (x1, y1, x2, y2);
|
||||
|
||||
/* EAST */
|
||||
skip_corner_1 = node->border_radius[ST_CORNER_TOPRIGHT] > 0;
|
||||
skip_corner_2 = node->border_radius[ST_CORNER_BOTTOMRIGHT] > 0;
|
||||
skip_corner_1 = border_radius[ST_CORNER_TOPRIGHT] > 0;
|
||||
skip_corner_2 = border_radius[ST_CORNER_BOTTOMRIGHT] > 0;
|
||||
|
||||
x1 = width - border_width[ST_SIDE_RIGHT];
|
||||
y1 = skip_corner_1 ? max_width_radius[ST_CORNER_TOPRIGHT]
|
||||
@ -1528,8 +1583,8 @@ st_theme_node_paint_borders (StThemeNode *node,
|
||||
cogl_rectangle (x1, y1, x2, y2);
|
||||
|
||||
/* SOUTH */
|
||||
skip_corner_1 = node->border_radius[ST_CORNER_BOTTOMLEFT] > 0;
|
||||
skip_corner_2 = node->border_radius[ST_CORNER_BOTTOMRIGHT] > 0;
|
||||
skip_corner_1 = border_radius[ST_CORNER_BOTTOMLEFT] > 0;
|
||||
skip_corner_2 = border_radius[ST_CORNER_BOTTOMRIGHT] > 0;
|
||||
|
||||
x1 = skip_corner_1 ? max_width_radius[ST_CORNER_BOTTOMLEFT] : 0;
|
||||
y1 = height - border_width[ST_SIDE_BOTTOM];
|
||||
@ -1539,8 +1594,8 @@ st_theme_node_paint_borders (StThemeNode *node,
|
||||
cogl_rectangle (x1, y1, x2, y2);
|
||||
|
||||
/* WEST */
|
||||
skip_corner_1 = node->border_radius[ST_CORNER_TOPLEFT] > 0;
|
||||
skip_corner_2 = node->border_radius[ST_CORNER_BOTTOMLEFT] > 0;
|
||||
skip_corner_1 = border_radius[ST_CORNER_TOPLEFT] > 0;
|
||||
skip_corner_2 = border_radius[ST_CORNER_BOTTOMLEFT] > 0;
|
||||
|
||||
x1 = 0;
|
||||
y1 = skip_corner_1 ? max_width_radius[ST_CORNER_TOPLEFT]
|
||||
@ -1610,32 +1665,32 @@ st_theme_node_paint_borders (StThemeNode *node,
|
||||
int n_rects;
|
||||
|
||||
/* corner texture does not need padding */
|
||||
if (max_border_radius == node->border_radius[corner_id])
|
||||
if (max_border_radius == border_radius[corner_id])
|
||||
continue;
|
||||
|
||||
n_rects = node->border_radius[corner_id] == 0 ? 1 : 2;
|
||||
n_rects = border_radius[corner_id] == 0 ? 1 : 2;
|
||||
|
||||
switch (corner_id)
|
||||
{
|
||||
case ST_CORNER_TOPLEFT:
|
||||
verts[0] = border_width[ST_SIDE_LEFT];
|
||||
verts[1] = MAX(node->border_radius[corner_id],
|
||||
verts[1] = MAX(border_radius[corner_id],
|
||||
border_width[ST_SIDE_TOP]);
|
||||
verts[2] = max_border_radius;
|
||||
verts[3] = max_border_radius;
|
||||
if (n_rects == 2)
|
||||
{
|
||||
verts[4] = MAX(node->border_radius[corner_id],
|
||||
verts[4] = MAX(border_radius[corner_id],
|
||||
border_width[ST_SIDE_LEFT]);
|
||||
verts[5] = border_width[ST_SIDE_TOP];
|
||||
verts[6] = max_border_radius;
|
||||
verts[7] = MAX(node->border_radius[corner_id],
|
||||
verts[7] = MAX(border_radius[corner_id],
|
||||
border_width[ST_SIDE_TOP]);
|
||||
}
|
||||
break;
|
||||
case ST_CORNER_TOPRIGHT:
|
||||
verts[0] = width - max_border_radius;
|
||||
verts[1] = MAX(node->border_radius[corner_id],
|
||||
verts[1] = MAX(border_radius[corner_id],
|
||||
border_width[ST_SIDE_TOP]);
|
||||
verts[2] = width - border_width[ST_SIDE_RIGHT];
|
||||
verts[3] = max_border_radius;
|
||||
@ -1643,9 +1698,9 @@ st_theme_node_paint_borders (StThemeNode *node,
|
||||
{
|
||||
verts[4] = width - max_border_radius;
|
||||
verts[5] = border_width[ST_SIDE_TOP];
|
||||
verts[6] = width - MAX(node->border_radius[corner_id],
|
||||
verts[6] = width - MAX(border_radius[corner_id],
|
||||
border_width[ST_SIDE_RIGHT]);
|
||||
verts[7] = MAX(node->border_radius[corner_id],
|
||||
verts[7] = MAX(border_radius[corner_id],
|
||||
border_width[ST_SIDE_TOP]);
|
||||
}
|
||||
break;
|
||||
@ -1653,14 +1708,14 @@ st_theme_node_paint_borders (StThemeNode *node,
|
||||
verts[0] = width - max_border_radius;
|
||||
verts[1] = height - max_border_radius;
|
||||
verts[2] = width - border_width[ST_SIDE_RIGHT];
|
||||
verts[3] = height - MAX(node->border_radius[corner_id],
|
||||
verts[3] = height - MAX(border_radius[corner_id],
|
||||
border_width[ST_SIDE_BOTTOM]);
|
||||
if (n_rects == 2)
|
||||
{
|
||||
verts[4] = width - max_border_radius;
|
||||
verts[5] = height - MAX(node->border_radius[corner_id],
|
||||
verts[5] = height - MAX(border_radius[corner_id],
|
||||
border_width[ST_SIDE_BOTTOM]);
|
||||
verts[6] = width - MAX(node->border_radius[corner_id],
|
||||
verts[6] = width - MAX(border_radius[corner_id],
|
||||
border_width[ST_SIDE_RIGHT]);
|
||||
verts[7] = height - border_width[ST_SIDE_BOTTOM];
|
||||
}
|
||||
@ -1669,13 +1724,13 @@ st_theme_node_paint_borders (StThemeNode *node,
|
||||
verts[0] = border_width[ST_SIDE_LEFT];
|
||||
verts[1] = height - max_border_radius;
|
||||
verts[2] = max_border_radius;
|
||||
verts[3] = height - MAX(node->border_radius[corner_id],
|
||||
verts[3] = height - MAX(border_radius[corner_id],
|
||||
border_width[ST_SIDE_BOTTOM]);
|
||||
if (n_rects == 2)
|
||||
{
|
||||
verts[4] = MAX(node->border_radius[corner_id],
|
||||
verts[4] = MAX(border_radius[corner_id],
|
||||
border_width[ST_SIDE_LEFT]);
|
||||
verts[5] = height - MAX(node->border_radius[corner_id],
|
||||
verts[5] = height - MAX(border_radius[corner_id],
|
||||
border_width[ST_SIDE_BOTTOM]);
|
||||
verts[6] = max_border_radius;
|
||||
verts[7] = height - border_width[ST_SIDE_BOTTOM];
|
||||
|
Loading…
Reference in New Issue
Block a user