hippo-canvas r7262 - in trunk: . common/hippo tests



Author: otaylor
Date: Tue May 27 21:06:07 2008
New Revision: 7262
URL: http://svn.gnome.org/viewvc/hippo-canvas?rev=7262&view=rev

Log:
Add experimental image theming with SVGs and PNGs from stylesheets.

 -hippo-background-image: url("header.svg") 10px 10px 1px 10px;

Says to paint the background area with 'header.svg' (relative to the
stylesheet file) with the specified top/right/bottom/left borders
unscaled.

hippo-canvas-theme-image.[ch]: Object containing an image with borders.

tests/test-transparent.py tests/test-transparent.css tests/main.svg tests/header.css:
  Simple example of SVG image theming.


Added:
   trunk/common/hippo/hippo-canvas-theme-image.c
   trunk/common/hippo/hippo-canvas-theme-image.h
   trunk/tests/header.svg
   trunk/tests/main.svg
   trunk/tests/test-transparent.css
   trunk/tests/test-transparent.py
Modified:
   trunk/Makefile-canvas-sources.am
   trunk/common/hippo/hippo-canvas-box.c
   trunk/common/hippo/hippo-canvas-style.c
   trunk/common/hippo/hippo-canvas-style.h
   trunk/common/hippo/hippo-canvas-theme-internal.h
   trunk/common/hippo/hippo-canvas-theme.c
   trunk/configure.ac

Modified: trunk/Makefile-canvas-sources.am
==============================================================================
--- trunk/Makefile-canvas-sources.am	(original)
+++ trunk/Makefile-canvas-sources.am	Tue May 27 21:06:07 2008
@@ -81,6 +81,7 @@
 	$(CANVASSRCDIR)/common/hippo/hippo-canvas-text.h		\
 	$(CANVASSRCDIR)/common/hippo/hippo-canvas-theme.h		\
 	$(CANVASSRCDIR)/common/hippo/hippo-canvas-theme-engine.h	\
+	$(CANVASSRCDIR)/common/hippo/hippo-canvas-theme-image.h		\
 	$(CANVASSRCDIR)/common/hippo/hippo-canvas-widgets.h		\
 	$(CANVASSRCDIR)/common/hippo/hippo-canvas-util.h		\
 	$(CANVASSRCDIR)/common/hippo/hippo-event.h			\
@@ -109,6 +110,7 @@
 	$(CANVASSRCDIR)/common/hippo/hippo-canvas-test.h		\
 	$(CANVASSRCDIR)/common/hippo/hippo-canvas-theme.c		\
 	$(CANVASSRCDIR)/common/hippo/hippo-canvas-theme-engine.c	\
+	$(CANVASSRCDIR)/common/hippo/hippo-canvas-theme-image.c		\
 	$(CANVASSRCDIR)/common/hippo/hippo-canvas-theme-internal.h	\
 	$(CANVASSRCDIR)/common/hippo/hippo-canvas-util.c		\
 	$(CANVASSRCDIR)/common/hippo/hippo-event.c			\

Modified: trunk/common/hippo/hippo-canvas-box.c
==============================================================================
--- trunk/common/hippo/hippo-canvas-box.c	(original)
+++ trunk/common/hippo/hippo-canvas-box.c	Tue May 27 21:06:07 2008
@@ -1597,6 +1597,7 @@
                                   HippoRectangle *damaged_box)
 {
     HippoCanvasStyle *style = hippo_canvas_context_get_style(HIPPO_CANVAS_CONTEXT(box));
+    HippoCanvasThemeImage *background_theme_image;
     guint background_color_rgba;
     Borders borders;
     
@@ -1620,6 +1621,17 @@
         cairo_fill(cr);
     }
 
+    background_theme_image = hippo_canvas_get_background_theme_image(style);
+    if (background_theme_image != NULL) {
+        HippoRectangle area;
+
+        hippo_canvas_box_get_background_area(box, &area);
+
+        hippo_canvas_theme_image_render(background_theme_image, cr,
+                                        area.x, area.y,
+                                        area.width, area.height);
+    }
+
     get_borders(box, &borders);
 
     draw_border(box, style, cr, HIPPO_CANVAS_SIDE_TOP,

Modified: trunk/common/hippo/hippo-canvas-style.c
==============================================================================
--- trunk/common/hippo/hippo-canvas-style.c	(original)
+++ trunk/common/hippo/hippo-canvas-style.c	Tue May 27 21:06:07 2008
@@ -37,6 +37,8 @@
     double border_width[4];
     guint padding[4];
 
+    HippoCanvasThemeImage *background_theme_image;
+
     GType element_type;
     char *element_id;
     char *element_class;
@@ -48,6 +50,7 @@
     guint borders_computed : 1;
     guint background_computed : 1;
     guint foreground_computed : 1;
+    guint background_theme_image_computed : 1;
     guint link_type : 2;
 };
 
