summaryrefslogtreecommitdiff
path: root/shared
diff options
context:
space:
mode:
authorMarek Chalupa <mchqwerty@gmail.com>2014-10-29 14:51:23 +0100
committerPekka Paalanen <pekka.paalanen@collabora.co.uk>2014-11-19 15:46:30 +0200
commiteaea47051053d6f991e900ab6b51cdc99095a7d3 (patch)
tree5037d8d600173719dfc0772a0d29af95da0b1b4a /shared
parent0d7fe8d92574e8cc9ff2195cbade28bab50d1c8d (diff)
downloadweston-eaea47051053d6f991e900ab6b51cdc99095a7d3.tar.gz
cairo-util: fix shadows for small clients
If the client is small (< 128 pixels in any ward), then the shadows overlap and create dark lines behind clients. This is a problem mosly with pop-up menues. The lines become observable when the menu has less than three items. The other case is when the client doesn't restrict its size when resizing (try 'weston-eventdemo --max-width=1 --max-height=1' for example) This fixes a part of the bug: https://bugs.freedesktop.org/show_bug.cgi?id=78511 v2: - rework computing of the size of corners - rewrite some comments - rename tile_mask to render_shadow (in separate patch) Signed-off-by: Marek Chalupa <mchqwerty@gmail.com> Tested-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
Diffstat (limited to 'shared')
-rw-r--r--shared/cairo-util.c129
1 files changed, 83 insertions, 46 deletions
diff --git a/shared/cairo-util.c b/shared/cairo-util.c
index 73e3ae70..a73c08bf 100644
--- a/shared/cairo-util.c
+++ b/shared/cairo-util.c
@@ -142,7 +142,7 @@ render_shadow(cairo_t *cr, cairo_surface_t *surface,
{
cairo_pattern_t *pattern;
cairo_matrix_t matrix;
- int i, fx, fy, vmargin;
+ int i, fx, fy, shadow_height, shadow_width;
cairo_set_source_rgba(cr, 0, 0, 0, 0.45);
cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
@@ -150,6 +150,14 @@ render_shadow(cairo_t *cr, cairo_surface_t *surface,
cairo_pattern_set_filter(pattern, CAIRO_FILTER_NEAREST);
for (i = 0; i < 4; i++) {
+ /* when fy is set, then we are working with lower corners,
+ * when fx is set, then we are working with right corners
+ *
+ * 00 ------- 01
+ * | |
+ * | |
+ * 10 ------- 11
+ */
fx = i & 1;
fy = i >> 1;
@@ -158,63 +166,92 @@ render_shadow(cairo_t *cr, cairo_surface_t *surface,
-y + fy * (128 - height));
cairo_pattern_set_matrix(pattern, &matrix);
- if (fy)
- vmargin = margin;
- else
- vmargin = top_margin;
+ shadow_width = margin;
+ shadow_height = fy ? margin : top_margin;
+
+ /* if the shadows together are greater than the surface, we need
+ * to fix it - set the shadow size to the half of
+ * the size of surface. Also handle the case when the size is
+ * not divisible by 2. In that case we need one part of the
+ * shadow to be one pixel greater. !fy or !fx, respectively,
+ * will do the work.
+ */
+ if (height < 2 * shadow_height)
+ shadow_height = (height + !fy) / 2;
+
+ if (width < 2 * shadow_width)
+ shadow_width = (width + !fx) / 2;
cairo_reset_clip(cr);
cairo_rectangle(cr,
- x + fx * (width - margin),
- y + fy * (height - vmargin),
- margin, vmargin);
+ x + fx * (width - shadow_width),
+ y + fy * (height - shadow_height),
+ shadow_width, shadow_height);
cairo_clip (cr);
cairo_mask(cr, pattern);
}
- /* Top stretch */
- cairo_matrix_init_translate(&matrix, 60, 0);
- cairo_matrix_scale(&matrix, 8.0 / width, 1);
- cairo_matrix_translate(&matrix, -x - width / 2, -y);
- cairo_pattern_set_matrix(pattern, &matrix);
- cairo_rectangle(cr, x + margin, y, width - 2 * margin, margin);
- cairo_reset_clip(cr);
- cairo_rectangle(cr,
- x + margin,
- y,
- width - 2 * margin, margin);
- cairo_clip (cr);
- cairo_mask(cr, pattern);
+ shadow_width = width - 2 * margin;
+ shadow_height = top_margin;
+ if (height < 2 * shadow_height)
+ shadow_height = height / 2;
- /* Bottom stretch */
- cairo_matrix_translate(&matrix, 0, -height + 128);
- cairo_pattern_set_matrix(pattern, &matrix);
+ if (shadow_width > 0 && shadow_height) {
+ /* Top stretch */
+ cairo_matrix_init_translate(&matrix, 60, 0);
+ cairo_matrix_scale(&matrix, 8.0 / width, 1);
+ cairo_matrix_translate(&matrix, -x - width / 2, -y);
+ cairo_pattern_set_matrix(pattern, &matrix);
+ cairo_rectangle(cr, x + margin, y, shadow_width, shadow_height);
- cairo_reset_clip(cr);
- cairo_rectangle(cr, x + margin, y + height - margin,
- width - 2 * margin, margin);
- cairo_clip (cr);
- cairo_mask(cr, pattern);
+ cairo_reset_clip(cr);
+ cairo_rectangle(cr,
+ x + margin, y,
+ shadow_width, shadow_height);
+ cairo_clip (cr);
+ cairo_mask(cr, pattern);
- /* Left stretch */
- cairo_matrix_init_translate(&matrix, 0, 60);
- cairo_matrix_scale(&matrix, 1, 8.0 / height);
- cairo_matrix_translate(&matrix, -x, -y - height / 2);
- cairo_pattern_set_matrix(pattern, &matrix);
- cairo_reset_clip(cr);
- cairo_rectangle(cr, x, y + margin, margin, height - 2 * margin);
- cairo_clip (cr);
- cairo_mask(cr, pattern);
+ /* Bottom stretch */
+ cairo_matrix_translate(&matrix, 0, -height + 128);
+ cairo_pattern_set_matrix(pattern, &matrix);
- /* Right stretch */
- cairo_matrix_translate(&matrix, -width + 128, 0);
- cairo_pattern_set_matrix(pattern, &matrix);
- cairo_rectangle(cr, x + width - margin, y + margin,
- margin, height - 2 * margin);
- cairo_reset_clip(cr);
- cairo_clip (cr);
- cairo_mask(cr, pattern);
+ cairo_reset_clip(cr);
+ cairo_rectangle(cr, x + margin, y + height - margin,
+ shadow_width, margin);
+ cairo_clip (cr);
+ cairo_mask(cr, pattern);
+ }
+
+ shadow_width = margin;
+ if (width < 2 * shadow_width)
+ shadow_width = width / 2;
+
+ shadow_height = height - margin - top_margin;
+
+ /* if height is smaller than sum of margins,
+ * then the shadow is already done by the corners */
+ if (shadow_height > 0 && shadow_width) {
+ /* Left stretch */
+ cairo_matrix_init_translate(&matrix, 0, 60);
+ cairo_matrix_scale(&matrix, 1, 8.0 / height);
+ cairo_matrix_translate(&matrix, -x, -y - height / 2);
+ cairo_pattern_set_matrix(pattern, &matrix);
+ cairo_reset_clip(cr);
+ cairo_rectangle(cr, x, y + top_margin,
+ shadow_width, shadow_height);
+ cairo_clip (cr);
+ cairo_mask(cr, pattern);
+
+ /* Right stretch */
+ cairo_matrix_translate(&matrix, -width + 128, 0);
+ cairo_pattern_set_matrix(pattern, &matrix);
+ cairo_rectangle(cr, x + width - shadow_width, y + top_margin,
+ shadow_width, shadow_height);
+ cairo_reset_clip(cr);
+ cairo_clip (cr);
+ cairo_mask(cr, pattern);
+ }
cairo_pattern_destroy(pattern);
cairo_reset_clip(cr);