changeset 257:50d253d0fcba

Simple image loader and image shape. - img_ldr.c is a simple image loader that rooted on a directory specified when a loader instance been created. - sh_image_t is corresponding shape of image tag in SVG. - This changeset is still buggy. It need more testing. - svg2code.py is not ready for image tag.
author Thinker K.F. Li <thinker@branda.to>
date Thu, 15 Jan 2009 16:46:47 +0800
parents cac9ad3df633
children f24129d4f0f9
files include/Makefile.am include/mb_img_ldr.h include/mb_prop.h include/mb_redraw_man.h include/mb_shapes.h include/mb_types.h src/Makefile.am src/Makefile.pmake src/img_ldr.c src/redraw_man.c src/shape_image.c tools/mb_c_header.m4 tools/mb_c_source.m4 tools/svg2code.py
diffstat 14 files changed, 425 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/include/Makefile.am	Thu Jan 15 02:15:35 2009 +0800
+++ b/include/Makefile.am	Thu Jan 15 16:46:47 2009 +0800
@@ -9,4 +9,5 @@
 	mb_shapes.h	\
 	mb_tools.h	\
 	mb_prop.h	\
-	mb_X_supp.h
+	mb_X_supp.h	\
+	mb_so.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/mb_img_ldr.h	Thu Jan 15 16:46:47 2009 +0800
@@ -0,0 +1,57 @@
+#ifndef __MB_IMG_LDR_H_
+#define __MB_IMG_LDR_H_
+
+typedef struct _mb_img_data mb_img_data_t;
+typedef struct _mb_img_ldr mb_img_ldr_t;
+
+typedef enum _mb_img_fmt {
+    MB_IFMT_DUMMY,
+    MB_IFMT_ARGB32,
+    MB_IFMT_RGB24,
+    MB_IFMT_A8,
+    MB_IFMT_A1,
+    MB_IFMT_RGB16_565
+} mb_img_fmt_t;
+
+/*! \brief Encapsulate image.
+ *
+ * The format and content of an image is encapsulated by imag_data_t.
+ * We hope someday, we can create an abstract backend layer that
+ * can deal with image data.
+ */
+struct _mb_img_data {
+    /*! \brief Content of the image. */
+    void *content;
+    int width, height;
+    int stride;			/*!< \brief Number of bytes a row */
+    mb_img_fmt_t fmt;
+    /*! \brief Release the image that was loaded by the loader. */
+    void (*free)(mb_img_data_t *img);
+};
+#define MB_IMG_DATA_FREE(img) (img)->free(img)
+
+/*! \brief Image loader.
+ *
+ * An image loader take a ID and find out the corresponding
+ * image from filesystem or somewhere.  Image ID is a hierachical
+ * structured path.  It is relative to the root of image database.
+ * Users of a loader do not need to know where the database is.
+ * The location can be configured when a loader been instantiated.
+ * But, it is invisible when loading images by an image loader.
+ */
+struct _mb_img_ldr {
+    /*! \brief Load a image with specified ID. */
+    mb_img_data_t *(*load)(mb_img_ldr_t *ldr, const char *img_id);
+    /*! \brief Free the loader. */
+    void (*free)(mb_img_ldr_t *ldr);
+};
+#define MB_IMG_LDR_FREE(ldr) (ldr)->free(ldr)
+
+/*! \brief Create a simple image loader.
+ *
+ * \param img_repository is a repository where images are loaded from.
+ * \return NULL for error.
+ */
+extern mb_img_ldr_t *simple_mb_img_ldr_new(const char *img_repository);
+
+#endif /* __MB_IMG_LDR_H_ */
--- a/include/mb_prop.h	Thu Jan 15 02:15:35 2009 +0800
+++ b/include/mb_prop.h	Thu Jan 15 16:46:47 2009 +0800
@@ -11,6 +11,10 @@
  * to keep property values.  Every property is identified by a ID; an
  * integer.  Programmer can use a ID to set/get value to/from a property
  * store.  The ID should be unique in a property store.
