summaryrefslogtreecommitdiff
path: root/src/cd_text.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cd_text.c')
-rw-r--r--src/cd_text.c632
1 files changed, 632 insertions, 0 deletions
diff --git a/src/cd_text.c b/src/cd_text.c
new file mode 100644
index 0000000..a06f9b1
--- /dev/null
+++ b/src/cd_text.c
@@ -0,0 +1,632 @@
+/** \file
+ * \brief External API - Text
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <memory.h>
+#include <math.h>
+
+
+#include "cd.h"
+#include "cd_private.h"
+
+
+void cdCanvasText(cdCanvas* canvas, int x, int y, const char *s)
+{
+ assert(canvas);
+ assert(s);
+ if (!_cdCheckCanvas(canvas)) return;
+
+ if (s[0] == 0)
+ return;
+
+ if (canvas->use_origin)
+ {
+ x += canvas->origin.x;
+ y += canvas->origin.y;
+ }
+
+ if (canvas->invert_yaxis)
+ y = _cdInvertYAxis(canvas, y);
+
+ canvas->cxText(canvas->ctxcanvas, x, y, s);
+}
+
+void cdfCanvasText(cdCanvas* canvas, double x, double y, const char *s)
+{
+ assert(canvas);
+ assert(s);
+ if (!_cdCheckCanvas(canvas)) return;
+
+ if (s[0] == 0)
+ return;
+
+ if (canvas->use_origin)
+ {
+ x += canvas->forigin.x;
+ y += canvas->forigin.y;
+ }
+
+ if (canvas->invert_yaxis)
+ y = _cdInvertYAxis(canvas, y);
+
+ if (canvas->cxFText)
+ canvas->cxFText(canvas->ctxcanvas, x, y, s);
+ else
+ canvas->cxText(canvas->ctxcanvas, _cdRound(x), _cdRound(y), s);
+}
+
+int cdGetFontSizePixels(cdCanvas* canvas, int size)
+{
+ if (size < 0)
+ size = -size;
+ else
+ {
+ double size_mm = (double)size/CD_MM2PT;
+ size = cdRound(size_mm*canvas->xres);
+ }
+
+ if (size == 0)
+ size = 1;
+
+ return size;
+}
+
+int cdGetFontSizePoints(cdCanvas* canvas, int size)
+{
+ if (size < 0)
+ {
+ double size_mm = ((double)-size)/canvas->xres;
+ size = cdRound(size_mm * CD_MM2PT);
+ }
+
+ if (size == 0)
+ size = 1;
+
+ return size;
+}
+
+int cdCanvasFont(cdCanvas* canvas, const char* type_face, int style, int size)
+{
+ assert(canvas);
+ assert(style>=-1 && style<=CD_STRIKEOUT);
+ if (!_cdCheckCanvas(canvas)) return CD_ERROR;
+ if (!type_face || type_face[0]==0)
+ type_face = canvas->font_type_face;
+ if (style==-1)
+ style = canvas->font_style;
+ if (size==0)
+ size = canvas->font_size;
+
+ if (strcmp(type_face, canvas->font_type_face)==0 &&
+ style == canvas->font_style &&
+ size == canvas->font_size)
+ return 1;
+
+ if (canvas->cxFont(canvas->ctxcanvas, type_face, style, size))
+ {
+ strcpy(canvas->font_type_face, type_face);
+ canvas->font_style = style;
+ canvas->font_size = size;
+ canvas->native_font[0] = 0;
+ return 1;
+ }
+
+ return 0;
+}
+
+void cdCanvasGetFont(cdCanvas* canvas, char *type_face, int *style, int *size)
+{
+ assert(canvas);
+ if (!_cdCheckCanvas(canvas)) return;
+
+ if (type_face) strcpy(type_face, canvas->font_type_face);
+ if (style) *style = canvas->font_style;
+ if (size) *size = canvas->font_size;
+}
+
+char* cdCanvasNativeFont(cdCanvas* canvas, const char* font)
+{
+ static char native_font[1024] = "";
+
+ assert(canvas);
+ if (!_cdCheckCanvas(canvas)) return NULL;
+
+ strcpy(native_font, canvas->native_font);
+
+ if (!font || font[0] == 0)
+ return native_font;
+
+ if (font == (char*)CD_QUERY)
+ {
+ char style[200] = " ";
+ if (canvas->font_style&CD_BOLD)
+ strcat(style, "Bold ");
+ if (canvas->font_style&CD_ITALIC)
+ strcat(style, "Italic ");
+ if (canvas->font_style&CD_UNDERLINE)
+ strcat(style, "Underline ");
+ if (canvas->font_style&CD_STRIKEOUT)
+ strcat(style, "Strikeout ");
+
+ sprintf(native_font, "%s,%s %d", canvas->font_type_face, style, canvas->font_size);
+ return native_font;
+ }
+
+ if (canvas->cxNativeFont)
+ {
+ if (canvas->cxNativeFont(canvas->ctxcanvas, font))
+ strcpy(canvas->native_font, font);
+ }
+ else
+ {
+ char type_face[1024];
+ int size, style = CD_PLAIN;
+
+ if (!cdParseIupWinFont(font, type_face, &style, &size))
+ {
+ if (!cdParseXWinFont(font, type_face, &style, &size))
+ {
+ if (!cdParsePangoFont(font, type_face, &style, &size))
+ return native_font;
+ }
+ }
+
+ if (cdCanvasFont(canvas, type_face, style, size))
+ strcpy(canvas->native_font, font);
+ }
+
+ return native_font;
+}
+
+int cdCanvasTextAlignment(cdCanvas* canvas, int alignment)
+{
+ int text_alignment;
+
+ assert(canvas);
+ assert(alignment==CD_QUERY || (alignment>=CD_NORTH && alignment<=CD_BASE_RIGHT));
+ if (!_cdCheckCanvas(canvas)) return CD_ERROR;
+ if (alignment<CD_QUERY || alignment>CD_BASE_RIGHT);
+
+ text_alignment = canvas->text_alignment;
+
+ if (alignment == CD_QUERY || alignment == text_alignment)
+ return text_alignment;
+
+ if (canvas->cxTextAlignment)
+ canvas->text_alignment = canvas->cxTextAlignment(canvas->ctxcanvas, alignment);
+ else
+ canvas->text_alignment = alignment;
+
+ return text_alignment;
+}
+
+double cdCanvasTextOrientation(cdCanvas* canvas, double angle)
+{
+ double text_orientation;
+
+ assert(canvas);
+ if (!_cdCheckCanvas(canvas)) return CD_ERROR;
+
+ text_orientation = canvas->text_orientation;
+
+ if (angle == CD_QUERY || angle == text_orientation)
+ return text_orientation;
+
+ if (canvas->cxTextOrientation)
+ canvas->text_orientation = canvas->cxTextOrientation(canvas->ctxcanvas, angle);
+ else
+ canvas->text_orientation = angle;
+
+ return text_orientation;
+}
+
+void cdCanvasGetFontDim(cdCanvas* canvas, int *max_width, int *height, int *ascent, int *descent)
+{
+ assert(canvas);
+ if (!_cdCheckCanvas(canvas)) return;
+ canvas->cxGetFontDim(canvas->ctxcanvas, max_width, height, ascent, descent);
+}
+
+void cdCanvasGetTextSize(cdCanvas* canvas, const char *s, int *width, int *height)
+{
+ assert(canvas);
+ assert(s);
+ if (!_cdCheckCanvas(canvas)) return;
+ canvas->cxGetTextSize(canvas->ctxcanvas, s, width, height);
+}
+
+void cdTextTranslatePoint(cdCanvas* canvas, int x, int y, int w, int h, int baseline, int *rx, int *ry)
+{
+ /* move to left */
+ switch (canvas->text_alignment)
+ {
+ case CD_BASE_RIGHT:
+ case CD_NORTH_EAST:
+ case CD_EAST:
+ case CD_SOUTH_EAST:
+ *rx = x - w;
+ break;
+ case CD_BASE_CENTER:
+ case CD_CENTER:
+ case CD_NORTH:
+ case CD_SOUTH:
+ *rx = x - w/2;
+ break;
+ case CD_BASE_LEFT:
+ case CD_NORTH_WEST:
+ case CD_WEST:
+ case CD_SOUTH_WEST:
+ *rx = x;
+ break;
+ }
+
+ /* move to bottom */
+ switch (canvas->text_alignment)
+ {
+ case CD_BASE_LEFT:
+ case CD_BASE_CENTER:
+ case CD_BASE_RIGHT:
+ if (canvas->invert_yaxis)
+ *ry = y + baseline;
+ else
+ *ry = y - baseline;
+ break;
+ case CD_SOUTH_EAST:
+ case CD_SOUTH_WEST:
+ case CD_SOUTH:
+ *ry = y;
+ break;
+ case CD_NORTH_EAST:
+ case CD_NORTH:
+ case CD_NORTH_WEST:
+ if (canvas->invert_yaxis)
+ *ry = y + h;
+ else
+ *ry = y - h;
+ break;
+ case CD_CENTER:
+ case CD_EAST:
+ case CD_WEST:
+ if (canvas->invert_yaxis)
+ *ry = y + h/2;
+ else
+ *ry = y - h/2;
+ break;
+ }
+}
+
+void cdCanvasGetTextBounds(cdCanvas* canvas, int x, int y, const char *s, int *rect)
+{
+ int w, h, ascent, height, baseline;
+ int xmin, xmax, ymin, ymax;
+ int old_invert_yaxis = canvas->invert_yaxis;
+
+ cdCanvasGetTextSize(canvas, s, &w, &h);
+ cdCanvasGetFontDim(canvas, NULL, &height, &ascent, NULL);
+ baseline = height - ascent;
+
+ /* in this case we are always upwards */
+ canvas->invert_yaxis = 0;
+
+ /* move to bottom-left */
+ cdTextTranslatePoint(canvas, x, y, w, h, baseline, &xmin, &ymin);
+
+ xmax = xmin + w-1;
+ ymax = ymin + h-1;
+
+ if (canvas->text_orientation)
+ {
+ double cos_theta = cos(canvas->text_orientation*CD_DEG2RAD);
+ double sin_theta = sin(canvas->text_orientation*CD_DEG2RAD);
+
+ cdRotatePoint(canvas, xmin, ymin, x, y, &rect[0], &rect[1], sin_theta, cos_theta);
+ cdRotatePoint(canvas, xmax, ymin, x, y, &rect[2], &rect[3], sin_theta, cos_theta);
+ cdRotatePoint(canvas, xmax, ymax, x, y, &rect[4], &rect[5], sin_theta, cos_theta);
+ cdRotatePoint(canvas, xmin, ymax, x, y, &rect[6], &rect[7], sin_theta, cos_theta);
+ }
+ else
+ {
+ rect[0] = xmin; rect[1] = ymin;
+ rect[2] = xmax; rect[3] = ymin;
+ rect[4] = xmax; rect[5] = ymax;
+ rect[6] = xmin; rect[7] = ymax;
+ }
+
+ canvas->invert_yaxis = old_invert_yaxis;
+}
+
+void cdCanvasGetTextBox(cdCanvas* canvas, int x, int y, const char *s, int *xmin, int *xmax, int *ymin, int *ymax)
+{
+ int rect[8];
+ int _xmin, _xmax, _ymin, _ymax;
+
+ cdCanvasGetTextBounds(canvas, x, y, s, rect);
+
+ _xmin = rect[0];
+ _ymin = rect[1];
+ _xmax = rect[0];
+ _ymax = rect[1];
+
+ if(rect[2] < _xmin) _xmin = rect[2];
+ if(rect[4] < _xmin) _xmin = rect[4];
+ if(rect[6] < _xmin) _xmin = rect[6];
+
+ if(rect[3] < _ymin) _ymin = rect[3];
+ if(rect[5] < _ymin) _ymin = rect[5];
+ if(rect[7] < _ymin) _ymin = rect[7];
+
+ if(rect[2] > _xmax) _xmax = rect[2];
+ if(rect[4] > _xmax) _xmax = rect[4];
+ if(rect[6] > _xmax) _xmax = rect[6];
+
+ if(rect[3] > _ymax) _ymax = rect[3];
+ if(rect[5] > _ymax) _ymax = rect[5];
+ if(rect[7] > _ymax) _ymax = rect[7];
+
+ if (xmin) *xmin = _xmin;
+ if (xmax) *xmax = _xmax;
+ if (ymin) *ymin = _ymin;
+ if (ymax) *ymax = _ymax;
+}
+
+/**************************************************************/
+/* Native Font Format, compatible with Pango Font Description */
+/**************************************************************/
+
+/*
+The string contains the font name, the style and the size.
+Style can be a free combination of some names separated by spaces.
+Font name can be a list of font family names separated by comma.
+*/
+
+#define isspace(_x) (_x == ' ')
+
+static int cd_find_style_name(const char *name, int len, int *style)
+{
+#define CD_STYLE_NUM_NAMES 21
+ static struct { const char* name; int style; } cd_style_names[CD_STYLE_NUM_NAMES] = {
+ {"Normal", 0},
+ {"Oblique", CD_ITALIC},
+ {"Italic", CD_ITALIC},
+ {"Small-Caps", 0},
+ {"Ultra-Light", 0},
+ {"Light", 0},
+ {"Medium", 0},
+ {"Semi-Bold", CD_BOLD},
+ {"Bold", CD_BOLD},
+ {"Ultra-Bold", CD_BOLD},
+ {"Heavy", 0},
+ {"Ultra-Condensed",0},
+ {"Extra-Condensed",0},
+ {"Condensed", 0},
+ {"Semi-Condensed", 0},
+ {"Semi-Expanded", 0},
+ {"Expanded", 0},
+ {"Extra-Expanded", 0},
+ {"Ultra-Expanded", 0},
+ {"Underline", CD_UNDERLINE},
+ {"Strikeout", CD_STRIKEOUT}
+ };
+
+ int i;
+ for (i = 0; i < CD_STYLE_NUM_NAMES; i++)
+ {
+ if (strncmp(cd_style_names[i].name, name, len)==0)
+ {
+ *style = cd_style_names[i].style;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static const char * cd_getword(const char *str, const char *last, int *wordlen)
+{
+ const char *result;
+
+ while (last > str && isspace(*(last - 1)))
+ last--;
+
+ result = last;
+ while (result > str && !isspace (*(result - 1)))
+ result--;
+
+ *wordlen = last - result;
+
+ return result;
+}
+
+int cdParsePangoFont(const char *nativefont, char *type_face, int *style, int *size)
+{
+ const char *p, *last;
+ int len, wordlen;
+
+ len = (int)strlen(nativefont);
+ last = nativefont + len;
+ p = cd_getword(nativefont, last, &wordlen);
+
+ /* Look for a size at the end of the string */
+ if (wordlen != 0)
+ {
+ int new_size = atoi(p);
+ if (new_size != 0)
+ {
+ *size = new_size;
+ last = p;
+ }
+ }
+
+ /* Now parse style words */
+ p = cd_getword(nativefont, last, &wordlen);
+ while (wordlen != 0)
+ {
+ int new_style = 0;
+
+ if (!cd_find_style_name(p, wordlen, &new_style))
+ break;
+ else
+ {
+ *style |= new_style;
+
+ last = p;
+ p = cd_getword(nativefont, last, &wordlen);
+ }
+ }
+
+ /* Remainder is font family list. */
+
+ /* Trim off trailing white space */
+ while (last > nativefont && isspace(*(last - 1)))
+ last--;
+
+ /* Trim off trailing commas */
+ if (last > nativefont && *(last - 1) == ',')
+ last--;
+
+ /* Again, trim off trailing white space */
+ while (last > nativefont && isspace(*(last - 1)))
+ last--;
+
+ /* Trim off leading white space */
+ while (last > nativefont && isspace(*nativefont))
+ nativefont++;
+
+ if (nativefont != last)
+ {
+ len = (last - nativefont);
+ strncpy(type_face, nativefont, len);
+ type_face[len] = 0;
+ return 1;
+ }
+ else
+ return 0;
+}
+
+int cdParseIupWinFont(const char *nativefont, char *type_face, int *style, int *size)
+{
+ int c;
+
+ if (strstr(nativefont, ":") == NULL)
+ return 0;
+
+ c = strcspn(nativefont, ":"); /* extract type_face */
+ if (c == 0) return 0;
+ strncpy(type_face, nativefont, c);
+ type_face[c]='\0';
+ nativefont += c+1;
+
+ if(nativefont[0] == ':') /* check for attributes */
+ nativefont++;
+ else
+ {
+ *style = 0;
+ while(strlen(nativefont)) /* extract style (bold/italic etc) */
+ {
+ char style_str[20];
+
+ c = strcspn(nativefont, ":,");
+ if (c == 0)
+ break;
+
+ strncpy(style_str, nativefont, c);
+ style_str[c] = '\0';
+
+ if(!strcmp(style_str, "BOLD"))
+ *style |= CD_BOLD;
+ else if(!strcmp(style_str,"ITALIC"))
+ *style |= CD_ITALIC;
+ else if(!strcmp(style_str,"UNDERLINE"))
+ *style |= CD_UNDERLINE;
+ else if(!strcmp(style_str,"STRIKEOUT"))
+ *style |= CD_STRIKEOUT;
+
+ nativefont += c;
+
+ if(nativefont[0] == ':') /* end attribute list */
+ {
+ nativefont++;
+ break;
+ }
+
+ nativefont++; /* skip separator */
+ }
+ }
+
+ /* extract size in points */
+ if (sscanf(nativefont, "%d", size) != 1)
+ return 0;
+
+ if (*size == 0)
+ return 0;
+
+ return 1;
+}
+
+int cdParseXWinFont(const char *nativefont, char *type_face, int *style, int *size)
+{
+ char style1[10], style2[10];
+ char* token;
+ char font[1024];
+
+ if (nativefont[0] != '-')
+ return 0;
+
+ strcpy(font, nativefont+1); /* skip first '-' */
+
+ *style = 0;
+
+ /* fndry */
+ token = strtok(font, "-");
+ if (!token) return 0;
+
+ /* fmly */
+ token = strtok(NULL, "-");
+ if (!token) return 0;
+ strcpy(type_face, token);
+
+ /* wght */
+ token = strtok(NULL, "-");
+ if (!token) return 0;
+ strcpy(style1, token);
+ if (strstr("bold", style1))
+ *style |= CD_BOLD;
+
+ /* slant */
+ token = strtok(NULL, "-");
+ if (!token) return 0;
+ strcpy(style2, token);
+ if (*style2 == 'i' || *style2 == 'o')
+ *style |= CD_ITALIC;
+
+ /* sWdth */
+ token = strtok(NULL, "-");
+ if (!token) return 0;
+ /* adstyl */
+ token = strtok(NULL, "-");
+ if (!token) return 0;
+
+ /* pxlsz */
+ token = strtok(NULL, "-");
+ if (!token) return 0;
+ *size = -atoi(token); /* size in pixels */
+
+ if (*size < 0)
+ return 1;
+
+ /* ptSz */
+ token = strtok(NULL, "-");
+ if (!token) return 0;
+ *size = atoi(token)/10; /* size in deci-points */
+
+ if (*size > 0)
+ return 1;
+
+ return 0;
+}