[gnome-shell] st-theme-node: Add repeating backgrounds



commit 7dbc78c95f2f149d15076d64b545bef9b5144595
Author: Jasper St. Pierre <jstpierre mecheye net>
Date:   Sat Jul 28 05:36:20 2012 -0300

    st-theme-node: Add repeating backgrounds
    
    Add support for the CSS "background-repeat" property. Currently, this
    only supports on/off, rather than allowing tiling in each individual
    dimension. It is supported for both the cogl and cairo rendering paths.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=680801

 src/st/st-theme-node-drawing.c         |   83 +++++++++++++++++++++++--------
 src/st/st-theme-node-private.h         |    1 +
 src/st/st-theme-node.c                 |    9 ++++
 tests/interactive/background-repeat.js |   29 +++++++++++
 tests/testcommon/test.css              |    4 ++
 5 files changed, 104 insertions(+), 22 deletions(-)
---
diff --git a/src/st/st-theme-node-drawing.c b/src/st/st-theme-node-drawing.c
index 96df6f8..8e58141 100644
--- a/src/st/st-theme-node-drawing.c
+++ b/src/st/st-theme-node-drawing.c
@@ -457,11 +457,12 @@ get_background_coordinates (StThemeNode *node,
 static void
 get_background_position (StThemeNode             *self,
                          const ClutterActorBox   *allocation,
-                         ClutterActorBox         *result)
+                         ClutterActorBox         *result,
+                         ClutterActorBox         *texture_coords)
 {
   gdouble painting_area_width, painting_area_height;
   gdouble background_image_width, background_image_height;
-  gdouble x, y;
+  gdouble x1, y1;
   gdouble scale_w, scale_h;
 
   /* get the background image size */
@@ -484,13 +485,31 @@ get_background_position (StThemeNode             *self,
   get_background_coordinates (self,
                               painting_area_width, painting_area_height,
                               background_image_width, background_image_height,
-                              &x, &y);
+                              &x1, &y1);
+
+  if (self->background_repeat)
+    {
+      gdouble width = allocation->x2 - allocation->x1 + x1;
+      gdouble height = allocation->y2 - allocation->y1 + y1;
+
+      *result = *allocation;
+
+      /* reference image is at x1, y1 */
+      texture_coords->x1 = x1 / background_image_width;
+      texture_coords->y1 = y1 / background_image_height;
+      texture_coords->x2 = width / background_image_width;
+      texture_coords->y2 = height / background_image_height;
+    }
+  else
+    {
+      result->x1 = x1;
+      result->y1 = y1;
+      result->x2 = x1 + background_image_width;
+      result->y2 = y1 + background_image_height;
 
-  /* place the background image */
-  result->x1 = x;
-  result->y1 = y;
-  result->x2 = result->x1 + background_image_width;
-  result->y2 = result->y1 + background_image_height;
+      texture_coords->x1 = texture_coords->y1 = 0;
+      texture_coords->x2 = texture_coords->y2 = 1;
+    }
 }
 
 /* Use of this function marks code which doesn't support
@@ -614,15 +633,21 @@ create_cairo_pattern_of_background_image (StThemeNode *node,
                               &x, &y);
   cairo_matrix_translate (&matrix, -x, -y);
 
+  if (node->background_repeat)
+    cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
+
   /* If it's opaque, fills up the entire allocated
    * area, then don't bother doing a background fill first
    */
-  if (content != CAIRO_CONTENT_COLOR_ALPHA
-      && x >= 0
-      && -x + background_image_width >= node->alloc_width
-      && y >= 0
-      && -y + background_image_height >= node->alloc_height)
-    *needs_background_fill = FALSE;
+  if (content != CAIRO_CONTENT_COLOR_ALPHA)
+    {
+      if (node->background_repeat ||
+          (x >= 0 &&
+           y >= 0 &&
+           background_image_width - x >= node->alloc_width &&
+           background_image_height -y >= node->alloc_height))
+        *needs_background_fill = FALSE;
+    }
 
   cairo_pattern_set_matrix (pattern, &matrix);
 
