changeset 27:19c603dd6ff9

Add text shape.
author Thinker K.F. Li <thinker@branda.to>
date Mon, 04 Aug 2008 10:10:47 +0800
parents d50f33040de6
children 604bc90d509d
files src/Makefile src/X_main.c src/redraw_man.c src/shape_text.c src/shapes.h
diffstat 5 files changed, 232 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/src/Makefile	Sun Aug 03 13:04:55 2008 +0800
+++ b/src/Makefile	Mon Aug 04 10:10:47 2008 +0800
@@ -1,4 +1,4 @@
-SRCS =	coord.c geo.c shape_path.c redraw_man.c paint.c tools.c
+SRCS =	coord.c geo.c shape_path.c shape_text.c redraw_man.c paint.c tools.c
 OBJS = ${SRCS:C/(.*)\.c/\1.o/g}
 TESTCASE_OBJS = ${SRCS:C/(.*)\.c/testcase-\1.o/g}
 CFLAGS+=	-Wall -I/usr/local/include `pkg-config --cflags cairo`
--- a/src/X_main.c	Sun Aug 03 13:04:55 2008 +0800
+++ b/src/X_main.c	Mon Aug 04 10:10:47 2008 +0800
@@ -17,22 +17,35 @@
     cairo_surface_t *tmpsuf;
     redraw_man_t rdman;
     shape_t *path1, *path2, *path3;
-    coord_t *coord1, *coord2;
+    coord_t *coord1, *coord2, *coord3;
     paint_t *fill1, *fill2, *fill3;
-    paint_t *stroke;
+    paint_t *stroke, *text_stroke;
+    shape_t *text;
     grad_stop_t fill3_stops[3];
+    cairo_font_face_t *face;
     int i;
 
     tmpsuf = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h);
     tmpcr = cairo_create(tmpsuf);
+
     cairo_set_source_surface(cr, tmpsuf, 0, 0);
     redraw_man_init(&rdman, tmpcr, cr);
     coord1 = rdman_coord_new(&rdman, rdman.root_coord);
     coord2 = rdman_coord_new(&rdman, rdman.root_coord);
+    coord3 = rdman_coord_new(&rdman, rdman.root_coord);
 
     fill1 = paint_color_new(&rdman, 1, 1, 0, 0.5);
     fill2 = paint_color_new(&rdman, 0, 1, 1, 0.5);
     stroke = paint_color_new(&rdman, 0.4, 0.4, 0.4, 1);
+    text_stroke = paint_color_new(&rdman, 0.5, 0.5, 0.5, 1);
+
+    face = cairo_get_font_face(tmpcr);
+    text = sh_text_new("hello \xe6\xbc\xa2\xe5\xad\x97", 10, h / 4,
+		       36.0, face);
+    rdman_paint_stroke(&rdman, text_stroke, text);
+    text->stroke_width = 0.5;
+    rdman_add_shape(&rdman, text, coord3);
+
     path1 = sh_path_new("M 22,89.36218 C -34,-0.63782 39,-9.637817 82,12.36218 C 125,34.36218 142,136.36218 142,136.36218 C 100.66667,125.36218 74.26756,123.42795 22,89.36218 z ");
     rdman_paint_fill(&rdman, fill1, path1);
     rdman_paint_stroke(&rdman, stroke, path1);
@@ -41,6 +54,7 @@
     coord1->matrix[2] = 20;
     coord1->matrix[4] = 0.8;
     coord1->matrix[5] = 20;
+
     path2 = sh_path_new("M 22,89.36218 C -34,-0.63782 39,-9.637817 82,12.36218 C 125,34.36218 142,136.36218 142,136.36218 C 100.66667,125.36218 74.26756,123.42795 22,89.36218 z ");
     rdman_paint_fill(&rdman, fill2, path2);
     rdman_paint_stroke(&rdman, stroke, path2);
@@ -49,6 +63,7 @@
     coord2->matrix[2] = 180;
     coord2->matrix[4] = 0.8;
     coord2->matrix[5] = 20;
+
     rdman_coord_changed(&rdman, coord1);
     rdman_coord_changed(&rdman, coord2);
     rdman_add_shape(&rdman, (shape_t *)path1, coord1);
@@ -115,11 +130,52 @@
 	XFlush(display);
     }
 
