summaryrefslogtreecommitdiff
path: root/src/sim/sim_text.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/sim/sim_text.c')
-rw-r--r--src/sim/sim_text.c371
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++;
+ }
+}