@@ -100,6 +103,11 @@
         style->font_desc = NULL;
     }
 
+    if (style->background_theme_image) {
+        g_object_unref(style->background_theme_image);
+        style->background_theme_image = NULL;
+    }
+
     G_OBJECT_CLASS(hippo_canvas_style_parent_class)->finalize(object);
 }
 
@@ -1379,6 +1387,112 @@
     return style->font_desc;
 }
 
+HippoCanvasThemeImage *
+hippo_canvas_get_background_theme_image (HippoCanvasStyle *style)
+{
+    int i;
+
+    if (style->background_theme_image_computed)
+        return style->background_theme_image;
+
+    style->background_theme_image = NULL;
+    style->background_theme_image_computed = TRUE;
+
+    ensure_properties(style);
+
+    for (i = style->n_properties - 1; i >= 0; i--) {
+        CRDeclaration *decl = style->properties[i];
+        
+        if (strcmp(decl->property->stryng->str, "-hippo-background-image") == 0) {
+            CRTerm *term = decl->value;
+            int lengths[4];
+            int n_lengths = 0;
+            int i;
+
+            const char *url;
+            int border_top;
+            int border_right;
+            int border_bottom;
+            int border_left;
+
+            char *filename;
+            GError *error = NULL;
+        
+            /* First term must be the URL to the image */
+            if (term->type != TERM_URI)
+                goto next_property;
+
+            url = term->content.str->stryng->str;
+            
+            term = term->next;
+
+            /* Followed by 0 to 4 lengths */
+            for (i = 0; i < 4; i++) {
+                double value;
+
+                if (term == NULL)
+                    break;
+
+                if (get_length_from_term(style, term, FALSE, &value) != VALUE_FOUND)
+                    goto next_property;
+
+                lengths[n_lengths] = (int)(0.5 + value);
+                n_lengths++;
+
+                term = term->next;
+            }
+
+            switch (n_lengths) {
+            case 0:
+                border_top = border_right = border_bottom = border_left = 0;
+                break; 
+            case 1:
+                border_top = border_right = border_bottom = border_left = lengths[0];
+                break; 
+            case 2:
+                border_top = border_bottom = lengths[0];
+                border_left = border_right = lengths[1];
+                break; 
+            case 3:
+                border_top = lengths[0];
+                border_left = border_right = lengths[1];
+                border_bottom = lengths[2];
+                break; 
+            case 4:
+            default:
+                border_top = lengths[0];
+                border_right = lengths[1];
+                border_bottom = lengths[2];
+                border_left = lengths[3];
+                break; 
+            }
+
+            filename = _hippo_canvas_theme_resolve_url(style->theme, decl, url);
+            if (filename == NULL)
+                goto next_property;
+            
+            style->background_theme_image = hippo_canvas_theme_image_new(filename,
+                                                                         border_top, border_right, border_bottom, border_left,
+                                                                         &error);
+
+            g_free(filename);
+
+            if (style->background_theme_image == NULL) {
+                g_warning("Failed to load theme image: %s", error->message);
+                g_error_free(error);
+                goto next_property;
+            } else {
+                return style->background_theme_image;
+            }
+        }
+
+    next_property:
+        ;
+    }
+
+    return NULL;
+}
+
 gboolean
 hippo_canvas_style_paint (HippoCanvasStyle       *style,
                           cairo_t                *cr,

Modified: trunk/common/hippo/hippo-canvas-style.h
==============================================================================
--- trunk/common/hippo/hippo-canvas-style.h	(original)
+++ trunk/common/hippo/hippo-canvas-style.h	Tue May 27 21:06:07 2008
@@ -3,6 +3,7 @@
 #define __HIPPO_CANVAS_STYLE_H__
 
 #include "hippo-canvas-context.h"
+#include "hippo-canvas-theme-image.h"
 
 G_BEGIN_DECLS
 
@@ -101,6 +102,11 @@
  */
 PangoFontDescription *hippo_canvas_style_get_font (HippoCanvasStyle *style);
 
+/* This is the getter for -hippo-background-image, which is different from
+ * background-image in having provisions for unscaled borders.
+ */
+HippoCanvasThemeImage *hippo_canvas_get_background_theme_image (HippoCanvasStyle *style);
+
 gboolean hippo_canvas_style_paint (HippoCanvasStyle       *style,
                                    cairo_t                *cr,
                                    const char             *name,

Added: trunk/common/hippo/hippo-canvas-theme-image.c
==============================================================================
--- (empty file)
+++ trunk/common/hippo/hippo-canvas-theme-image.c	Tue May 27 21:06:07 2008
@@ -0,0 +1,286 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
+
+#include <config.h>
+
+#include "hippo-canvas-theme-image.h"
+
+#ifdef HAVE_LIBRSVG
+#include <librsvg/rsvg.h>
+#include <librsvg/rsvg-cairo.h>
+#endif
+
+typedef enum {
+  THEME_IMAGE_SURFACE,
+  THEME_IMAGE_SVG
+} ThemeImageType;
+
+struct _HippoCanvasThemeImage {
+    GObject parent;
+
+    ThemeImageType type;
+    
+    union {
+#ifdef HAVE_LIBRSVG
+	RsvgHandle      *svg;
+#endif	
+	cairo_surface_t *surface;
+    } u;
+
+    int border_top;
+    int border_right;
+    int border_bottom;
+    int border_left;
+};
+
+struct _HippoCanvasThemeImageClass {
+    GObjectClass parent_class;
+
+};
+
+G_DEFINE_TYPE(HippoCanvasThemeImage, hippo_canvas_theme_image, G_TYPE_OBJECT)
+
+GQuark
+hippo_canvas_theme_image_error_quark (void)
+{
+    return g_quark_from_static_string ("hippo-canvas-theme-image-error-quark");
+}
+
+static void
+hippo_canvas_theme_image_finalize(GObject *object)
+{
+    HippoCanvasThemeImage *image = HIPPO_CANVAS_THEME_IMAGE(object);
+
+    switch (image->type) {
+    case THEME_IMAGE_SURFACE:
+	if (image->u.surface) {
+	    cairo_surface_destroy(image->u.surface);
+	    image->u.surface = NULL;
+	}
+	break;
+    case THEME_IMAGE_SVG:
+#ifdef HAVE_LIBRSVG
+	if (image->u.svg) {
+	    g_object_unref(image->u.svg);
+	    image->u.svg = NULL;
+	}
+#endif	
+	break;
+    }
+}
+
+static void
+hippo_canvas_theme_image_class_init(HippoCanvasThemeImageClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+    object_class->finalize = hippo_canvas_theme_image_finalize;
+}
+
+static void
+hippo_canvas_theme_image_init(HippoCanvasThemeImage *image)
+{
+}
+
+HippoCanvasThemeImage *
+hippo_canvas_theme_image_new (const char *filename,
+			      int         border_top,
+			      int         border_right,
+			      int         border_bottom,
+			      int         border_left,
+			      GError    **error)
+{
+    HippoCanvasThemeImage *image;
+
+    g_return_val_if_fail(error == NULL || *error == NULL, NULL);
+
+    image = g_object_new(HIPPO_TYPE_CANVAS_THEME_IMAGE, NULL);
+
+#ifdef HAVE_LIBRSVG
+    if (g_str_has_suffix(filename, ".svg") || g_str_has_suffix(filename, ".SVG")) {
+	image->type = THEME_IMAGE_SVG;
+
+	image->u.svg = rsvg_handle_new_from_file(filename, error);
+	if (image->u.svg == NULL) {
+	    /* librsvg does a horrible job setting error, it's probably NULL */
+	    if (*error == NULL)
+		g_set_error(error,
+			    HIPPO_CANVAS_THEME_IMAGE_ERROR,
+			    HIPPO_CANVAS_THEME_IMAGE_ERROR_FAILED,		  
+			    "Failed to read SVG image '%s'", filename);
+	    goto fail;
+	}
+    } else
+#endif	
+    if (g_str_has_suffix(filename, ".png") || g_str_has_suffix(filename, ".PNG")) {
+	image->type = THEME_IMAGE_SURFACE;
+
+	image->u.surface = cairo_image_surface_create_from_png(filename);
+	if (image->u.surface == NULL) {
+	    g_set_error(error,
+			HIPPO_CANVAS_THEME_IMAGE_ERROR,
+			HIPPO_CANVAS_THEME_IMAGE_ERROR_FAILED,		  
+			"Failed to read PNG image '%s'", filename);
+	    goto fail;
+	}
+    } else {
+	g_set_error(error,
+		    HIPPO_CANVAS_THEME_IMAGE_ERROR,
+		    HIPPO_CANVAS_THEME_IMAGE_ERROR_FAILED,		  
+		    "Unknown filetype for image '%s'", filename);
+	goto fail;
+    }
+
+    image->border_top = border_top;
+    image->border_right = border_right;
+    image->border_bottom = border_bottom;
+    image->border_left = border_left;
+
+    return image;
+
+fail:
+    g_object_unref(image);
+    return NULL;
+}
+
+void
+hippo_canvas_theme_image_render (HippoCanvasThemeImage *image,
+				 cairo_t               *cr,
+				 int                    x,
+				 int                    y,
+				 int                    width,
+				 int                    height)
+{
+    int source_width = 0;
+    int source_height = 0;
+
+    int source_x1 = 0, source_x2 = 0, source_y1 = 0, source_y2 = 0;
+    int dest_x1 = 0, dest_x2 = 0, dest_y1 = 0, dest_y2 = 0;
+
+    int i, j;
+
+    /* To draw a theme image, we divide the source and destination into 9
+     * pieces and draw each piece separately. (Some pieces may not exist
+     * if we have 0-width borders, in which case they'll be skipped)
+     * 
+     *                         i=0               i=1              i=2
+     *                     border_left                        border_right
+     *                    +------------+--------------------+--------------+
+     * j=0: border_top    |            |                    |              |
+     *                    +------------+--------------------+--------------+
+     * j=1                |            |                    |              |
+     *                    +------------+--------------------+--------------+
+     * j=2: border_bottom |            |                    |              |
+     *                    +------------+--------------------+--------------+
+     *
+     */
+	
+    switch (image->type) {
+    case THEME_IMAGE_SURFACE:
+	source_width = cairo_image_surface_get_width(image->u.surface);
+	source_height = cairo_image_surface_get_height(image->u.surface);
+	break;
+    case THEME_IMAGE_SVG:
+    {
+#ifdef HAVE_LIBRSVG
+	RsvgDimensionData dimensions;
+	rsvg_handle_get_dimensions(image->u.svg, &dimensions);
+	source_width = dimensions.width;
+	source_height = dimensions.height;
+#endif	
+	break;
+    }
+    }
+
+    for (j = 0; j < 3; j++) {
+	switch (j) {
+	case 0:
+	    source_y1 = 0;
+	    source_y2 = image->border_top;
+	    dest_y1 = y;
+	    dest_y2 = y + image->border_top;
+	    break;
+	case 1:
+	    source_y1 = image->border_top;
+	    source_y2 = source_height - image->border_bottom;
+	    dest_y1 = y + image->border_top;
+	    dest_y2 = y + height - image->border_bottom;
+	    break;
+	case 2:
+	    source_y1 = source_height - image->border_bottom;
+	    source_y2 = source_height;
+	    dest_y1 = y + height - image->border_bottom;
+	    dest_y2 = y + height;
+	    break;
+	}
+	
+	if (dest_y2 <= dest_y1)
+	    continue;
+
+	/* pixbuf-theme-engine has a nice interpretation of source_y2 == source_y1,
+	 * dest_y2 != dest_y1, which is to linearly interpolate between the surrounding
+	 * areas. We could do that for the surface case by setting
+	 *
+	 *   source_y1 == y - 0.5
+	 *   source_y2 == y + 0.5
+	 *
+	 * but it's hard for the SVG case. source_y2 < source_y1 is pathological ... someone
+	 * specified borders that sum up larger than the image.
+	 */
+	 if (source_y2 <= source_y1)
+	    continue;
+	    
+	for (i = 0; i < 3; i++) {
+	    switch (i) {
+	    case 0:
+		source_x1 = 0;
+		source_x2 = image->border_left;
+		dest_x1 = x;
+		dest_x2 = x + image->border_left;
+		break;
+	    case 1:
+		source_x1 = image->border_left;
+		source_x2 = source_width - image->border_right;
+		dest_x1 = x + image->border_left;
+		dest_x2 = x + width - image->border_right;
+		break;
+	    case 2:
+		source_x1 = source_width - image->border_right;
+		source_x2 = source_width;
+		dest_x1 = x + width - image->border_right;
+		dest_x2 = x + width;
+		break;
+	    }
+
+	    if (dest_x2 <= dest_x1)
+		continue;
+	    
+	    if (source_x2 <= source_x1)
+		continue;
+
+	    cairo_save(cr);
+	    
+	    cairo_rectangle(cr, dest_x1, dest_y1, dest_x2 - dest_x1, dest_y2 - dest_y1);
+	    cairo_clip(cr);
+	    
+	    cairo_translate(cr, dest_x1, dest_y1);
+	    cairo_scale(cr,
+			(double)(dest_x2 - dest_x1) / (source_x2 - source_x1),
+			(double)(dest_y2 - dest_y1) / (source_y2 - source_y1));
+
+	    switch (image->type) {
+	    case THEME_IMAGE_SURFACE:
+		cairo_set_source_surface(cr, image->u.surface, - source_x1, - source_y1);
+		cairo_paint(cr);
+		break;
+	    case THEME_IMAGE_SVG:
+#ifdef HAVE_LIBRSVG
+		cairo_translate(cr, - source_x1, - source_y1);
+		rsvg_handle_render_cairo(image->u.svg, cr);
+#endif		
+		break;
+	    }
+	    
+	    cairo_restore(cr);
+	}
+    }
+}

Added: trunk/common/hippo/hippo-canvas-theme-image.h
==============================================================================
--- (empty file)
+++ trunk/common/hippo/hippo-canvas-theme-image.h	Tue May 27 21:06:07 2008
@@ -0,0 +1,49 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
+#ifndef __HIPPO_CANVAS_THEME_IMAGE_H__
+#define __HIPPO_CANVAS_THEME_IMAGE_H__
+
+#include <glib-object.h>
+#include <cairo.h>
+
+G_BEGIN_DECLS
+
+/* A HippoCanvasThemeImage encapsulates an image with specified unscaled borders
+ * on each edge. This class has the secondary purpose of encapsulating the use
+ * of librvsg to render SVG images without revealing it in the public API.
+ */
+#define HIPPO_TYPE_CANVAS_THEME_IMAGE              (hippo_canvas_theme_image_get_type ())
+#define HIPPO_CANVAS_THEME_IMAGE(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), HIPPO_TYPE_CANVAS_THEME_IMAGE, HippoCanvasThemeImage))
+#define HIPPO_CANVAS_THEME_IMAGE_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), HIPPO_TYPE_CANVAS_THEME_IMAGE, HippoCanvasThemeImageClass))
+#define HIPPO_IS_CANVAS_THEME_IMAGE(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), HIPPO_TYPE_CANVAS_THEME_IMAGE))
+#define HIPPO_IS_CANVAS_THEME_IMAGE_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), HIPPO_TYPE_CANVAS_THEME_IMAGE))
+#define HIPPO_CANVAS_THEME_IMAGE_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), HIPPO_TYPE_CANVAS_THEME_IMAGE, HippoCanvasThemeImageClass))
+
+typedef struct _HippoCanvasThemeImage HippoCanvasThemeImage;
+typedef struct _HippoCanvasThemeImageClass HippoCanvasThemeImageClass;
+
+#define HIPPO_CANVAS_THEME_IMAGE_ERROR (hippo_canvas_theme_image_error_quark())
+
+enum {
+    HIPPO_CANVAS_THEME_IMAGE_ERROR_FAILED
+} HippoCanvasThemeImageError;
+
+GType             hippo_canvas_theme_image_get_type          (void) G_GNUC_CONST;
+
+GQuark            hippo_canvas_theme_image_error_quark (void);
+
+HippoCanvasThemeImage *hippo_canvas_theme_image_new    (const char             *filename,
+                                                        int                     border_top,
+                                                        int                     border_right,
+                                                        int                     border_bottom,
+                                                        int                     border_left,
+                                                        GError                **error);
+void                   hippo_canvas_theme_image_render (HippoCanvasThemeImage  *image,
+                                                        cairo_t                *cr,
+                                                        int                     x,
+                                                        int                     y,
+                                                        int                     width,
+                                                        int                     height);
+
+G_END_DECLS
+
+#endif /* __HIPPO_CANVAS_THEME_IMAGE_H__ */

Modified: trunk/common/hippo/hippo-canvas-theme-internal.h
==============================================================================
--- trunk/common/hippo/hippo-canvas-theme-internal.h	(original)
+++ trunk/common/hippo/hippo-canvas-theme-internal.h	Tue May 27 21:06:07 2008
@@ -17,6 +17,11 @@
                                                  CRDeclaration  ***properties,
                                                  int              *n_properties);
 
+/* Resolve an URL from the stylesheet to a filename */
+char *_hippo_canvas_theme_resolve_url (HippoCanvasTheme *theme,
+                                       CRDeclaration    *decl,
+                                       const char       *url);
+
 G_END_DECLS
 
 #endif /* __HIPPO_CANVAS_THEME_INTERNAL_H__ */

Modified: trunk/common/hippo/hippo-canvas-theme.c
==============================================================================
--- trunk/common/hippo/hippo-canvas-theme.c	(original)
+++ trunk/common/hippo/hippo-canvas-theme.c	Tue May 27 21:06:07 2008
@@ -935,3 +935,68 @@
     *n_properties = props->len;
     *properties = (CRDeclaration **)g_ptr_array_free(props, FALSE);
 }
