st: optimize box-shadow rendering
Currently the box-shadow is rendering is done like this : The first time we want to render a node that requires a box-shadow, St creates an cogl offscreen surface of the size of the allocation and renders the box into this offscreen buffer using modulation on the alpha channel, this buffer is then blurred according to the CSS parameters. The problem with this method is that every time an StWidget is resized, its box-shadow offscreen buffer has to be resized and therefore rendered and blurred. This patches propose an optimization for this use case by rendering the box-shadow only once but at a size that is independent of the StWidget's size. Then every time we need to paint this box-shadow, we just render this offscreen buffer using a 9-slices. This method only works when the allocation of the widget is bigger than the minimum shadow size on which we can apply a 9-slices, that is given my the radius of the corners. If the allocation is smaller than this minimum size, we then fallback to the fully render/blur the shadow (like before this patch). https://bugzilla.gnome.org/show_bug.cgi?id=689858
This commit is contained in:
parent
3582ba0c77
commit
318283fc70
@ -1370,6 +1370,8 @@ st_theme_node_load_background_image (StThemeNode *node)
|
|||||||
return node->background_texture != COGL_INVALID_HANDLE;
|
return node->background_texture != COGL_INVALID_HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void st_theme_node_prerender_shadow (StThemeNode *node, StThemeNodePaintState *state);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
st_theme_node_render_resources (StThemeNode *node,
|
st_theme_node_render_resources (StThemeNode *node,
|
||||||
StThemeNodePaintState *state,
|
StThemeNodePaintState *state,
|
||||||
@ -1474,38 +1476,54 @@ st_theme_node_render_resources (StThemeNode *node,
|
|||||||
state->box_shadow_material = _st_create_shadow_material (box_shadow_spec,
|
state->box_shadow_material = _st_create_shadow_material (box_shadow_spec,
|
||||||
state->prerendered_texture);
|
state->prerendered_texture);
|
||||||
else if (node->background_color.alpha > 0 || has_border)
|
else if (node->background_color.alpha > 0 || has_border)
|
||||||
|
st_theme_node_prerender_shadow (node, state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
st_theme_node_update_resources (StThemeNode *node, StThemeNodePaintState *state, float width, float height)
|
||||||
{
|
{
|
||||||
CoglHandle buffer, offscreen;
|
gboolean had_prerendered_texture = FALSE;
|
||||||
int texture_width = ceil (width);
|
gboolean had_box_shadow = FALSE;
|
||||||
int texture_height = ceil (height);
|
StShadow *box_shadow_spec;
|
||||||
|
|
||||||
buffer = cogl_texture_new_with_size (texture_width,
|
g_return_if_fail (width > 0 && height > 0);
|
||||||
texture_height,
|
|
||||||
COGL_TEXTURE_NO_SLICING,
|
|
||||||
COGL_PIXEL_FORMAT_ANY);
|
|
||||||
offscreen = cogl_offscreen_new_to_texture (buffer);
|
|
||||||
|
|
||||||
if (offscreen != COGL_INVALID_HANDLE)
|
/* Free handles we can't reuse */
|
||||||
|
if (state->prerendered_texture != COGL_INVALID_HANDLE)
|
||||||
{
|
{
|
||||||
ClutterActorBox box = { 0, 0, width, height };
|
cogl_handle_unref (state->prerendered_texture);
|
||||||
CoglColor clear_color;
|
state->prerendered_texture = COGL_INVALID_HANDLE;
|
||||||
|
had_prerendered_texture = TRUE;
|
||||||
|
}
|
||||||
|
if (state->prerendered_material != COGL_INVALID_HANDLE)
|
||||||
|
{
|
||||||
|
cogl_handle_unref (state->prerendered_material);
|
||||||
|
state->prerendered_material = COGL_INVALID_HANDLE;
|
||||||
|
|
||||||
cogl_push_framebuffer (offscreen);
|
if (node->border_slices_texture == COGL_INVALID_HANDLE &&
|
||||||
cogl_ortho (0, width, height, 0, 0, 1.0);
|
state->box_shadow_material != COGL_INVALID_HANDLE)
|
||||||
|
{
|
||||||
|
cogl_handle_unref (state->box_shadow_material);
|
||||||
|
state->box_shadow_material = COGL_INVALID_HANDLE;
|
||||||
|
had_box_shadow = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cogl_color_set_from_4ub (&clear_color, 0, 0, 0, 0);
|
state->alloc_width = width;
|
||||||
cogl_clear (&clear_color, COGL_BUFFER_BIT_COLOR);
|
state->alloc_height = height;
|
||||||
|
|
||||||
st_theme_node_paint_borders (node, state, &box, 0xFF);
|
box_shadow_spec = st_theme_node_get_box_shadow (node);
|
||||||
cogl_pop_framebuffer ();
|
|
||||||
cogl_handle_unref (offscreen);
|
|
||||||
|
|
||||||
|
if (had_prerendered_texture)
|
||||||
|
{
|
||||||
|
state->prerendered_texture = st_theme_node_prerender_background (node, width, height);
|
||||||
|
state->prerendered_material = _st_create_texture_material (state->prerendered_texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (had_box_shadow)
|
||||||
state->box_shadow_material = _st_create_shadow_material (box_shadow_spec,
|
state->box_shadow_material = _st_create_shadow_material (box_shadow_spec,
|
||||||
buffer);
|
state->prerendered_texture);
|
||||||
}
|
|
||||||
cogl_handle_unref (buffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -1792,6 +1810,352 @@ st_theme_node_paint_borders (StThemeNode *node,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
st_theme_node_paint_sliced_shadow (StThemeNode *node,
|
||||||
|
StThemeNodePaintState *state,
|
||||||
|
const ClutterActorBox *box,
|
||||||
|
guint8 paint_opacity)
|
||||||
|
{
|
||||||
|
guint border_radius[4];
|
||||||
|
CoglColor color;
|
||||||
|
StShadow *box_shadow_spec;
|
||||||
|
gfloat xoffset, yoffset;
|
||||||
|
gfloat width, height;
|
||||||
|
gfloat shadow_width, shadow_height;
|
||||||
|
gfloat xend, yend, top, bottom, left, right;
|
||||||
|
gfloat s_top, s_bottom, s_left, s_right;
|
||||||
|
gfloat shadow_blur_radius, x_spread_factor, y_spread_factor;
|
||||||
|
float rectangles[8 * 9];
|
||||||
|
gint idx;
|
||||||
|
|
||||||
|
if (paint_opacity == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
st_theme_node_reduce_border_radius (node, box->x2 - box->x1, box->y2 - box->y1, border_radius);
|
||||||
|
|
||||||
|
box_shadow_spec = st_theme_node_get_box_shadow (node);
|
||||||
|
|
||||||
|
/* Compute input & output areas :
|
||||||
|
*
|
||||||
|
* yoffset ----------------------------
|
||||||
|
* | | | |
|
||||||
|
* | | | |
|
||||||
|
* | | | |
|
||||||
|
* top ----------------------------
|
||||||
|
* | | | |
|
||||||
|
* | | | |
|
||||||
|
* | | | |
|
||||||
|
* bottom ----------------------------
|
||||||
|
* | | | |
|
||||||
|
* | | | |
|
||||||
|
* | | | |
|
||||||
|
* yend ----------------------------
|
||||||
|
* xoffset left right xend
|
||||||
|
*
|
||||||
|
* s_top = top in offscreen's coordinates (0.0 - 1.0)
|
||||||
|
* s_bottom = bottom in offscreen's coordinates (0.0 - 1.0)
|
||||||
|
* s_left = left in offscreen's coordinates (0.0 - 1.0)
|
||||||
|
* s_right = right in offscreen's coordinates (0.0 - 1.0)
|
||||||
|
*/
|
||||||
|
if (box_shadow_spec->blur == 0)
|
||||||
|
shadow_blur_radius = 0;
|
||||||
|
else
|
||||||
|
shadow_blur_radius = (5 * (box_shadow_spec->blur / 2.0)) / 2;
|
||||||
|
|
||||||
|
shadow_width = state->box_shadow_width + 2 * shadow_blur_radius;
|
||||||
|
shadow_height = state->box_shadow_height + 2 * shadow_blur_radius;
|
||||||
|
|
||||||
|
/* Compute input regions parameters */
|
||||||
|
s_top = shadow_blur_radius + box_shadow_spec->blur +
|
||||||
|
MAX (node->border_radius[ST_CORNER_TOPLEFT],
|
||||||
|
node->border_radius[ST_CORNER_TOPRIGHT]);
|
||||||
|
s_bottom = shadow_blur_radius + box_shadow_spec->blur +
|
||||||
|
MAX (node->border_radius[ST_CORNER_BOTTOMLEFT],
|
||||||
|
node->border_radius[ST_CORNER_BOTTOMRIGHT]);
|
||||||
|
s_left = shadow_blur_radius + box_shadow_spec->blur +
|
||||||
|
MAX (node->border_radius[ST_CORNER_TOPLEFT],
|
||||||
|
node->border_radius[ST_CORNER_BOTTOMLEFT]);
|
||||||
|
s_right = shadow_blur_radius + box_shadow_spec->blur +
|
||||||
|
MAX (node->border_radius[ST_CORNER_TOPRIGHT],
|
||||||
|
node->border_radius[ST_CORNER_BOTTOMRIGHT]);
|
||||||
|
|
||||||
|
/* Compute output regions parameters */
|
||||||
|
xoffset = box->x1 + box_shadow_spec->xoffset - shadow_blur_radius - box_shadow_spec->spread;
|
||||||
|
yoffset = box->y1 + box_shadow_spec->yoffset - shadow_blur_radius - box_shadow_spec->spread;
|
||||||
|
width = box->x2 - box->x1 + 2 * shadow_blur_radius;
|
||||||
|
height = box->y2 - box->y1 + 2 * shadow_blur_radius;
|
||||||
|
|
||||||
|
x_spread_factor = (width + 2 * box_shadow_spec->spread) / width;
|
||||||
|
y_spread_factor = (height + 2 * box_shadow_spec->spread) / height;
|
||||||
|
|
||||||
|
width += 2 * box_shadow_spec->spread;
|
||||||
|
height += 2 * box_shadow_spec->spread;
|
||||||
|
|
||||||
|
xend = xoffset + width;
|
||||||
|
yend = yoffset + height;
|
||||||
|
|
||||||
|
top = s_top * y_spread_factor;
|
||||||
|
bottom = s_bottom * y_spread_factor;
|
||||||
|
left = s_left * x_spread_factor;
|
||||||
|
right = s_right * x_spread_factor;
|
||||||
|
|
||||||
|
bottom = height - bottom;
|
||||||
|
right = width - right;
|
||||||
|
|
||||||
|
/* Final adjustments */
|
||||||
|
s_top /= shadow_height;
|
||||||
|
s_bottom /= shadow_height;
|
||||||
|
s_left /= shadow_width;
|
||||||
|
s_right /= shadow_width;
|
||||||
|
|
||||||
|
s_bottom = 1.0 - s_bottom;
|
||||||
|
s_right = 1.0 - s_right;
|
||||||
|
|
||||||
|
top += yoffset;
|
||||||
|
bottom += yoffset;
|
||||||
|
left += xoffset;
|
||||||
|
right += xoffset;
|
||||||
|
|
||||||
|
/* Setup pipeline */
|
||||||
|
cogl_color_set_from_4ub (&color,
|
||||||
|
box_shadow_spec->color.red * paint_opacity / 255,
|
||||||
|
box_shadow_spec->color.green * paint_opacity / 255,
|
||||||
|
box_shadow_spec->color.blue * paint_opacity / 255,
|
||||||
|
box_shadow_spec->color.alpha * paint_opacity / 255);
|
||||||
|
cogl_color_premultiply (&color);
|
||||||
|
|
||||||
|
cogl_material_set_layer_combine_constant (state->box_shadow_material, 0, &color);
|
||||||
|
|
||||||
|
cogl_set_source (state->box_shadow_material);
|
||||||
|
|
||||||
|
idx = 0;
|
||||||
|
|
||||||
|
if (top > 0)
|
||||||
|
{
|
||||||
|
if (left > 0)
|
||||||
|
{
|
||||||
|
/* Top left corner */
|
||||||
|
rectangles[idx++] = xoffset;
|
||||||
|
rectangles[idx++] = yoffset;
|
||||||
|
rectangles[idx++] = left;
|
||||||
|
rectangles[idx++] = top;
|
||||||
|
|
||||||
|
rectangles[idx++] = 0;
|
||||||
|
rectangles[idx++] = 0;
|
||||||
|
rectangles[idx++] = s_left;
|
||||||
|
rectangles[idx++] = s_top;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Top middle */
|
||||||
|
rectangles[idx++] = left;
|
||||||
|
rectangles[idx++] = yoffset;
|
||||||
|
rectangles[idx++] = right;
|
||||||
|
rectangles[idx++] = top;
|
||||||
|
|
||||||
|
rectangles[idx++] = s_left;
|
||||||
|
rectangles[idx++] = 0;
|
||||||
|
rectangles[idx++] = s_right;
|
||||||
|
rectangles[idx++] = s_top;
|
||||||
|
|
||||||
|
if (right > 0)
|
||||||
|
{
|
||||||
|
/* Top right corner */
|
||||||
|
rectangles[idx++] = right;
|
||||||
|
rectangles[idx++] = yoffset;
|
||||||
|
rectangles[idx++] = xend;
|
||||||
|
rectangles[idx++] = top;
|
||||||
|
|
||||||
|
rectangles[idx++] = s_right;
|
||||||
|
rectangles[idx++] = 0;
|
||||||
|
rectangles[idx++] = 1;
|
||||||
|
rectangles[idx++] = s_top;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left > 0)
|
||||||
|
{
|
||||||
|
/* Left middle */
|
||||||
|
rectangles[idx++] = xoffset;
|
||||||
|
rectangles[idx++] = top;
|
||||||
|
rectangles[idx++] = left;
|
||||||
|
rectangles[idx++] = bottom;
|
||||||
|
|
||||||
|
rectangles[idx++] = 0;
|
||||||
|
rectangles[idx++] = s_top;
|
||||||
|
rectangles[idx++] = s_left;
|
||||||
|
rectangles[idx++] = s_bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Center middle */
|
||||||
|
rectangles[idx++] = left;
|
||||||
|
rectangles[idx++] = top;
|
||||||
|
rectangles[idx++] = right;
|
||||||
|
rectangles[idx++] = bottom;
|
||||||
|
|
||||||
|
rectangles[idx++] = s_left;
|
||||||
|
rectangles[idx++] = s_top;
|
||||||
|
rectangles[idx++] = s_right;
|
||||||
|
rectangles[idx++] = s_bottom;
|
||||||
|
|
||||||
|
|
||||||
|
if (right > 0)
|
||||||
|
{
|
||||||
|
/* Right middle */
|
||||||
|
rectangles[idx++] = right;
|
||||||
|
rectangles[idx++] = top;
|
||||||
|
rectangles[idx++] = xend;
|
||||||
|
rectangles[idx++] = bottom;
|
||||||
|
|
||||||
|
rectangles[idx++] = s_right;
|
||||||
|
rectangles[idx++] = s_top;
|
||||||
|
rectangles[idx++] = 1;
|
||||||
|
rectangles[idx++] = s_bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bottom > 0)
|
||||||
|
{
|
||||||
|
if (left > 0)
|
||||||
|
{
|
||||||
|
/* Bottom left corner */
|
||||||
|
rectangles[idx++] = xoffset;
|
||||||
|
rectangles[idx++] = bottom;
|
||||||
|
rectangles[idx++] = left;
|
||||||
|
rectangles[idx++] = yend;
|
||||||
|
|
||||||
|
rectangles[idx++] = 0;
|
||||||
|
rectangles[idx++] = s_bottom;
|
||||||
|
rectangles[idx++] = s_left;
|
||||||
|
rectangles[idx++] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Bottom middle */
|
||||||
|
rectangles[idx++] = left;
|
||||||
|
rectangles[idx++] = bottom;
|
||||||
|
rectangles[idx++] = right;
|
||||||
|
rectangles[idx++] = yend;
|
||||||
|
|
||||||
|
rectangles[idx++] = s_left;
|
||||||
|
rectangles[idx++] = s_bottom;
|
||||||
|
rectangles[idx++] = s_right;
|
||||||
|
rectangles[idx++] = 1;
|
||||||
|
|
||||||
|
if (right > 0)
|
||||||
|
{
|
||||||
|
/* Bottom right corner */
|
||||||
|
rectangles[idx++] = right;
|
||||||
|
rectangles[idx++] = bottom;
|
||||||
|
rectangles[idx++] = xend;
|
||||||
|
rectangles[idx++] = yend;
|
||||||
|
|
||||||
|
rectangles[idx++] = s_right;
|
||||||
|
rectangles[idx++] = s_bottom;
|
||||||
|
rectangles[idx++] = 1;
|
||||||
|
rectangles[idx++] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cogl_rectangles_with_texture_coords (rectangles, idx / 8);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/* Visual feedback on shadow's 9-slice and orignal offscreen buffer,
|
||||||
|
for debug purposes */
|
||||||
|
cogl_rectangle (xend, yoffset, xend + shadow_width, yoffset + shadow_height);
|
||||||
|
|
||||||
|
cogl_set_source_color4ub (0xff, 0x0, 0x0, 0xff);
|
||||||
|
|
||||||
|
cogl_rectangle (xoffset, top, xend, top + 1);
|
||||||
|
cogl_rectangle (xoffset, bottom, xend, bottom + 1);
|
||||||
|
cogl_rectangle (left, yoffset, left + 1, yend);
|
||||||
|
cogl_rectangle (right, yoffset, right + 1, yend);
|
||||||
|
|
||||||
|
cogl_rectangle (xend, yoffset, xend + shadow_width, yoffset + 1);
|
||||||
|
cogl_rectangle (xend, yoffset + shadow_height, xend + shadow_width, yoffset + shadow_height + 1);
|
||||||
|
cogl_rectangle (xend, yoffset, xend + 1, yoffset + shadow_height);
|
||||||
|
cogl_rectangle (xend + shadow_width, yoffset, xend + shadow_width + 1, yoffset + shadow_height);
|
||||||
|
|
||||||
|
s_top *= shadow_height;
|
||||||
|
s_bottom *= shadow_height;
|
||||||
|
s_left *= shadow_width;
|
||||||
|
s_right *= shadow_width;
|
||||||
|
|
||||||
|
cogl_rectangle (xend, yoffset + s_top, xend + shadow_width, yoffset + s_top + 1);
|
||||||
|
cogl_rectangle (xend, yoffset + s_bottom, xend + shadow_width, yoffset + s_bottom + 1);
|
||||||
|
cogl_rectangle (xend + s_left, yoffset, xend + s_left + 1, yoffset + shadow_height);
|
||||||
|
cogl_rectangle (xend + s_right, yoffset, xend + s_right + 1, yoffset + shadow_height);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
st_theme_node_prerender_shadow (StThemeNode *node, StThemeNodePaintState *state)
|
||||||
|
{
|
||||||
|
guint border_radius[4];
|
||||||
|
int max_borders[4];
|
||||||
|
int center_radius, corner_id;
|
||||||
|
CoglHandle buffer, offscreen;
|
||||||
|
|
||||||
|
/* Get infos from the node */
|
||||||
|
if (state->alloc_width < node->box_shadow_min_width ||
|
||||||
|
state->alloc_height < node->box_shadow_min_height)
|
||||||
|
st_theme_node_reduce_border_radius (node, state->alloc_width, state->alloc_height, border_radius);
|
||||||
|
else
|
||||||
|
for (corner_id = 0; corner_id < 4; corner_id++)
|
||||||
|
border_radius[corner_id] = node->border_radius[corner_id];
|
||||||
|
|
||||||
|
/* Compute maximum borders sizes */
|
||||||
|
max_borders[ST_SIDE_TOP] = MAX (node->border_radius[ST_CORNER_TOPLEFT],
|
||||||
|
node->border_radius[ST_CORNER_TOPRIGHT]);
|
||||||
|
max_borders[ST_SIDE_BOTTOM] = MAX (node->border_radius[ST_CORNER_BOTTOMLEFT],
|
||||||
|
node->border_radius[ST_CORNER_BOTTOMRIGHT]);
|
||||||
|
max_borders[ST_SIDE_LEFT] = MAX (node->border_radius[ST_CORNER_TOPLEFT],
|
||||||
|
node->border_radius[ST_CORNER_BOTTOMLEFT]);
|
||||||
|
max_borders[ST_SIDE_RIGHT] = MAX (node->border_radius[ST_CORNER_TOPRIGHT],
|
||||||
|
node->border_radius[ST_CORNER_BOTTOMRIGHT]);
|
||||||
|
|
||||||
|
center_radius = (node->box_shadow->blur > 0) ? (2 * node->box_shadow->blur + 1) : 1;
|
||||||
|
node->box_shadow_min_width = max_borders[ST_SIDE_LEFT] + max_borders[ST_SIDE_RIGHT] + center_radius;
|
||||||
|
node->box_shadow_min_height = max_borders[ST_SIDE_TOP] + max_borders[ST_SIDE_BOTTOM] + center_radius;
|
||||||
|
|
||||||
|
if (state->alloc_width < node->box_shadow_min_width ||
|
||||||
|
state->alloc_height < node->box_shadow_min_height)
|
||||||
|
{
|
||||||
|
state->box_shadow_width = state->alloc_width;
|
||||||
|
state->box_shadow_height = state->alloc_height;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
state->box_shadow_width = node->box_shadow_min_width;
|
||||||
|
state->box_shadow_height = node->box_shadow_min_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Render offscreen */
|
||||||
|
buffer = cogl_texture_new_with_size (state->box_shadow_width,
|
||||||
|
state->box_shadow_height,
|
||||||
|
COGL_TEXTURE_NO_SLICING,
|
||||||
|
COGL_PIXEL_FORMAT_ANY);
|
||||||
|
offscreen = cogl_offscreen_new_to_texture (buffer);
|
||||||
|
|
||||||
|
if (offscreen != COGL_INVALID_HANDLE)
|
||||||
|
{
|
||||||
|
ClutterActorBox box = { 0, 0, state->box_shadow_width, state->box_shadow_height};
|
||||||
|
CoglColor clear_color;
|
||||||
|
|
||||||
|
cogl_push_framebuffer (offscreen);
|
||||||
|
cogl_ortho (0, state->box_shadow_width, state->box_shadow_height, 0, 0, 1.0);
|
||||||
|
|
||||||
|
cogl_color_set_from_4ub (&clear_color, 0, 0, 0, 0);
|
||||||
|
cogl_clear (&clear_color, COGL_BUFFER_BIT_COLOR);
|
||||||
|
|
||||||
|
st_theme_node_paint_borders (node, state, &box, 0xFF);
|
||||||
|
cogl_pop_framebuffer ();
|
||||||
|
cogl_handle_unref (offscreen);
|
||||||
|
|
||||||
|
state->box_shadow_material = _st_create_shadow_material (st_theme_node_get_box_shadow (node),
|
||||||
|
buffer);
|
||||||
|
}
|
||||||
|
cogl_handle_unref (buffer);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
st_theme_node_paint_sliced_border_image (StThemeNode *node,
|
st_theme_node_paint_sliced_border_image (StThemeNode *node,
|
||||||
float width,
|
float width,
|
||||||
@ -1945,6 +2309,43 @@ st_theme_node_paint_outline (StThemeNode *node,
|
|||||||
cogl_rectangles (rects, 4);
|
cogl_rectangles (rects, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
st_theme_node_needs_new_box_shadow_for_size (StThemeNode *node,
|
||||||
|
StThemeNodePaintState *state,
|
||||||
|
float width,
|
||||||
|
float height)
|
||||||
|
{
|
||||||
|
if (!node->rendered_once)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
/* The allocation hasn't changed, no need to recompute a new
|
||||||
|
box-shadow. */
|
||||||
|
if (state->alloc_width == width ||
|
||||||
|
state->alloc_height == height)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* If there is no shadow, no need to recompute a new box-shadow. */
|
||||||
|
if (node->box_shadow_min_width == 0 ||
|
||||||
|
node->box_shadow_min_height == 0)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* If the new size is inferior to the box-shadow minimum size (we
|
||||||
|
already know the size has changed), we need to recompute the
|
||||||
|
box-shadow. */
|
||||||
|
if (width < node->box_shadow_min_width ||
|
||||||
|
height < node->box_shadow_min_height)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
/* Now checking whether the size of the node has crossed the minimum
|
||||||
|
box-shadow size boundary, from below to above the minimum size .
|
||||||
|
If that's the case, we need to recompute the box-shadow */
|
||||||
|
if (state->alloc_width < node->box_shadow_min_width ||
|
||||||
|
state->alloc_height < node->box_shadow_min_height)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
st_theme_node_paint (StThemeNode *node,
|
st_theme_node_paint (StThemeNode *node,
|
||||||
StThemeNodePaintState *state,
|
StThemeNodePaintState *state,
|
||||||
@ -1964,11 +2365,13 @@ st_theme_node_paint (StThemeNode *node,
|
|||||||
if (width <= 0 || height <= 0)
|
if (width <= 0 || height <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (state->alloc_width != width || state->alloc_height != height)
|
|
||||||
{
|
|
||||||
state->node = node;
|
state->node = node;
|
||||||
|
if (st_theme_node_needs_new_box_shadow_for_size (node, state, width, height))
|
||||||
st_theme_node_render_resources (node, state, width, height);
|
st_theme_node_render_resources (node, state, width, height);
|
||||||
}
|
else
|
||||||
|
st_theme_node_update_resources (node, state, width, height);
|
||||||
|
|
||||||
|
node->rendered_once = TRUE;
|
||||||
|
|
||||||
/* Rough notes about the relationship of borders and backgrounds in CSS3;
|
/* Rough notes about the relationship of borders and backgrounds in CSS3;
|
||||||
* see http://www.w3.org/TR/css3-background/ for more accurate details.
|
* see http://www.w3.org/TR/css3-background/ for more accurate details.
|
||||||
@ -1997,10 +2400,19 @@ st_theme_node_paint (StThemeNode *node,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
if (state->box_shadow_material)
|
if (state->box_shadow_material)
|
||||||
|
{
|
||||||
|
if (state->alloc_width < node->box_shadow_min_width ||
|
||||||
|
state->alloc_height < node->box_shadow_min_height)
|
||||||
_st_paint_shadow_with_opacity (node->box_shadow,
|
_st_paint_shadow_with_opacity (node->box_shadow,
|
||||||
state->box_shadow_material,
|
state->box_shadow_material,
|
||||||
&allocation,
|
&allocation,
|
||||||
paint_opacity);
|
paint_opacity);
|
||||||
|
else
|
||||||
|
st_theme_node_paint_sliced_shadow (node,
|
||||||
|
state,
|
||||||
|
&allocation,
|
||||||
|
paint_opacity);
|
||||||
|
}
|
||||||
|
|
||||||
if (state->prerendered_material != COGL_INVALID_HANDLE ||
|
if (state->prerendered_material != COGL_INVALID_HANDLE ||
|
||||||
st_theme_node_load_border_image (node))
|
st_theme_node_load_border_image (node))
|
||||||
@ -2124,6 +2536,8 @@ st_theme_node_paint_state_copy (StThemeNodePaintState *state,
|
|||||||
|
|
||||||
state->alloc_width = other->alloc_width;
|
state->alloc_width = other->alloc_width;
|
||||||
state->alloc_height = other->alloc_height;
|
state->alloc_height = other->alloc_height;
|
||||||
|
state->box_shadow_width = other->box_shadow_width;
|
||||||
|
state->box_shadow_height = other->box_shadow_height;
|
||||||
|
|
||||||
if (other->box_shadow_material)
|
if (other->box_shadow_material)
|
||||||
state->box_shadow_material = cogl_handle_ref (other->box_shadow_material);
|
state->box_shadow_material = cogl_handle_ref (other->box_shadow_material);
|
||||||
|
@ -99,6 +99,10 @@ struct _StThemeNode {
|
|||||||
guint background_image_shadow_computed : 1;
|
guint background_image_shadow_computed : 1;
|
||||||
guint text_shadow_computed : 1;
|
guint text_shadow_computed : 1;
|
||||||
guint link_type : 2;
|
guint link_type : 2;
|
||||||
|
guint rendered_once : 1;
|
||||||
|
|
||||||
|
int box_shadow_min_width;
|
||||||
|
int box_shadow_min_height;
|
||||||
|
|
||||||
CoglHandle border_slices_texture;
|
CoglHandle border_slices_texture;
|
||||||
CoglHandle border_slices_material;
|
CoglHandle border_slices_material;
|
||||||
|
@ -102,6 +102,9 @@ struct _StThemeNodePaintState {
|
|||||||
float alloc_width;
|
float alloc_width;
|
||||||
float alloc_height;
|
float alloc_height;
|
||||||
|
|
||||||
|
float box_shadow_width;
|
||||||
|
float box_shadow_height;
|
||||||
|
|
||||||
CoglHandle box_shadow_material;
|
CoglHandle box_shadow_material;
|
||||||
CoglHandle prerendered_texture;
|
CoglHandle prerendered_texture;
|
||||||
CoglHandle prerendered_material;
|
CoglHandle prerendered_material;
|
||||||
|
Loading…
Reference in New Issue
Block a user