/** \file * \brief Text and Font Functions of the Simulation Base Driver * * See Copyright Notice in cd.h */ #include #include #include #include #include #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++; } }