+
+/* Resolve an url from an url() reference in a stylesheet into an absolute
+ * local filename, if possible. The resolution here is distinctly lame and
+ * will fail on many examples.
+ */
+char *
+_hippo_canvas_theme_resolve_url (HippoCanvasTheme *theme,
+                                 CRDeclaration    *decl,
+                                 const char       *url)
+{
+    enum CRStyleOrigin origin = decl->parent_statement->parent_sheet->origin;
+    const char *stylesheet_filename = NULL;
+    char *dirname;
+    char *filename;
+
+    /* Handle absolute file:/ URLs */
+    if (g_str_has_prefix(url, "file:") ||
+        g_str_has_prefix(url, "File:") ||
+        g_str_has_prefix(url, "FILE:"))
+    {
+        GError *error = NULL;
+        char *filename;
+
+        filename = g_filename_from_uri(url, NULL, &error);
+        if (filename == NULL) {
+            g_warning("%s", error->message);
+            g_error_free(error);
+        }
+
+        return NULL;
+    }
+
+    /* Guard against http:/ URLs */
+
+    if (g_str_has_prefix(url, "http:") ||
+        g_str_has_prefix(url, "Http:") ||
+        g_str_has_prefix(url, "HTTP:"))
+    {
+        g_warning("Http URL '%s' in theme stylesheet is not supported", url);
+        return NULL;
+    }
+        
+    /* Assume anything else is a relative URL, and "resolve" it
+     */
+    if (url[0] == '/')
+        return g_strdup(url);
+    
+    if (origin == ORIGIN_UA)
+        stylesheet_filename = theme->default_stylesheet;
+    else if (origin == ORIGIN_AUTHOR)
+        stylesheet_filename = theme->application_stylesheet;
+    else if (origin == ORIGIN_USER)
+        stylesheet_filename = theme->theme_stylesheet;
+
+    if (stylesheet_filename == NULL) {
+        g_warning("Can't get base to resolve url '%s'", url);
+        return NULL;
+    }
+
+    dirname = g_path_get_dirname(stylesheet_filename);
+    filename = g_build_filename(dirname, url, NULL);
+    g_free(dirname);
+
+    return filename;
+}

