diff options
Diffstat (limited to 'src/sim/sim_text.c')
-rw-r--r-- | src/sim/sim_text.c | 371 |
1 files changed, 371 insertions, 0 deletions
diff --git a/src/sim/sim_text.c b/src/sim/sim_text.c new file mode 100644 index 0000000..3ea7aef --- /dev/null +++ b/src/sim/sim_text.c @@ -0,0 +1,371 @@ +/** \file + * \brief Text and Font Functions of the Simulation Base Driver + * + * See Copyright Notice in cd.h + */ + +#include <stdlib.h> +#include <stdio.h> +#include <math.h> +#include <memory.h> +#include <ctype.h> + +#include "cd.h" +#include "cd_private.h" +#include "cd_truetype.h" +#include "sim.h" +#include FT_GLYPH_H + + +static int font_name_match(const char* map, const char* name) +{ + while (*map != '=') + { + if (tolower(*map) != tolower(*name)) + return 0; + + map++; + name++; + } + + return 1; +} + +static void cdSimAddFontMap(cdSimulation* simulation, const char* map) +{ + int i; + + if (!strstr(map, "=")) + return; + + for (i = 0; i < simulation->font_map_n; i++) + { + if (font_name_match(simulation->font_map[i], map)) + { + /* replace */ + simulation->font_map[i] = map; + return; + } + } + + /* not found add */ + simulation->font_map[i] = map; + simulation->font_map_n++; +} + +static void set_addfontmap(cdCtxCanvas* ctxcanvas, char* data) +{ + if (data) + { + cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas; + cdSimAddFontMap(canvas->simulation, data); + } +} + +static cdAttribute addfontmap_attrib = +{ + "ADDFONTMAP", + set_addfontmap, + NULL +}; + +void cdSimInitText(cdSimulation* simulation) +{ + if (!simulation->tt_text) + simulation->tt_text = cdTT_create(); + + cdRegisterAttribute(simulation->canvas, &addfontmap_attrib); +} + +static const char* find_font_filename(cdSimulation* simulation, const char* name) +{ + int i; + for (i = 0; i < simulation->font_map_n; i++) + { + if (font_name_match(simulation->font_map[i], name)) + return strstr(simulation->font_map[i], "=")+1; + } + return NULL; +} + +int cdfontSIM(cdCtxCanvas* ctxcanvas, const char *type_face, int style, int size) +{ + cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas; + + /* check for the pre-defined names */ + if (cdStrEqualNoCase(type_face, "System")) + type_face = "cour"; + else if (cdStrEqualNoCase(type_face, "Courier")) + type_face = "cour"; + else if (cdStrEqualNoCase(type_face, "Times")) + type_face = "times"; + else if (cdStrEqualNoCase(type_face, "Helvetica")) + type_face = "arial"; + else + { + /* use the font map */ + const char* filename = find_font_filename(canvas->simulation, type_face); + if (filename) + return cdTT_load(canvas->simulation->tt_text, filename, cdGetFontSizePoints(canvas, size), canvas->xres, canvas->yres); + else + { + /* try the type_face name without change */ + if (cdTT_load(canvas->simulation->tt_text, type_face, cdGetFontSizePoints(canvas, size), canvas->xres, canvas->yres)) + return 1; + } + } + + { + static char * cd_ttf_font_style[4] = { + "", + "bd", + "i", + "bi"}; + char font[10240]; /* can have a path */ + sprintf(font, "%s%s", type_face, cd_ttf_font_style[style&3]); + return cdTT_load(canvas->simulation->tt_text, font, cdGetFontSizePoints(canvas, size), canvas->xres, canvas->yres); + } +} + +void cdgetfontdimSIM(cdCtxCanvas* ctxcanvas, int *max_width, int *height, int *ascent, int *descent) +{ + cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas; + cdSimulation* simulation = canvas->simulation; + + if (!simulation->tt_text->face) + return; + + if(ascent) *ascent = simulation->tt_text->ascent; + if(descent) *descent= simulation->tt_text->descent; + if(max_width) *max_width= simulation->tt_text->max_width; + if(height) *height= simulation->tt_text->max_height; +} + +void cdgettextsizeSIM(cdCtxCanvas* ctxcanvas, const char *s, int *width, int *height) +{ + cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas; + cdSimulation* simulation = canvas->simulation; + int w = 0; + FT_Face face; + FT_GlyphSlot slot; + FT_Error error; + + if (!simulation->tt_text->face) + return; + + face = simulation->tt_text->face; + slot = face->glyph; + + /* set transformation */ + FT_Set_Transform( face, NULL, NULL ); + + while(*s) + { + /* load glyph image into the slot (erase previous one) */ + error = FT_Load_Char( face, *(unsigned char*)s, FT_LOAD_DEFAULT ); + if (error) {s++; continue;} /* ignore errors */ + + w += slot->advance.x; + + s++; + } + + if (height) *height = simulation->tt_text->max_height; + if (width) *width = w >> 6; +} + +static void simDrawTextBitmap(cdSimulation* simulation, FT_Bitmap* bitmap, int x, int y) +{ + unsigned char *red, *green, *blue, *alpha, *bitmap_data; + int width = bitmap->width; + int height = bitmap->rows; + int size = width*height; + int rgba_data_size = size*4; + int olduse_matrix = simulation->canvas->use_matrix; + + /* avoid spaces */ + if (width == 0 || height == 0) + return; + + if (!simulation->tt_text->rgba_data) + simulation->tt_text->rgba_data = malloc(rgba_data_size); + else if (rgba_data_size > simulation->tt_text->rgba_data_size) + { + simulation->tt_text->rgba_data = realloc(simulation->tt_text->rgba_data, rgba_data_size); + simulation->tt_text->rgba_data_size = rgba_data_size; + } + + /* disable image transformation */ + simulation->canvas->use_matrix = 0; + + bitmap_data = bitmap->buffer + (height-1)*width; /* bitmap is top down. */ + red = simulation->tt_text->rgba_data; + green = red + size; + blue = green + size; + alpha = blue + size; + + if (!simulation->canvas->cxPutImageRectRGBA && !simulation->canvas->cxGetImageRGB) + { + int i, j; + unsigned char bg_red, bg_green, bg_blue, fg_red, fg_green, fg_blue; + long int c; + c = simulation->canvas->background; + bg_red = cdRed(c); + bg_green = cdGreen(c); + bg_blue = cdBlue(c); + c = simulation->canvas->foreground; + fg_red = cdRed(c); + fg_green = cdGreen(c); + fg_blue = cdBlue(c); + + for (i = 0; i < height; i++) + { + for (j = 0; j < width; j++) + { + *red++ = (fg_red*bitmap_data[j] + bg_red*(255-bitmap_data[j]))/255; + *green++ = (fg_green*bitmap_data[j] + bg_green*(255-bitmap_data[j]))/255; + *blue++ = (fg_blue*bitmap_data[j] + bg_blue*(255-bitmap_data[j]))/255; + } + + bitmap_data -= width; + } + + red = simulation->tt_text->rgba_data; + green = red + size; + blue = green + size; + simulation->canvas->cxPutImageRectRGB(simulation->canvas->ctxcanvas, width,height,red,green,blue,x,y,width,height,0,width-1,0,height-1); + } + else + { + int i; + long int fg = simulation->canvas->foreground; + memset(red, cdRed(fg), size); + memset(green, cdGreen(fg), size); + memset(blue, cdBlue(fg), size); + for (i = 0; i < height; i++) + { + memcpy(alpha, bitmap_data, width); + alpha += width; + bitmap_data -= width; + } + + alpha = blue + size; + simulation->canvas->cxPutImageRectRGBA(simulation->canvas->ctxcanvas, width,height,red,green,blue,alpha,x,y,width,height,0,width-1,0,height-1); + } + + simulation->canvas->use_matrix = olduse_matrix; +} + +void simGetPenPos(cdCanvas* canvas, int x, int y, const char* s, FT_Matrix *matrix, FT_Vector *pen) +{ + int ox = x, oy = y; + int old_invert_yaxis = canvas->invert_yaxis; + int w, h, ascent, height, baseline; + + cdCanvasGetTextSize(canvas, s, &w, &h); + cdCanvasGetFontDim(canvas, NULL, &height, &ascent, NULL); + baseline = height - ascent; + + /* in this case we are always upwards */ + + /* move to bottom left */ + canvas->invert_yaxis = 0; + cdTextTranslatePoint(canvas, x, y, w, h, baseline, &x, &y); + canvas->invert_yaxis = old_invert_yaxis; + + /* move to the base line */ + y += baseline; + + /* set up matrix */ + matrix->xx = (FT_Fixed)0x10000L; + matrix->xy = (FT_Fixed)0; + matrix->yx = (FT_Fixed)0; + matrix->yy = (FT_Fixed)0x10000L; + + if (canvas->text_orientation) + { + FT_Matrix text_matrix; + double cos_theta = cos(canvas->text_orientation*CD_DEG2RAD); + double sin_theta = sin(canvas->text_orientation*CD_DEG2RAD); + + /* manually rotate the initial point */ + canvas->invert_yaxis = 0; + cdRotatePoint(canvas, x, y, ox, oy, &x, &y, sin_theta, cos_theta); + canvas->invert_yaxis = old_invert_yaxis; + + text_matrix.xx = (FT_Fixed)( cos_theta*0x10000L); + text_matrix.xy = (FT_Fixed)(-sin_theta*0x10000L); + text_matrix.yx = (FT_Fixed)( sin_theta*0x10000L); + text_matrix.yy = (FT_Fixed)( cos_theta*0x10000L); + + FT_Matrix_Multiply(&text_matrix, matrix); + } + + if (canvas->use_matrix && !canvas->invert_yaxis) + { + FT_Matrix trans_matrix; + trans_matrix.xx = (FT_Fixed)(canvas->matrix[0]*0x10000L); + trans_matrix.yx = (FT_Fixed)(canvas->matrix[1]*0x10000L); + trans_matrix.xy = (FT_Fixed)(canvas->matrix[2]*0x10000L); + trans_matrix.yy = (FT_Fixed)(canvas->matrix[3]*0x10000L); + + FT_Matrix_Multiply(&trans_matrix, matrix); + + /* manually transform the initial point */ + cdMatrixTransformPoint(canvas->matrix, x, y, &x, &y); + } + + /* the pen position in 26.6 scale */ + pen->x = x * 64; + pen->y = y * 64; + +} + +void cdtextSIM(cdCtxCanvas* ctxcanvas, int x, int y, const char * s) +{ + cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas; + cdSimulation* simulation = canvas->simulation; + FT_Face face; + FT_GlyphSlot slot; + FT_Matrix matrix; /* transformation matrix */ + FT_Vector pen; /* untransformed origin */ + FT_Error error; + + if (!simulation->tt_text->face) + return; + + face = simulation->tt_text->face; + slot = face->glyph; + + /* the pen position is in cartesian space coordinates */ + if (simulation->canvas->invert_yaxis) + y = _cdInvertYAxis(canvas, y); /* y is already inverted, invert back to cartesian space */ + + /* move the reference point to the baseline-left */ + simGetPenPos(simulation->canvas, x, y, s, &matrix, &pen); + + while(*s) + { + /* set transformation */ + FT_Set_Transform(face, &matrix, &pen); + + /* load glyph image into the slot (erase previous one) */ + error = FT_Load_Char(face, *(unsigned char*)s, FT_LOAD_RENDER); + if (error) {s++; continue;} /* ignore errors */ + + x = slot->bitmap_left; + y = slot->bitmap_top-slot->bitmap.rows; /* CD image reference point is at bottom-left */ + + if (canvas->invert_yaxis) + y = _cdInvertYAxis(canvas, y); + + /* now, draw to our target surface (convert position) */ + simDrawTextBitmap(simulation, &slot->bitmap, x, y); + + /* increment pen position */ + pen.x += slot->advance.x; + pen.y += slot->advance.y; + + s++; + } +} |