Mercurial > MadButterfly
diff src/shape_text.c @ 27:19c603dd6ff9
Add text shape.
author | Thinker K.F. Li <thinker@branda.to> |
---|---|
date | Mon, 04 Aug 2008 10:10:47 +0800 |
parents | |
children | e06a4a667ce2 |
line wrap: on
line diff
--- /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); +}