Modified: trunk/configure.ac
==============================================================================
--- trunk/configure.ac	(original)
+++ trunk/configure.ac	Tue May 27 21:06:07 2008
@@ -144,8 +144,20 @@
 GTK2_REQUIRED=2.6.0
 LIBCROCO_REQUIRED=0.6.0
 PANGO_REQUIRED=1.14
+LIBRSVG_REQUIRED=2.18
 
-PKG_CHECK_MODULES(LIBHIPPOCANVAS, gobject-2.0 >= $GLIB2_REQUIRED gtk+-2.0 >= $GTK2_REQUIRED libcroco-0.6 >= $LIBCROCO_REQUIRED cairo pango >= $PANGO_REQUIRED)
+# We define HAVE_LIBRSVG so we can do a Windows build without it, but there's
+# no point in supporting no-librsvg Linux builds, so we don't go ahead and
+# make it fully optional.
+PKG_CHECK_EXISTS(librsvg-2.0 >= $LIBRSVG_REQUIRED, have_rsvg=true, have_rsvg=false)
+if $have_rsvg; then
+   AC_DEFINE(HAVE_LIBRSVG, 1, [Define if you have librsvg])
+   librsvg_modules=librsvg-2.0 
+else 
+   AC_MSG_ERROR([librsvg >= $LIBRSVG_REQUIRED is required])
+fi
+
+PKG_CHECK_MODULES(LIBHIPPOCANVAS, gobject-2.0 >= $GLIB2_REQUIRED gtk+-2.0 >= $GTK2_REQUIRED libcroco-0.6 >= $LIBCROCO_REQUIRED $librsvg_modules cairo pango >= $PANGO_REQUIRED)
 
 GLIB_GENMARSHAL=`$PKG_CONFIG --variable=glib_genmarshal glib-2.0`
 AC_SUBST(GLIB_GENMARSHAL)

