/** \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 }; static char* get_version_attrib(cdCtxCanvas* ctxcanvas) { static char version[50]; FT_Int major, minor, patch; cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas; FT_Library_Version(canvas->simulation->tt_text->library, &major, &minor, &patch); sprintf(version, "FreeType %d.%d.%d", major, minor, patch); return version; } static cdAttribute version_attrib = { "FREETYPEVERSION", NULL, get_version_attrib }; void cdSimInitText(cdSimulation* simulation) { if (!simulation->tt_text) simulation->tt_text = cdTT_create(); cdRegisterAttribute(simulation->canvas, &addfontmap_attrib); cdRegisterAttribute(simulation->canvas, &version_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 cdSimFontFT(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 cdSimGetFontDimFT(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 cdSimGetTextSizeFT(cdCtxCanvas* ctxcanvas, const char *s, int len, int *width, int *height) { cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas; cdSimulation* simulation = canvas->simulation; int i = 0, 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(i < len) { /* load glyph image into the slot (erase previous one) */ error = FT_Load_Char( face, (unsigned char)s[i], FT_LOAD_DEFAULT ); if (error) {i++; continue;} /* ignore errors */ w += slot->advance.x; i++; } 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 old_use_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; /* this is the char bitmap, contains an alpha map of the char to be combined with the foreground color */ bitmap_data = bitmap->buffer + (height-1)*width; /* bitmap is top down. */ /* this is the image used to draw the char with the foreground color */ 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, fg_alpha, calpha; long int c; /* must manually combine using only the background color, ignore canvas contents */ 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); fg_alpha = cdAlpha(c); for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { if (simulation->antialias) { if (fg_alpha == 255) calpha = bitmap_data[j]; else calpha = (fg_alpha*bitmap_data[j])/255; } else { if (bitmap_data[j] > 128) /* behave as 255 */ calpha = fg_alpha; else calpha = 0; } *red++ = CD_ALPHA_BLEND(fg_red, bg_red, calpha); *green++ = CD_ALPHA_BLEND(fg_green, bg_green, calpha); *blue++ = CD_ALPHA_BLEND(fg_blue, bg_blue, calpha); } bitmap_data -= width; } /* reset pointers */ red = simulation->tt_text->rgba_data; green = red + size; blue = green + size; /* draw the char */ simulation->canvas->cxPutImageRectRGB(simulation->canvas->ctxcanvas, width,height,red,green,blue,x,y,width,height,0,width-1,0,height-1); } else { int i, j; long int fg = simulation->canvas->foreground; unsigned char fg_alpha = cdAlpha(fg); memset(red, cdRed(fg), size); memset(green, cdGreen(fg), size); memset(blue, cdBlue(fg), size); /* alpha is the bitmap_data itself if the foreground color does not contains alpha. Also must invert since it is top-down. */ for (i = 0; i < height; i++) { if (simulation->antialias) { if (fg_alpha == 255) { memcpy(alpha, bitmap_data, width); alpha += width; } else { for (j = 0; j < width; j++) { *alpha++ = (fg_alpha*bitmap_data[j])/255; } } } else { for (j = 0; j < width; j++) { if (bitmap_data[j] > 128) /* behave as 255 */ *alpha++ = fg_alpha; else *alpha++ = 0; } } bitmap_data -= width; } /* reset alpha pointer */ alpha = blue + size; /* draw the char */ 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 = old_use_matrix; } void simGetPenPos(cdCanvas* canvas, int x, int y, const char* s, int len, FT_Matrix *matrix, FT_Vector *pen) { int ox = x, oy = y; int old_invert_yaxis = canvas->invert_yaxis; int w, h, ascent, height, baseline; cdSimGetTextSizeFT(canvas->ctxcanvas, s, len, &w, &h); cdSimGetFontDimFT(canvas->ctxcanvas, 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) { 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 cdSimTextFT(cdCtxCanvas* ctxcanvas, int x, int y, const char* s, int len) { 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; int i = 0; 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, len, &matrix, &pen); while(ibitmap_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; i++; } }