+ *
+ * \todo Add a free function pointer on entries to release resources when
+ *	the store is destroy. (See: \ref mouse.c)
+ *
  * @{
  */
 
--- a/include/mb_redraw_man.h	Thu Jan 15 02:15:35 2009 +0800
+++ b/include/mb_redraw_man.h	Thu Jan 15 16:46:47 2009 +0800
@@ -78,6 +78,7 @@
                                 *          graphic backend. 
 				*          \see rdman_attach_backend()
 				*/
+    mb_prop_store_t props;
 };
 
 extern int redraw_man_init(redraw_man_t *rdman, cairo_t *cr,
--- a/include/mb_shapes.h	Thu Jan 15 02:15:35 2009 +0800
+++ b/include/mb_shapes.h	Thu Jan 15 16:46:47 2009 +0800
@@ -10,6 +10,7 @@
 #include <cairo.h>
 #include "mb_types.h"
 #include "mb_redraw_man.h"
+#include "mb_img_ldr.h"
 
 /*! \page define_shape How to Define Shapes
  *
@@ -29,6 +30,14 @@
  * - event.c::draw_shape_path()
  * - redraw_man.c::clean_shape()
  * - redraw_man.c::draw_shape()
+ *
+ * \section shape_transform Shape Transform
+ *
+ * All shape types must have a shape transform function.  It is invoked by
+ * redraw_man.c::clean_shape().  It's task is to update \ref geo_t of the
+ * shape object.  In most situtation, it call geo_from_positions() to
+ * update geo_t.
+ * 
  */
 
 /*! \defgroup shapes Shapes
@@ -68,6 +77,19 @@
 extern void sh_rect_set(shape_t *shape, co_aix x, co_aix y,
 			co_aix w, co_aix h, co_aix rx, co_aix ry);
 /* @} */
+
+/*! \defgroup shape_image Shape of Image
+ * @{
+ */
+extern shape_t *rdman_shape_image_new(redraw_man_t *rdman,
+				      mb_img_data_t *img_data,
+				      co_aix x, co_aix y,
+				      co_aix w, co_aix h);
+extern void sh_image_transform(shape_t *shape);
+extern void sh_image_draw(shape_t *shape, cairo_t *cr);
+extern void sh_image_set(shape_t *shape, co_aix x, co_aix y,
+			 co_aix w, co_aix h);
+/* @} */
 /* @} */
 
 #endif /* __SHAPES_H_ */
--- a/include/mb_types.h	Thu Jan 15 02:15:35 2009 +0800
+++ b/include/mb_types.h	Thu Jan 15 16:46:47 2009 +0800
@@ -40,7 +40,8 @@
        MBO_SHAPES=0x1000,	/*! \note Don't touch this.  */
        MBO_PATH,
        MBO_TEXT,
-       MBO_RECT
+       MBO_RECT,
+       MBO_IMAGE
 };
 #define MBO_CLASS_MASK 0xf000
 #define MBO_CLASS(x) (((mb_obj_t *)(x))->obj_type & MBO_CLASS_MASK)
@@ -197,6 +198,7 @@
     } while(0)
 #define coord_show(co) do { co->flags &= ~COF_HIDDEN; } while(0)
 #define coord_get_mouse_event(coord) ((coord)->mouse_event)