Added: trunk/tests/header.svg
==============================================================================
--- (empty file)
+++ trunk/tests/header.svg	Tue May 27 21:06:07 2008
@@ -0,0 +1,146 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/";
+   xmlns:cc="http://creativecommons.org/ns#";
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+   xmlns:svg="http://www.w3.org/2000/svg";
+   xmlns="http://www.w3.org/2000/svg";
+   xmlns:xlink="http://www.w3.org/1999/xlink";
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
+   width="50"
+   height="20"
+   id="svg2715"
+   sodipodi:version="0.32"
+   inkscape:version="0.46"
+   version="1.0"
+   sodipodi:docname="header.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape">
+  <defs
+     id="defs2717">
+    <linearGradient
+       id="linearGradient3531">
+      <stop
+         style="stop-color:#bcbcbc;stop-opacity:1;"
+         offset="0"
+         id="stop3533" />
+      <stop
+         style="stop-color:#5b5bdf;stop-opacity:1;"
+         offset="1"
+         id="stop3535" />
+    </linearGradient>
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="0 : 526.18109 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="744.09448 : 526.18109 : 1"
+       inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+       id="perspective2723" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3531"
+       id="linearGradient3537"
+       x1="5"
+       y1="5"
+       x2="45"
+       y2="45"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(0,1)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3531"
+       id="linearGradient3162"
+       gradientUnits="userSpaceOnUse"
+       x1="25"
+       y1="2"
+       x2="25"
+       y2="19" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3531"
+       id="linearGradient3787"
+       gradientUnits="userSpaceOnUse"
+       x1="25"
+       y1="2"
+       x2="25"
+       y2="19" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3531"
+       id="linearGradient3812"
+       gradientUnits="userSpaceOnUse"
+       x1="25"
+       y1="2"
+       x2="25"
+       y2="19" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     gridtolerance="10000"
+     guidetolerance="10"
+     objecttolerance="10"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="8"
+     inkscape:cx="0.053668"
+     inkscape:cy="25.046335"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     showborder="true"
+     inkscape:window-width="1400"
+     inkscape:window-height="1000"
+     inkscape:window-x="0"
+     inkscape:window-y="24">
+    <inkscape:grid
+       type="xygrid"
+       id="grid2725"
+       visible="true"
+       enabled="true"
+       spacingx="1px"
+       spacingy="1px" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata2720">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage"; />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <path
+       style="fill:url(#linearGradient3812);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="M 5,1 L 1,5 L 1,20 L 49,20 L 49,5 L 45,1 L 5,1 z"
+       id="path3529" />
+    <g
+       id="g2388"
+       style="enable-background:new">
+      <path
+         style="opacity:1;fill:#707070;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;comp-op:plus"
+         d="M 7.5,0 C 3.3536486,0 0,3.3536486 0,7.5 L 0,20 L 1,20 L 1,7.5 C 1,3.8903514 3.8903514,1 7.5,1 L 42.5,1 C 46.109649,1 49,3.8903514 49,7.5 L 49,20 L 50,20 L 50,7.5 C 50,3.3536486 46.646351,0 42.5,0 L 7.5,0 z"
+         id="rect3509" />
+      <path
+         style="opacity:1;fill:#c3dff4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;comp-op:plus"
+         d="M 7.5,1 C 3.9076486,1 1,3.9076486 1,7.5 L 1,20 L 2,20 L 2,7.5 C 2,4.4443514 4.4443514,2 7.5,2 L 42.5,2 C 45.555649,2 48,4.4443514 48,7.5 L 48,20 L 49,20 L 49,7.5 C 49,3.9076486 46.092351,1 42.5,1 L 7.5,1 z"
+         id="rect3511" />
+    </g>
+    <rect
+       style="opacity:1;fill:#0d1c59;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+       id="rect3267"
+       width="46"
+       height="1"
+       x="2"
+       y="19" />
+  </g>
+</svg>