+    for(i = 0; i < 4; i++) {
+	usleep(500000);
+	text->stroke_width += 1;
+	rdman_shape_changed(&rdman, text);
+	coord3->matrix[2] += 5;
+	rdman_coord_changed(&rdman, coord3);
+	rdman_redraw_changed(&rdman);
+	XFlush(display);
+    }
+    for(i = 0; i < 4; i++) {
+	usleep(500000);
+	text->stroke_width -= 1;
+	rdman_shape_changed(&rdman, text);
+	coord3->matrix[2] -= 5;
+	rdman_coord_changed(&rdman, coord3);
+	rdman_redraw_changed(&rdman);
+	XFlush(display);
+    }
+
+    for(i = 0; i < 4; i++) {
+	usleep(500000);
+	text->stroke_width += 1;
+	rdman_shape_changed(&rdman, text);
+	coord3->matrix[5] += 5;
+	rdman_coord_changed(&rdman, coord3);
+	rdman_redraw_changed(&rdman);
+	XFlush(display);
+    }
+    for(i = 0; i < 4; i++) {
+	usleep(500000);
+	text->stroke_width -= 1;
+	rdman_shape_changed(&rdman, text);
+	coord3->matrix[5] -= 5;
+	rdman_coord_changed(&rdman, coord3);
+	rdman_redraw_changed(&rdman);
+	XFlush(display);
+    }
+
     fill1->free(fill1);
     fill2->free(fill2);
+    stroke->free(stroke);
+    text_stroke->free(text_stroke);
     redraw_man_destroy(&rdman);
     sh_path_free(path1);
     sh_path_free(path2);
+    sh_text_free(text);
     cairo_destroy(tmpcr);
     cairo_surface_destroy(tmpsuf);
 }
@@ -130,14 +186,8 @@
     cr = cairo_create(surface);
     cairo_set_source_rgb(cr, 0, 0, 0);
     cairo_paint(cr);
-    cairo_set_source_rgb(cr, 0.9, 0.1, 0.1);
     draw_path(cr, w, h);
-    cairo_set_source_rgb(cr, 0.5, 0.9, 0.8);
-    cairo_move_to(cr, 10, h / 2);
-    cairo_set_font_size(cr, 36.0);
-    cairo_text_path(cr, "hello \xe6\xbc\xa2\xe5\xad\x97");
-    cairo_set_line_width(cr, 2);
-    cairo_stroke(cr);
+    cairo_destroy(cr);
 }
 
 int
--- a/src/redraw_man.c	Sun Aug 03 13:04:55 2008 +0800
+++ b/src/redraw_man.c	Mon Aug 04 10:10:47 2008 +0800
@@ -98,6 +98,9 @@
     case SHT_PATH:
 	sh_path_transform(shape);
 	break;
+    case SHT_TEXT:
+	sh_text_transform(shape);
+	break;
 #ifdef UNITTEST
     default:
 	sh_dummy_transform(shape);
@@ -483,6 +486,9 @@
 	case SHT_PATH:
 	    sh_path_fill(shape, rdman->cr);
 	    break;
+	case SHT_TEXT:
+	    sh_text_fill(shape, rdman->cr);
+	    break;
 #ifdef UNITTEST
 	default:
 	    sh_dummy_fill(shape, rdman->cr);
@@ -498,6 +504,9 @@
 	case SHT_PATH:
 	    sh_path_stroke(shape, rdman->cr);
 	    break;
+	case SHT_TEXT:
+	    sh_text_stroke(shape, rdman->cr);
+	    break;
 #ifdef UNITTEST
 	default:
 	    /* sh_dummy_fill(shape, rdman->cr); */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/shape_text.c	Mon Aug 04 10:10:47 2008 +0800
