Graphviz 12.0.1~dev.20240716.0800
Loading...
Searching...
No Matches
gvtextlayout_gd.c
Go to the documentation of this file.
1/*************************************************************************
2 * Copyright (c) 2011 AT&T Intellectual Property
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors: Details at https://graphviz.org
9 *************************************************************************/
10
11#include "config.h"
12#include <cgraph/strview.h>
13#include "gd_psfontResolve.h"
14#include <stdbool.h>
15#include <stdio.h>
16#include <stdlib.h>
17#include <string.h>
19#include <gd.h>
20#include <cgraph/strcasecmp.h>
21#include <common/const.h>
22
23#ifdef HAVE_GD_FREETYPE
24
25/* fontsize at which text is omitted entirely */
26#define FONTSIZE_MUCH_TOO_SMALL 0.15
27/* fontsize at which text is rendered by a simple line */
28#define FONTSIZE_TOO_SMALL 1.5
29
30#ifndef HAVE_GD_FONTCONFIG
31/* gd_alternate_fontlist;
32 * Sometimes fonts are stored under a different name,
33 * especially on Windows. Without fontconfig, we provide
34 * here some rudimentary name mapping.
35 */
36char *gd_alternate_fontlist(const char *font) {
37 char *p;
38
39 /* fontbuf to contain font without style descriptions like -Roman or -Italic */
40 strview_t fontlist = strview(font, '\0');
41 if ((p = strchr(font, '-')) || (p = strchr(font, '_')))
42 fontlist.size = (size_t)(p - font);
43
44 if ((strcasecmp(font, "times-bold") == 0)
45 || strview_case_str_eq(fontlist, "timesbd")
46 || strview_case_str_eq(fontlist, "timesb"))
47 fontlist = strview("timesbd;Timesbd;TIMESBD;timesb;Timesb;TIMESB", '\0');
48
49 else if ((strcasecmp(font, "times-italic") == 0)
50 || strview_case_str_eq(fontlist, "timesi"))
51 fontlist = strview("timesi;Timesi;TIMESI", '\0');
52
53 else if ((strcasecmp(font, "timesnewroman") == 0)
54 || (strcasecmp(font, "timesnew") == 0)
55 || (strcasecmp(font, "timesroman") == 0)
56 || strview_case_str_eq(fontlist, "times"))
57 fontlist = strview("times;Times;TIMES", '\0');
58
59 else if ((strcasecmp(font, "arial-bold") == 0)
60 || strview_case_str_eq(fontlist, "arialb"))
61 fontlist = strview("arialb;Arialb;ARIALB", '\0');
62
63 else if ((strcasecmp(font, "arial-italic") == 0)
64 || strview_case_str_eq(fontlist, "ariali"))
65 fontlist = strview("ariali;Ariali;ARIALI", '\0');
66
67 else if (strview_case_str_eq(fontlist, "helvetica"))
68 fontlist = strview("helvetica;Helvetica;HELVETICA;arial;Arial;ARIAL", '\0');
69
70 else if (strview_case_str_eq(fontlist, "arial"))
71 fontlist = strview("arial;Arial;ARIAL", '\0');
72
73 else if (strview_case_str_eq(fontlist, "courier"))
74 fontlist = strview("courier;Courier;COURIER;cour", '\0');
75
76 return strview_str(fontlist);
77}
78#endif /* HAVE_GD_FONTCONFIG */
79
80/* gd_psfontResolve:
81 * * Construct alias for postscript fontname.
82 * * NB. Uses a static array - non-reentrant.
83 * */
84
85#define ADD_ATTR(a) \
86 if (a) { \
87 strcat(buf, comma ? " " : ", "); \
88 comma = 1; \
89 strcat(buf, a); \
90 }
91
93{
94 static char buf[1024];
95 int comma=0;
96 strcpy(buf, pa->family);
97
98 ADD_ATTR(pa->weight);
99 ADD_ATTR(pa->stretch);
100 ADD_ATTR(pa->style);
101
102 return buf;
103}
104
105static bool gd_textlayout(textspan_t * span, char **fontpath)
106{
107 char *err, *fontlist, *fontname;
108 double fontsize;
109 int brect[8];
110 gdFTStringExtra strex;
111#ifdef HAVE_GD_FONTCONFIG
112 PostscriptAlias *pA;
113#endif
114
115 fontname = span->font->name;
116 fontsize = span->font->size;
117
118 strex.fontpath = NULL;
119 strex.flags = gdFTEX_RETURNFONTPATHNAME | gdFTEX_RESOLUTION;
120 strex.hdpi = strex.vdpi = POINTS_PER_INCH;
121
122 if (strchr(fontname, '/'))
123 strex.flags |= gdFTEX_FONTPATHNAME;
124 else
125 strex.flags |= gdFTEX_FONTCONFIG;
126
127 span->size.x = 0.0;
128 span->size.y = 0.0;
129 span->yoffset_layout = 0.0;
130
131 span->layout = NULL;
132 span->free_layout = NULL;
133
134 span->yoffset_centerline = 0.05 * fontsize;
135
136 if (fontname) {
137 if (fontsize <= FONTSIZE_MUCH_TOO_SMALL) {
138 return true; /* OK, but ignore text entirely */
139 } else if (fontsize <= FONTSIZE_TOO_SMALL) {
140 /* draw line in place of text */
141 /* fake a finite fontsize so that line length is calculated */
142 fontsize = FONTSIZE_TOO_SMALL;
143 }
144 /* call gdImageStringFT with null *im to get brect and to set font cache */
145#ifdef HAVE_GD_FONTCONFIG
146 gdFTUseFontConfig(1); /* tell gd that we really want to use fontconfig, 'cos it s not the default */
147 pA = span->font->postscript_alias;
148 if (pA)
149 fontlist = gd_psfontResolve (pA);
150 else
151 fontlist = fontname;
152#else
153 fontlist = gd_alternate_fontlist(fontname);
154#endif
155
156 err = gdImageStringFTEx(NULL, brect, -1, fontlist,
157 fontsize, 0, 0, 0, span->str, &strex);
158#ifndef HAVE_GD_FONTCONFIG
159 free(fontlist);
160#endif
161
162 if (err) {
163 agerrorf("%s\n", err);
164 return false; /* indicate error */
165 }
166
167 if (fontpath)
168 *fontpath = strex.fontpath;
169 else
170 free (strex.fontpath); /* strup'ed in libgd */
171
172 if (span->str && span->str[0]) {
173 /* can't use brect on some archtectures if strlen 0 */
174 span->size.x = (double) (brect[4] - brect[0]);
175 // LINESPACING specifies how much extra space to leave between lines
176 span->size.y = fontsize * LINESPACING;
177 }
178 }
179 return true;
180}
181
182static gvtextlayout_engine_t gd_textlayout_engine = {
183 gd_textlayout,
184};
185#endif
186
188#ifdef HAVE_GD_FREETYPE
189 {0, "textlayout", 2, &gd_textlayout_engine, NULL},
190#endif
191 {0, NULL, 0, NULL, NULL}
192};
#define LINESPACING
Definition const.h:70
#define FONTSIZE_MUCH_TOO_SMALL
Definition const.h:268
#define FONTSIZE_TOO_SMALL
Definition const.h:270
static char * err
Definition delaunay.c:746
char * gd_psfontResolve(PostscriptAlias *pa)
#define POINTS_PER_INCH
Definition geom.h:64
void free(void *)
node NULL
Definition grammar.y:149
void agerrorf(const char *fmt,...)
Definition agerror.c:165
gvplugin_installed_t gvtextlayout_gd_types[]
$2 font
Definition htmlparse.y:498
platform abstraction for case-insensitive string functions
ingroup plugin_api
Definition gvplugin.h:35
double x
Definition geom.h:29
double y
Definition geom.h:29
a non-owning string reference
Definition strview.h:20
size_t size
extent of the string in bytes
Definition strview.h:22
char * name
Definition textspan.h:54
PostscriptAlias * postscript_alias
Definition textspan.h:56
double size
Definition textspan.h:57
double yoffset_layout
Definition textspan.h:69
char * str
Definition textspan.h:65
void * layout
Definition textspan.h:67
pointf size
Definition textspan.h:70
textfont_t * font
Definition textspan.h:66
double yoffset_centerline
Definition textspan.h:69
void(* free_layout)(void *layout)
Definition textspan.h:68
Non-owning string references.
static char * strview_str(strview_t source)
make a heap-allocated string from this string view
Definition strview.h:41
static strview_t strview(const char *referent, char terminator)
create a string reference
Definition strview.h:26
static bool strview_case_str_eq(strview_t a, const char *b)
compare a string reference to a string for case insensitive equality
Definition strview.h:62