@@ -1444,6 +1469,9 @@ st_theme_node_render_resources (StThemeNode   *node,
       node->background_texture = st_texture_cache_load_file_to_cogl_texture (texture_cache, background_image);
       node->background_material = _st_create_texture_material (node->background_texture);
 
+      if (node->background_repeat)
+        cogl_material_set_layer_wrap_mode (node->background_material, 0, COGL_MATERIAL_WRAP_MODE_REPEAT);
+
       if (background_image_shadow_spec)
         {
           node->background_shadow_material = _st_create_shadow_material (background_image_shadow_spec,
@@ -1464,13 +1492,19 @@ st_theme_node_render_resources (StThemeNode   *node,
 static void
 paint_material_with_opacity (CoglHandle       material,
                              ClutterActorBox *box,
+                             ClutterActorBox *coords,
                              guint8           paint_opacity)
 {
   cogl_material_set_color4ub (material,
                               paint_opacity, paint_opacity, paint_opacity, paint_opacity);
 
   cogl_set_source (material);
-  cogl_rectangle (box->x1, box->y1, box->x2, box->y2);
+
+  if (coords)
+    cogl_rectangle_with_texture_coords (box->x1, box->y1, box->x2, box->y2,
+                                        coords->x1, coords->y1, coords->x2, coords->y2);
+  else
+    cogl_rectangle (box->x1, box->y1, box->x2, box->y2);
 }
 
 static void
@@ -1947,6 +1981,7 @@ st_theme_node_paint (StThemeNode           *node,
 
           paint_material_with_opacity (node->prerendered_material,
                                        &paint_box,
+                                       NULL,
                                        paint_opacity);
         }
 
@@ -1963,17 +1998,18 @@ st_theme_node_paint (StThemeNode           *node,
   if (node->background_texture != COGL_INVALID_HANDLE)
     {
       ClutterActorBox background_box;
+      ClutterActorBox texture_coords;
       gboolean has_visible_outline;
 
-      /* If the background doesn't have a border or opaque background,
-       * then we let its background image shadows leak out, but other
-       * wise we clip it.
+      /* If the node doesn't have an opaque or repeating background or
+       * a border then we let its background image shadows leak out,
+       * but otherwise we clip it.
        */
       has_visible_outline = st_theme_node_has_visible_outline (node);
 
-      get_background_position (node, &allocation, &background_box);
+      get_background_position (node, &allocation, &background_box, &texture_coords);
 
-      if (has_visible_outline)
+      if (has_visible_outline || node->background_repeat)
         cogl_clip_push_rectangle (allocation.x1, allocation.y1, allocation.x2, allocation.y2);
 
       /* CSS based drop shadows
@@ -1995,9 +2031,12 @@ st_theme_node_paint (StThemeNode           *node,
                                        &background_box,
                                        paint_opacity);
 
-      paint_material_with_opacity (node->background_material, &background_box, paint_opacity);
+      paint_material_with_opacity (node->background_material,
+                                   &background_box,
+                                   &texture_coords,
+                                   paint_opacity);
 
-      if (has_visible_outline)
+      if (has_visible_outline || node->background_repeat)
         cogl_clip_pop ();
     }
 }
diff --git a/src/st/st-theme-node-private.h b/src/st/st-theme-node-private.h
index f31f1b8..9ceee1c 100644
--- a/src/st/st-theme-node-private.h
+++ b/src/st/st-theme-node-private.h
@@ -88,6 +88,7 @@ struct _StThemeNode {
   CRDeclaration *inline_properties;
 
   guint background_position_set : 1;
+  guint background_repeat : 1;
 
   guint properties_computed : 1;
   guint geometry_computed : 1;
diff --git a/src/st/st-theme-node.c b/src/st/st-theme-node.c
index 331b5d8..7e966e8 100644
--- a/src/st/st-theme-node.c
+++ b/src/st/st-theme-node.c
@@ -1569,6 +1569,7 @@ _st_theme_node_ensure_background (StThemeNode *node)
   if (node->background_computed)
     return;
 
+  node->background_repeat = FALSE;
   node->background_computed = TRUE;
   node->background_color = TRANSPARENT_COLOR;
   node->background_gradient_type = ST_GRADIENT_NONE;
@@ -1658,6 +1659,14 @@ _st_theme_node_ensure_background (StThemeNode *node)
           else
             node->background_position_set = TRUE;
         }
+      else if (strcmp (property_name, "-repeat") == 0)
+        {
+          if (decl->value->type == TERM_IDENT)
+            {
+              if (strcmp (decl->value->content.str->stryng->str, "repeat") == 0)
+                node->background_repeat = TRUE;
+            }
+        }
       else if (strcmp (property_name, "-size") == 0)
         {
           if (decl->value->type == TERM_IDENT)
diff --git a/tests/interactive/background-repeat.js b/tests/interactive/background-repeat.js
new file mode 100644
index 0000000..3e1c869
--- /dev/null
+++ b/tests/interactive/background-repeat.js
@@ -0,0 +1,29 @@
+// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
+
+const Clutter = imports.gi.Clutter;
+const St = imports.gi.St;
+
+const UI = imports.testcommon.ui;
+
+function test() {
+    let stage = new Clutter.Stage({ width: 640, height: 480 });
+    UI.init(stage);
+
+    let vbox = new St.BoxLayout({ width: stage.width,
+                                  height: stage.height,
+                                  style: 'background: #ffee88;' });
+    stage.add_actor(vbox);
+
+    let scroll = new St.ScrollView();
+    vbox.add(scroll, { expand: true });
+
+    let box = new St.BoxLayout({ vertical: true });
+    scroll.add_actor(box);
+
+    let contents = new St.Widget({ width: 1000, height: 1000,
+                                   style_class: 'background-image background-repeat' });
+    box.add_actor(contents);
+
+    UI.main(stage);
+}
+test();
diff --git a/tests/testcommon/test.css b/tests/testcommon/test.css
index eeeb8de..6cbadfb 100644
--- a/tests/testcommon/test.css
+++ b/tests/testcommon/test.css
@@ -67,6 +67,10 @@ stage {
     background-color: white;
 }
 
+.background-repeat {
+    background-repeat: repeat;
+}
+
 .push-button {
     background: #eeddbb;
     border: 1px solid black;



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]