Added: trunk/tests/main.svg
==============================================================================
--- (empty file)
+++ trunk/tests/main.svg	Tue May 27 21:06:07 2008
@@ -0,0 +1,133 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/";
+   xmlns:cc="http://creativecommons.org/ns#";
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+   xmlns:svg="http://www.w3.org/2000/svg";
+   xmlns="http://www.w3.org/2000/svg";
+   xmlns:xlink="http://www.w3.org/1999/xlink";
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
+   width="50"
+   height="40"
+   id="svg2715"
+   sodipodi:version="0.32"
+   inkscape:version="0.46"
+   version="1.0"
+   sodipodi:docname="main.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape">
+  <defs
+     id="defs2717">
+    <linearGradient
+       id="linearGradient3531">
+      <stop
+         style="stop-color:#bcbcbc;stop-opacity:0.78431374;"
+         offset="0"
+         id="stop3533" />
+      <stop
+         style="stop-color:#0000ff;stop-opacity:0.50196081;"
+         offset="1"
+         id="stop3535" />
+    </linearGradient>
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="0 : 526.18109 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="744.09448 : 526.18109 : 1"
+       inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+       id="perspective2723" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3531"
+       id="linearGradient3537"
+       x1="5"
+       y1="5"
+       x2="45"
+       y2="45"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(0,1)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3531"
+       id="linearGradient3162"
+       gradientUnits="userSpaceOnUse"
+       x1="5"
+       y1="5"
+       x2="45"
+       y2="45" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3531"
+       id="linearGradient3211"
+       gradientUnits="userSpaceOnUse"
+       x1="5"
+       y1="5"
+       x2="45"
+       y2="45" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     gridtolerance="10000"
+     guidetolerance="10"
+     objecttolerance="10"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="8"
+     inkscape:cx="27.964833"
+     inkscape:cy="33.919797"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     showborder="true"
+     inkscape:window-width="1400"
+     inkscape:window-height="1000"
+     inkscape:window-x="0"
+     inkscape:window-y="24"
+     showguides="true"
+     inkscape:guide-bbox="true">
+    <inkscape:grid
+       type="xygrid"
+       id="grid2725"
+       visible="true"
+       enabled="true"
+       spacingx="1px"
+       spacingy="1px" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata2720">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage"; />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(0,-10)">
+    <path
+       style="fill:url(#linearGradient3211);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="M 1,10 L 1,45 L 5,49 L 45,49 L 49,45 L 49,10 L 1,10 z"
+       id="path3529" />
+    <g
+       id="g2388"
+       style="enable-background:new">
+      <path
+         style="opacity:1;fill:#707070;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;comp-op:plus"
+         d="M 0,10 L 0,42.5 C 0,46.646351 3.3536486,50 7.5,50 L 42.5,50 C 46.646351,50 50,46.646351 50,42.5 L 50,10 L 49,10 L 49,42.5 C 49,46.109649 46.109649,49 42.5,49 L 7.5,49 C 3.8903514,49 1,46.109649 1,42.5 L 1,10 L 0,10 z"
+         id="rect3509" />
+      <path
+         style="opacity:1;fill:#c3dff4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;comp-op:plus"
+         d="M 1,10 L 1,42.5 C 1,46.092351 3.9076486,49 7.5,49 L 42.5,49 C 46.092351,49 49,46.092351 49,42.5 L 49,10 L 48,10 L 48,42.5 C 48,45.555649 45.555649,48 42.5,48 L 7.5,48 C 4.4443514,48 2,45.555649 2,42.5 L 2,10 L 1,10 z"
+         id="rect3511" />
+    </g>
+  </g>
+</svg>

