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);
|
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
|
static void
|
||||||
st_theme_node_get_corner_border_widths (StThemeNode *node,
|
st_theme_node_get_corner_border_widths (StThemeNode *node,
|
||||||
StCorner corner_id,
|
StCorner corner_id,
|
||||||
@ -301,13 +352,15 @@ st_theme_node_lookup_corner (StThemeNode *node,
|
|||||||
StTextureCache *cache;
|
StTextureCache *cache;
|
||||||
StCornerSpec corner;
|
StCornerSpec corner;
|
||||||
LoadCornerData data;
|
LoadCornerData data;
|
||||||
|
guint radius[4];
|
||||||
|
|
||||||
if (node->border_radius[corner_id] == 0)
|
if (node->border_radius[corner_id] == 0)
|
||||||
return COGL_INVALID_HANDLE;
|
return COGL_INVALID_HANDLE;
|
||||||
|
|
||||||
cache = st_texture_cache_get_default ();
|
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;
|
corner.color = node->background_color;
|
||||||
st_theme_node_get_corner_border_widths (node, corner_id,
|
st_theme_node_get_corner_border_widths (node, corner_id,
|
||||||
&corner.border_width_1,
|
&corner.border_width_1,
|
||||||
@ -877,7 +930,8 @@ st_theme_node_prerender_background (StThemeNode *node)
|
|||||||
{
|
{
|
||||||
StBorderImage *border_image;
|
StBorderImage *border_image;
|
||||||
CoglHandle texture;
|
CoglHandle texture;
|
||||||
int radius[4], i;
|
guint radius[4];
|
||||||
|
int i;
|
||||||
cairo_t *cr;
|
cairo_t *cr;
|
||||||
cairo_surface_t *surface;
|
cairo_surface_t *surface;
|
||||||
StShadow *shadow_spec;
|
StShadow *shadow_spec;
|
||||||
@ -944,12 +998,10 @@ st_theme_node_prerender_background (StThemeNode *node)
|
|||||||
/* TODO - support non-uniform border colors */
|
/* TODO - support non-uniform border colors */
|
||||||
get_arbitrary_border_color (node, &border_color);
|
get_arbitrary_border_color (node, &border_color);
|
||||||
|
|
||||||
for (i = 0; i < 4; i++)
|
st_theme_node_reduce_border_radius (node, radius);
|
||||||
{
|
|
||||||
border_width[i] = st_theme_node_get_border_width (node, i);
|
|
||||||
|
|
||||||
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
|
/* Note we don't support translucent background images on top
|
||||||
* of gradients. It's strictly either/or.
|
* of gradients. It's strictly either/or.
|
||||||
@ -1457,6 +1509,7 @@ st_theme_node_paint_borders (StThemeNode *node,
|
|||||||
{
|
{
|
||||||
float width, height;
|
float width, height;
|
||||||
int border_width[4];
|
int border_width[4];
|
||||||
|
guint border_radius[4];
|
||||||
int max_border_radius = 0;
|
int max_border_radius = 0;
|
||||||
int max_width_radius[4];
|
int max_width_radius[4];
|
||||||
int corner_id, side_id;
|
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++)
|
for (side_id = 0; side_id < 4; side_id++)
|
||||||
border_width[side_id] = st_theme_node_get_border_width(node, 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++)
|
for (corner_id = 0; corner_id < 4; corner_id++)
|
||||||
{
|
{
|
||||||
guint border_width_1, border_width_2;
|
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,
|
st_theme_node_get_corner_border_widths (node, corner_id,
|
||||||
&border_width_1, &border_width_2);
|
&border_width_1, &border_width_2);
|
||||||
|
|
||||||
if (node->border_radius[corner_id] > max_border_radius)
|
if (border_radius[corner_id] > max_border_radius)
|
||||||
max_border_radius = node->border_radius[corner_id];
|
max_border_radius = border_radius[corner_id];
|
||||||
max_width_radius[corner_id] = MAX(MAX(border_width_1, border_width_2),
|
max_width_radius[corner_id] = MAX(MAX(border_width_1, border_width_2),
|
||||||
node->border_radius[corner_id]);
|
border_radius[corner_id]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* borders */
|
/* borders */
|
||||||
@ -1506,8 +1561,8 @@ st_theme_node_paint_borders (StThemeNode *node,
|
|||||||
alpha);
|
alpha);
|
||||||
|
|
||||||
/* NORTH */
|
/* NORTH */
|
||||||
skip_corner_1 = node->border_radius[ST_CORNER_TOPLEFT] > 0;
|
skip_corner_1 = border_radius[ST_CORNER_TOPLEFT] > 0;
|
||||||
skip_corner_2 = node->border_radius[ST_CORNER_TOPRIGHT] > 0;
|
skip_corner_2 = border_radius[ST_CORNER_TOPRIGHT] > 0;
|
||||||
|
|
||||||
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;
|
||||||
@ -1516,8 +1571,8 @@ st_theme_node_paint_borders (StThemeNode *node,
|
|||||||
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 = border_radius[ST_CORNER_TOPRIGHT] > 0;
|
||||||
skip_corner_2 = node->border_radius[ST_CORNER_BOTTOMRIGHT] > 0;
|
skip_corner_2 = border_radius[ST_CORNER_BOTTOMRIGHT] > 0;
|
||||||
|
|
||||||
x1 = width - border_width[ST_SIDE_RIGHT];
|
x1 = width - border_width[ST_SIDE_RIGHT];
|
||||||
y1 = skip_corner_1 ? max_width_radius[ST_CORNER_TOPRIGHT]
|
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);
|
cogl_rectangle (x1, y1, x2, y2);
|
||||||
|
|
||||||
/* SOUTH */
|
/* SOUTH */
|
||||||
skip_corner_1 = node->border_radius[ST_CORNER_BOTTOMLEFT] > 0;
|
skip_corner_1 = border_radius[ST_CORNER_BOTTOMLEFT] > 0;
|
||||||
skip_corner_2 = node->border_radius[ST_CORNER_BOTTOMRIGHT] > 0;
|
skip_corner_2 = 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[ST_SIDE_BOTTOM];
|
y1 = height - border_width[ST_SIDE_BOTTOM];
|
||||||
@ -1539,8 +1594,8 @@ st_theme_node_paint_borders (StThemeNode *node,
|
|||||||
cogl_rectangle (x1, y1, x2, y2);
|
cogl_rectangle (x1, y1, x2, y2);
|
||||||
|
|
||||||
/* WEST */
|
/* WEST */
|
||||||
skip_corner_1 = node->border_radius[ST_CORNER_TOPLEFT] > 0;
|
skip_corner_1 = border_radius[ST_CORNER_TOPLEFT] > 0;
|
||||||
skip_corner_2 = node->border_radius[ST_CORNER_BOTTOMLEFT] > 0;
|
skip_corner_2 = border_radius[ST_CORNER_BOTTOMLEFT] > 0;
|
||||||
|
|
||||||
x1 = 0;
|
x1 = 0;
|
||||||
y1 = skip_corner_1 ? max_width_radius[ST_CORNER_TOPLEFT]
|
y1 = skip_corner_1 ? max_width_radius[ST_CORNER_TOPLEFT]
|
||||||
@ -1610,32 +1665,32 @@ st_theme_node_paint_borders (StThemeNode *node,
|
|||||||
int n_rects;
|
int n_rects;
|
||||||
|
|
||||||
/* corner texture does not need padding */
|
/* corner texture does not need padding */
|
||||||
if (max_border_radius == node->border_radius[corner_id])
|
if (max_border_radius == border_radius[corner_id])
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
n_rects = node->border_radius[corner_id] == 0 ? 1 : 2;
|
n_rects = border_radius[corner_id] == 0 ? 1 : 2;
|
||||||
|
|
||||||
switch (corner_id)
|
switch (corner_id)
|
||||||
{
|
{
|
||||||
case ST_CORNER_TOPLEFT:
|
case ST_CORNER_TOPLEFT:
|
||||||
verts[0] = border_width[ST_SIDE_LEFT];
|
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]);
|
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(node->border_radius[corner_id],
|
verts[4] = MAX(border_radius[corner_id],
|
||||||
border_width[ST_SIDE_LEFT]);
|
border_width[ST_SIDE_LEFT]);
|
||||||
verts[5] = border_width[ST_SIDE_TOP];
|
verts[5] = border_width[ST_SIDE_TOP];
|
||||||
verts[6] = max_border_radius;
|
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]);
|
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(node->border_radius[corner_id],
|
verts[1] = MAX(border_radius[corner_id],
|
||||||
border_width[ST_SIDE_TOP]);
|
border_width[ST_SIDE_TOP]);
|
||||||
verts[2] = width - border_width[ST_SIDE_RIGHT];
|
verts[2] = width - border_width[ST_SIDE_RIGHT];
|
||||||
verts[3] = max_border_radius;
|
verts[3] = max_border_radius;
|
||||||
@ -1643,9 +1698,9 @@ st_theme_node_paint_borders (StThemeNode *node,
|
|||||||
{
|
{
|
||||||
verts[4] = width - max_border_radius;
|
verts[4] = width - max_border_radius;
|
||||||
verts[5] = border_width[ST_SIDE_TOP];
|
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]);
|
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]);
|
border_width[ST_SIDE_TOP]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1653,14 +1708,14 @@ st_theme_node_paint_borders (StThemeNode *node,
|
|||||||
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[ST_SIDE_RIGHT];
|
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]);
|
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(node->border_radius[corner_id],
|
verts[5] = height - MAX(border_radius[corner_id],
|
||||||
border_width[ST_SIDE_BOTTOM]);
|
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]);
|
border_width[ST_SIDE_RIGHT]);
|
||||||
verts[7] = height - border_width[ST_SIDE_BOTTOM];
|
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[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(node->border_radius[corner_id],
|
verts[3] = height - MAX(border_radius[corner_id],
|
||||||
border_width[ST_SIDE_BOTTOM]);
|
border_width[ST_SIDE_BOTTOM]);
|
||||||
if (n_rects == 2)
|
if (n_rects == 2)
|
||||||
{
|
{
|
||||||
verts[4] = MAX(node->border_radius[corner_id],
|
verts[4] = MAX(border_radius[corner_id],
|
||||||
border_width[ST_SIDE_LEFT]);
|
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]);
|
border_width[ST_SIDE_BOTTOM]);
|
||||||
verts[6] = max_border_radius;
|
verts[6] = max_border_radius;
|
||||||
verts[7] = height - border_width[ST_SIDE_BOTTOM];
|
verts[7] = height - border_width[ST_SIDE_BOTTOM];
|
||||||
|
Loading…
x
Reference in New Issue
Block a user