+#define coord_get_aggr_matrix(coord) ((coord)->aggr_matrix)
 #define FOR_COORDS_POSTORDER(coord, cur)			\
     for((cur) = postorder_coord_subtree((coord), NULL);		\
 	(cur) != NULL;						\
@@ -270,6 +272,7 @@
 #define sh_clear_flags(sh, mask) geo_clear_flags(sh_get_geo(sh), mask)
 #define sh_pos_is_in(sh, x, y) geo_pos_is_in(sh_get_geo(sh), x, y)
 #define sh_get_area(sh) geo_get_area(sh_get_geo(sh))
+#define sh_get_coord(sh) ((sh)->coord)
 
 
 /*! \brief A sprite is a set of graphics that being an object in animation.
--- a/src/Makefile.am	Thu Jan 15 02:15:35 2009 +0800
+++ b/src/Makefile.am	Thu Jan 15 16:46:47 2009 +0800
@@ -8,7 +8,7 @@
 	observer.c paint.c redraw_man.c rotate.c shape_path.c		\
 	shape_rect.c shape_text.c shift.c subtree_free.c timer.c 	\
 	timertool.c tools.c visibility.c X_supp.c prop.c sprite.c	\
-	mouse.c
+	mouse.c shape_image.c img_ldr.c
 libmbfly_la_CPPFLAGS = @cairo_CFLAGS@
 libmbfly_la_LDFLAGS = @cairo_LIBS@
 
--- a/src/Makefile.pmake	Thu Jan 15 02:15:35 2009 +0800
+++ b/src/Makefile.pmake	Thu Jan 15 16:46:47 2009 +0800
@@ -1,7 +1,8 @@
 SRCS =	coord.c geo.c shape_path.c shape_text.c shape_rect.c \
+     	shape_image.c \
 	redraw_man.c timer.c animate.c paint.c event.c observer.c \
 	X_supp.c timertool.c tools.c shift.c chgcolor.c \
-	visibility.c rotate.c prop.c mouse.c
+	visibility.c rotate.c prop.c mouse.c img_ldr.c
 OBJS = ${SRCS:C/(.*)\.c/\1.o/g}
 TESTCASE_SRCS = ${SRCS:C/X_supp\.c//}
 TESTCASE_OBJS = ${TESTCASE_SRCS:C/(.*)\.c/testcase-\1.o/g}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/img_ldr.c	Thu Jan 15 16:46:47 2009 +0800
@@ -0,0 +1,125 @@
+#include <stdio.h>
+#include <string.h>
+#include <cairo.h>
+#include "mb_tools.h"
+#include "mb_img_ldr.h"
+
+/*! \brief Simple image loader.
+ *
+ */
+struct _simple_mb_img_ldr {
+    mb_img_ldr_t ldr;
+    const char *repo;		/*!< \brief The directory of repository. */
+};
+typedef struct _simple_mb_img_ldr simple_mb_img_ldr_t;
+
+struct _simple_mb_img_data {
+    mb_img_data_t img;
+    cairo_surface_t *surf;
+};
+typedef struct _simple_mb_img_data simple_mb_img_data_t;
+
+static void simple_mb_img_ldr_img_free(mb_img_data_t *img);
+
+static
+mb_img_data_t *simple_mb_img_ldr_load(mb_img_ldr_t *ldr, const char *img_id) {
+    simple_mb_img_ldr_t *sldr = (simple_mb_img_ldr_t *)ldr;
+    simple_mb_img_data_t *img;
+    cairo_surface_t *surf;
+    char *fname;
+    cairo_format_t fmt;
+    int sz;
+
+    sz = strlen(sldr->repo);
+    sz += strlen(img_id);
+    fname = (char *)malloc(sz + 2);
+    strcpy(fname, sldr->repo);
+    strcat(fname, img_id);
+    
+    surf = cairo_image_surface_create_from_png(fname);
+    if(surf == NULL)
+	return NULL;
+
+    img = O_ALLOC(simple_mb_img_data_t);
+    if(img == NULL) {
+	cairo_surface_destroy(surf);
+	return NULL;
+    }
+    img->img.content = cairo_image_surface_get_data(surf);
+    img->img.width = cairo_image_surface_get_width(surf);
+    img->img.height = cairo_image_surface_get_height(surf);
+    img->img.stride = cairo_image_surface_get_stride(surf);
+    fmt = cairo_image_surface_get_format(surf);
+    switch(fmt) {
+    case CAIRO_FORMAT_ARGB32:
+	img->img.fmt = MB_IFMT_ARGB32;
+	break;
+	
+    case CAIRO_FORMAT_RGB24:
+	img->img.fmt = MB_IFMT_RGB24;
+	break;
+	
+    case CAIRO_FORMAT_A8:
+	img->img.fmt = MB_IFMT_A8;
+	break;
+	
+    case CAIRO_FORMAT_A1:
+	img->img.fmt = MB_IFMT_A1;
+	break;
+	
+    default:
+	cairo_surface_destroy(surf);
+	free(img);
+	return NULL;
+    }
+    img->img.free = simple_mb_img_ldr_img_free;
+    img->surf = surf;
+
+    return (mb_img_data_t *)img;
+}
+
+static
+void simple_mb_img_ldr_img_free(mb_img_data_t *img) {
+    simple_mb_img_data_t *simg = (simple_mb_img_data_t *)img;
+    cairo_surface_destroy((cairo_surface_t *)simg->surf);
+    free(img);
+}
+
+static
+void simple_mb_img_ldr_free(mb_img_ldr_t *ldr) {
+    simple_mb_img_ldr_t *defldr = (simple_mb_img_ldr_t *)ldr;
+
+    free((void *)defldr->repo);
+}
+
+mb_img_ldr_t *simple_mb_img_ldr_new(const char *img_repository) {
+    simple_mb_img_ldr_t *ldr;
+    int sz;
+
+    if(img_repository == NULL)
+	return NULL;
+
+    ldr = O_ALLOC(simple_mb_img_ldr_t);
+    if(ldr == NULL)
+	return NULL;
+
+    /*
+     * Copy and formalize path of image repository.
+     */
+    sz = strlen(img_repository);
+    ldr->repo = (const char *)malloc(sz + 2);
+    if(ldr->repo == NULL) {
+	free(ldr);
+	return NULL;
+    }
+    strcpy((char *)ldr->repo, img_repository);
+    if(img_repository[sz - 1] != '/') {
+	((char *)ldr->repo)[sz] = '/';
+	((char *)ldr->repo)[sz + 1] = 0;
+    }
+    
+    ldr->ldr.load = simple_mb_img_ldr_load;
+    ldr->ldr.free = simple_mb_img_ldr_free;
+    
+    return (mb_img_ldr_t *)ldr;
+}
--- a/src/redraw_man.c	Thu Jan 15 02:15:35 2009 +0800
+++ b/src/redraw_man.c	Thu Jan 15 16:46:47 2009 +0800
@@ -316,6 +316,7 @@
     subject_add_observer(rdman->root_coord->mouse_event,
 			 mouse_event_root_dummy, NULL);
 
+    mb_prop_store_init(&rdman->props, rdman->pent_pool);
     return OK;
 
  err:
@@ -341,6 +342,8 @@
     shape_t *shape, *saved_shape;
     geo_t *member;
 
+    mb_prop_store_destroy(&rdman->props);
+
     free_free_objs(rdman);
     free_objs_destroy(rdman);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/shape_image.c	Thu Jan 15 16:46:47 2009 +0800
@@ -0,0 +1,161 @@
+#include <stdio.h>
+#include <string.h>
+#include <cairo.h>
+#include "mb_types.h"
+#include "mb_shapes.h"
+#include "mb_img_ldr.h"
+#include "mb_tools.h"
+
+#define ASSERT(x)
+#define OK 0
+#define ERR -1
+
+typedef struct _sh_image {
+    shape_t shape;
+    
+    co_aix x, y;
+    co_aix w, h;
+    
+    mb_img_data_t *img_data;
+    cairo_surface_t *surf;
+} sh_image_t;
+
+static void sh_image_free(shape_t *shape);
+
+/*! \brief Creae a new image shape.
+ *
+ * \param img_data is image data whose owner-ship is transfered.
+ */
+shape_t *rdman_shape_image_new(redraw_man_t *rdman, mb_img_data_t *img_data,
+			       co_aix x, co_aix y, co_aix w, co_aix h) {
+    sh_image_t *img;
+    cairo_format_t fmt;
+
+    img = O_ALLOC(sh_image_t);
+    if(img == NULL)
+	return NULL;
+
+    memset(img, 0, sizeof(sh_image_t));
+    
+    img->shape.free = sh_image_free;
+    mb_obj_init((mb_obj_t *)img, MBO_IMAGE);
+    img->x = x;
+    img->y = y;
+    img->w = w;
+    img->h = h;
+    img->img_data = img_data;
+
+    switch(img_data->fmt) {
+    case MB_IFMT_ARGB32:
+	fmt = CAIRO_FORMAT_ARGB32;
+	break;
+
+    case MB_IFMT_RGB24:
+	fmt = CAIRO_FORMAT_RGB24;
+	break;
+
+    case MB_IFMT_A8:
+	fmt = CAIRO_FORMAT_A8;
+	break;
+
+    case MB_IFMT_A1:
+	fmt = CAIRO_FORMAT_A1;
+	break;
+    
+    case MB_IFMT_RGB16_565:
+	fmt = CAIRO_FORMAT_RGB16_565;
+	break;
+    
+    default:
+	mb_obj_destroy(img);
+	free(img);
+	return NULL;
+    }
+    
+    img->surf = cairo_image_surface_create_for_data(img_data->content,
+						    fmt,
+						    img_data->width,
+						    img_data->height,
+						    img_data->stride);
+    if(img->surf == NULL) {
+	mb_obj_destroy(img);
+	free(img);
+	return NULL;
+    }
+    
+    return (shape_t *)img;
+}
+
+void sh_image_free(shape_t *shape) {
+    sh_image_t *img = (sh_image_t *)shape;
+
+    mb_obj_destroy(shape);
+    MB_IMG_DATA_FREE(img->img_data);
+    cairo_surface_destroy(img->surf);
+    free(img);
+}
+
+void sh_image_transform(shape_t *shape) {
+    sh_image_t *img = (sh_image_t *)shape;
+    co_aix poses[4][2];
+    int i;
+
+    poses[0][0] = img->x;
+    poses[0][1] = img->y;
+    poses[1][0] = img->x + img->w;
+    poses[1][1] = img->y;
+    poses[2][0] = img->x + img->w;
+    poses[2][1] = img->y + img->h;
+    poses[3][0] = img->x;
+    poses[3][1] = img->y + img->h;
+    for(i = 0; i < 4; i++)
+	coord_trans_pos(img->shape.coord, &poses[i][0], &poses[i][1]);
+    
+    geo_from_positions(sh_get_geo(shape), 4, poses);
+}
+
+/*! \brief Draw image for an image shape.
+ *
+ * \note Image is not rescaled for size of the shape.
+ */
+void sh_image_draw(shape_t *shape, cairo_t *cr) {
+    sh_image_t *img = (sh_image_t *)shape;
+    cairo_pattern_t *saved_source;
+    cairo_matrix_t matrix, saved_matrix;
+    co_aix *aggr;
+    
+    aggr = coord_get_aggr_matrix(sh_get_coord(shape));
+    cairo_matrix_init(&matrix,
+		      aggr[0], aggr[3],
+		      aggr[1], aggr[4],
+		      aggr[2], aggr[5]);
+
+    /* set matrix */
+    cairo_get_matrix(cr, &saved_matrix);
+    cairo_set_matrix(cr, &matrix);
+    
+    /* set source */
+    saved_source = cairo_get_source(cr);
+    cairo_pattern_reference(saved_source);
+
+    /* draw image */
+    cairo_set_source_surface(cr, img->surf, 0, 0);
+    cairo_paint(cr);
+    
+    /* restore source */
+    cairo_set_source(cr, saved_source);
+    cairo_pattern_destroy(saved_source);
+
+    /* restore matrix */
+    cairo_set_matrix(cr, &saved_matrix);
+}
+
+void sh_image_set(shape_t *shape, co_aix x, co_aix y,
+		  co_aix w, co_aix h) {
+    sh_image_t *img = (sh_image_t *)shape;
+
+    img->x = x;
+    img->y = y;
+    img->w = w;
+    img->h = h;
+}
--- a/tools/mb_c_header.m4	Thu Jan 15 02:15:35 2009 +0800
+++ b/tools/mb_c_header.m4	Thu Jan 15 16:46:47 2009 +0800
@@ -20,6 +20,9 @@
 define([ADD_TEXT],[
 [    shape_t *$1;
 ]])
+define([ADD_IMAGE],[
+[    shape_t *$1;
+]])
 define([COLOR_STOP],[ ])
 
 define([REF_STOPS_RADIAL],)
--- a/tools/mb_c_source.m4	Thu Jan 15 02:15:35 2009 +0800
+++ b/tools/mb_c_source.m4	Thu Jan 15 16:46:47 2009 +0800
@@ -20,6 +20,7 @@
 define([ADD_RECT])
 define([ADD_COORD])
 define([ADD_TEXT],)
+define([ADD_IMAGE],)
 define([FILL_SHAPE])
 define([STROKE_SHAPE])
 define([FILL_SHAPE_WITH_PAINT])
--- a/tools/svg2code.py	Thu Jan 15 02:15:35 2009 +0800
+++ b/tools/svg2code.py	Thu Jan 15 16:46:47 2009 +0800
@@ -369,6 +369,7 @@
         pass
     pass
 
+@check_mbname
 def translate_text(text, coord_id, codefo, doc):
     translate_font_style(text, codefo)
 
@@ -394,6 +395,42 @@
         pass
     pass
 
+@check_mbname
+def translate_image(image, coord_id, codefo, doc):
+    image_id = _get_id(image)
+    if not image.hasAttribute('href'):
+        raise ValueError, 'image %s must has a href attribute.' % (image_id)
+    href = image.getAttribute('href')
+    if image.hasAttribute('x'):
+        x_str = image.getAttribute('x')
+        x = int(x_str)
+    else:
+        x = 0
+        pass
+    if image.hasAttribute('y'):
+        y_str = image.getAttribute('y')
+        y = int(y_str)
+    else:
+        y = 0
+        pass
+    if image.hasAttribute('width'):
+        width_str = image.getAttribute('width')
+        width = int(width_str)
+    else:
+        width = -1
+        pass
+    if image.hasAttribute('height'):
+        height_str = image.getAttribute('height')
+        height = int(height_str)
+    else:
+        height = -1
+        pass
+    print >> codefo, 'dnl'
+    print >> codefo, \
+        'ADD_IMAGE([%s], [%s], %f, %f, %f, %f)dnl' % (
+        image_id, href, x, y, width, height)
+    pass
+
 reo_func = re.compile('([a-zA-Z]+)\\([^\\)]*\\)')
 reo_translate = re.compile('translate\\(([-+]?[0-9]+(\\.[0-9]+)?),([-+]?[0-9]+(\\.[0-9]+)?)\\)')
 reo_matrix = re.compile('matrix\\(([-+]?[0-9]+(\\.[0-9]+)?),([-+]?[0-9]+(\\.[0-9]+)?),([-+]?[0-9]+(\\.[0-9]+)?),([-+]?[0-9]+(\\.[0-9]+)?),([-+]?[0-9]+(\\.[0-9]+)?),([-+]?[0-9]+(\\.[0-9]+)?)\\)')
@@ -448,6 +485,8 @@
             translate_rect(node, group_id, codefo, doc)
         elif node.localName == 'text':
             translate_text(node, group_id, codefo, doc)
+        elif node.localName == 'image':
+            translate_image(node, group_id, codefo, doc)
             pass
         pass
     pass