@@ -0,0 +1,144 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <cairo.h>
+#include "mb_types.h"
+#include "shapes.h"
+
+#define OK 0
+#define ERR -1
+
+typedef struct _sh_text {
+    shape_t shape;
+    char *data;
+    co_aix x, y;
+    co_aix d_x, d_y;		/* device x and y */
+    co_aix font_size;
+    cairo_font_face_t *face;
+    cairo_scaled_font_t *scaled_font;
+    int flags;
+} sh_text_t;
+
+#define TXF_SCALE_DIRTY 0x1
+
+shape_t *sh_text_new(const char *txt, co_aix x, co_aix y,
+		     co_aix font_size, cairo_font_face_t *face) {
+    sh_text_t *text;
+
+    text = (sh_text_t *)malloc(sizeof(sh_text_t));
+    if(text == NULL)
+	return NULL;
+
+    memset(text, 0, sizeof(sh_text_t));
+    text->shape.sh_type = SHT_TEXT;
+    text->data = strdup(txt);
+    if(text->data == NULL) {
+	free(text);
+	return NULL;
+    }
+    text->x = x;
+    text->y = y;
+    text->font_size = font_size;
+    cairo_font_face_reference(face);
+    text->face = face;
+    text->flags |= TXF_SCALE_DIRTY;
+
+    return (shape_t *)text;
+}
+
+void sh_text_free(shape_t *shape) {
+    sh_text_t *text = (sh_text_t *)shape;
+
+    if(text->scaled_font)
+	cairo_scaled_font_destroy(text->scaled_font);
+    cairo_font_face_destroy(text->face);
+}
+
+static int get_extents(sh_text_t *text, cairo_text_extents_t *extents) {
+    cairo_matrix_t fmatrix;
+    cairo_matrix_t ctm;
+    cairo_scaled_font_t *new_scaled;
+    cairo_font_options_t *fopt;
+
+    if((text->flags & TXF_SCALE_DIRTY) ||
+       text->scaled_font == NULL) {
+	fopt = cairo_font_options_create();
+	if(fopt == NULL)
+	    return ERR;
+	memset(&fmatrix, 0, sizeof(cairo_matrix_t));
+	fmatrix.xx = text->font_size;
+	fmatrix.yy = text->font_size;
+	memset(&ctm, 0, sizeof(cairo_matrix_t));
+	ctm.xx = 1;
+	ctm.yy = 1;
+	new_scaled = cairo_scaled_font_create(text->face,
+					      &fmatrix,
+					      &ctm,
+					      fopt);
+	cairo_font_options_destroy(fopt);
+	if(new_scaled == NULL)
+	    return ERR;
+
+	if(text->scaled_font)
+	    cairo_scaled_font_destroy(text->scaled_font);
+	text->scaled_font = new_scaled;
+	text->flags &= ~TXF_SCALE_DIRTY;
+    }
+
+    cairo_scaled_font_text_extents(text->scaled_font,
+				   text->data, extents);
+    return OK;
+}
+
+void sh_text_transform(shape_t *shape) {
+    sh_text_t *text;
+    co_aix x, y;
+    co_aix shw;
+    cairo_text_extents_t extents;
+    co_aix poses[2][2];
+    int r;
+
+    text = (sh_text_t *)shape;
+    x = text->x;
+    y = text->y;
+    coord_trans_pos(shape->coord, &x, &y);
+    r = get_extents(text, &extents);
+    if(r != OK)
+	/* TODO: announce error. change return type? */
+	return;
+
+    text->d_x = x;
+    text->d_y = y;
+    shw = shape->stroke_width / 2;
+    /* FIXME: It is unreasonable that a font exceed it's bbox.
+     * We add 5 pixels in get right bbox.  But, it is unreasonable.
+     */
+    poses[0][0] = x + extents.x_bearing - 5 - shw;
+    poses[0][1] = y + extents.y_bearing - 5 - shw;
+    poses[1][0] = poses[0][0] + extents.width + 10 + shape->stroke_width;
+    poses[1][1] = poses[0][1] + extents.height + 10 + shape->stroke_width;
+    geo_from_positions(shape->geo, 2, poses);
+}
+
+
+static void draw_text(sh_text_t *text, cairo_t *cr) {
+    cairo_set_scaled_font(cr, text->scaled_font);
+    cairo_move_to(cr, text->d_x, text->d_y);
+    cairo_text_path(cr, text->data);
+}
+
+
+void sh_text_fill(shape_t *shape, cairo_t *cr) {
+    sh_text_t *text = (sh_text_t *)shape;
+
+    draw_text(text, cr);
+    cairo_fill(cr);
+}
+
+
+void sh_text_stroke(shape_t *shape, cairo_t *cr) {
+    sh_text_t *text = (sh_text_t *)shape;
+
+    draw_text(text, cr);
+    cairo_stroke(cr);
+}
--- a/src/shapes.h	Sun Aug 03 13:04:55 2008 +0800
+++ b/src/shapes.h	Mon Aug 04 10:10:47 2008 +0800
@@ -4,10 +4,29 @@
 #include <cairo.h>
 #include "mb_types.h"
 
+/* Define a shape
+ *
+ * A shape must include
+ * - *_new() and *_free()
+ * - *_transform()
+ * - *_fill()
+ * - *_stroke()
+ * - struct of shape must include an shape_t as type of first member.
+ */
+
 extern void sh_path_free(shape_t *path);
 extern shape_t *sh_path_new(char *data);
 extern void sh_path_transform(shape_t *shape);
 extern void sh_path_fill(shape_t *shape, cairo_t *cr);
 extern void sh_path_stroke(shape_t *shape, cairo_t *cr);
 
+
+extern void sh_text_free(shape_t *text);
+extern shape_t *sh_text_new(const char *txt, co_aix x, co_aix y,
+			    co_aix font_size, cairo_font_face_t *face);
+extern void sh_text_transform(shape_t *shape);
+extern void sh_text_fill(shape_t *shape, cairo_t *cr);
+extern void sh_text_stroke(shape_t *shape, cairo_t *cr);
+
+
 #endif /* __SHAPES_H_ */