Added: trunk/tests/test-transparent.css
==============================================================================
--- (empty file)
+++ trunk/tests/test-transparent.css	Tue May 27 21:06:07 2008
@@ -0,0 +1,11 @@
+canvas {
+    background-color: transparent;
+}
+
+#header {
+    -hippo-background-image: url("header.svg") 10px 10px 1px;
+}
+
+#main {
+    -hippo-background-image: url("main.svg") 0px 10px 10px;
+}

Added: trunk/tests/test-transparent.py
==============================================================================
--- (empty file)
+++ trunk/tests/test-transparent.py	Tue May 27 21:06:07 2008
@@ -0,0 +1,58 @@
+#!/usr/bin/python
+# coding=UTF_8
+
+from __future__ import division
+
+import pygtk
+pygtk.require('2.0')
+import gobject
+import gtk
+import hippo
+import rsvg
+import sys
+
+window = hippo.CanvasWindow()
+
+if not window.get_screen().is_composited():
+    print sys.stderr, "Compositing manager must be running"
+    sys.exit(1)
+
+colormap = window.get_screen().get_rgba_colormap()
+if colormap == None:
+    print sys.stderr, "RGBA visual not found"
+    sys.exit(1)
+
+window.set_colormap(colormap)
+window.set_decorated(False)
+
+theme = hippo.CanvasTheme(theme_stylesheet="test-transparent.css")
+window.set_theme(theme)
+
+window.connect('delete-event', lambda *args: gtk.main_quit())
+window.connect('button-press-event', lambda *args: gtk.main_quit())
+
+root = hippo.CanvasBox(id='root')
+window.set_root(root)
+
+header = hippo.CanvasBox(id='header')
+root.append(header)
+
+header_text = hippo.CanvasText(text="Khayyam via Fitzgerald", border=5, font='18')
+header.append(header_text)
+
+main = hippo.CanvasBox(id='main')
+root.append(main)
+
+text = u"""
+Think, in this batterâd Caravanserai
+Whose Doorways are alternate Night and Day,
+  How Sultan after Sultan with his Pomp
+Abode his Hour or two, and went his way.
+""".strip()
+
+text_item = hippo.CanvasText(text=text, border=10)
+main.append(text_item)
+
+window.show()
+
+gtk.main()



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