Graphviz 12.0.1~dev.20240716.0800
Loading...
Searching...
No Matches
gvtextlayout_pango.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
13#include <assert.h>
14#include <limits.h>
15#include <stdbool.h>
16#include <stdlib.h>
17#include <string.h>
18#include <gvc/gvplugin_render.h>
19#include <cgraph/agxbuf.h>
20#include <cgraph/alloc.h>
21#include <common/utils.h>
23
24#include <pango/pangocairo.h>
25#include "gvgetfontlist.h"
26#ifdef HAVE_PANGO_FC_FONT_LOCK_FACE
27#include <pango/pangofc-font.h>
28#endif
29
30static void pango_free_layout (void *layout)
31{
32 g_object_unref(layout);
33}
34
36{
37 static char buf[1024];
38 strcpy(buf, pa->family);
39 strcat(buf, ",");
40 if (pa->weight) {
41 strcat(buf, " ");
42 strcat(buf, pa->weight);
43 }
44 if (pa->stretch) {
45 strcat(buf, " ");
46 strcat(buf, pa->stretch);
47 }
48 if (pa->style) {
49 strcat(buf, " ");
50 strcat(buf, pa->style);
51 }
52 return buf;
53}
54
55#define FONT_DPI 96.
56
57#define ENABLE_PANGO_MARKUP
58
59// wrapper to handle difference in calling conventions between `agxbput` and
60// `xml_escape`’s `cb`
61static int agxbput_int(void *buffer, const char *s) {
62 size_t len = agxbput(buffer, s);
63 assert(len <= INT_MAX);
64 return (int)len;
65}
66
67static bool pango_textlayout(textspan_t * span, char **fontpath)
68{
69 static char buf[1024]; /* returned in fontpath, only good until next call */
70 static PangoFontMap *fontmap;
71 static PangoContext *context;
72 static PangoFontDescription *desc;
73 static char *fontname;
74 static double fontsize;
75 static gv_font_map* gv_fmap;
76 char *fnt, *psfnt = NULL;
77 PangoLayout *layout;
78 PangoRectangle logical_rect;
79 cairo_font_options_t* options;
80 PangoFont *font;
81#ifdef ENABLE_PANGO_MARKUP
82 PangoAttrList *attrs;
83 GError *error = NULL;
84 int flags;
85#endif
86 char *text;
87 double textlayout_scale;
89
90 if (!context) {
91 fontmap = pango_cairo_font_map_new();
92 gv_fmap = get_font_mapping(fontmap);
93 context = pango_font_map_create_context (fontmap);
94 options=cairo_font_options_create();
95 cairo_font_options_set_antialias(options,CAIRO_ANTIALIAS_GRAY);
96 cairo_font_options_set_hint_style(options,CAIRO_HINT_STYLE_FULL);
97 cairo_font_options_set_hint_metrics(options,CAIRO_HINT_METRICS_ON);
98 cairo_font_options_set_subpixel_order(options,CAIRO_SUBPIXEL_ORDER_BGR);
99 pango_cairo_context_set_font_options(context, options);
100 pango_cairo_context_set_resolution(context, FONT_DPI);
101 cairo_font_options_destroy(options);
102 g_object_unref(fontmap);
103 }
104
105 if (!fontname || strcmp(fontname, span->font->name) != 0 || fontsize != span->font->size) {
106
107 /* check if the conversion to Pango units below will overflow */
108 if ((double)(G_MAXINT / PANGO_SCALE) < span->font->size) {
109 return false;
110 }
111
112 free(fontname);
113 fontname = gv_strdup(span->font->name);
114 fontsize = span->font->size;
115 pango_font_description_free (desc);
116
117 pA = span->font->postscript_alias;
118 if (pA) {
119 psfnt = fnt = gv_fmap[pA->xfig_code].gv_font;
120 if(!psfnt)
121 psfnt = fnt = pango_psfontResolve (pA);
122 }
123 else
124 fnt = fontname;
125
126 desc = pango_font_description_from_string(fnt);
127 /* all text layout is done at a scale of FONT_DPI (nominaly 96.) */
128 pango_font_description_set_size (desc, (gint)(fontsize * PANGO_SCALE));
129
130 if (fontpath && (font = pango_font_map_load_font(fontmap, context, desc))) { /* -v support */
131 const char *fontclass;
132
133 fontclass = G_OBJECT_CLASS_NAME(G_OBJECT_GET_CLASS(font));
134
135 buf[0] = '\0';
136 if (psfnt) {
137 strcat(buf, "(ps:pango ");
138 strcat(buf, psfnt);
139 strcat(buf, ") ");
140 }
141 strcat(buf, "(");
142 strcat(buf, fontclass);
143 strcat(buf, ") ");
144#ifdef HAVE_PANGO_FC_FONT_LOCK_FACE
145 if (strcmp(fontclass, "PangoCairoFcFont") == 0) {
146 FT_Face face;
147 PangoFcFont *fcfont;
148 FT_Stream stream;
149 FT_StreamDesc streamdesc;
150 fcfont = PANGO_FC_FONT(font);
151 face = pango_fc_font_lock_face(fcfont);
152 if (face) {
153 strcat(buf, "\"");
154 strcat(buf, face->family_name);
155 strcat(buf, ", ");
156 strcat(buf, face->style_name);
157 strcat(buf, "\" ");
158
159 stream = face->stream;
160 if (stream) {
161 streamdesc = stream->pathname;
162 if (streamdesc.pointer)
163 strcat(buf, (char*)streamdesc.pointer);
164 else
165 strcat(buf, "*no pathname available*");
166 }
167 else
168 strcat(buf, "*no stream available*");
169 }
170 pango_fc_font_unlock_face(fcfont);
171 }
172 else
173#endif
174 {
175 PangoFontDescription *tdesc;
176 char *tfont;
177
178 tdesc = pango_font_describe(font);
179 tfont = pango_font_description_to_string(tdesc);
180 strcat(buf, "\"");
181 strcat(buf, tfont);
182 strcat(buf, "\" ");
183 g_free(tfont);
184 }
185 *fontpath = buf;
186 }
187 }
188
189#ifdef ENABLE_PANGO_MARKUP
190 if ((span->font) && (flags = span->font->flags)) {
191 agxbuf xb = {0};
192
193 agxbput(&xb,"<span");
194
195 if (flags & HTML_BF)
196 agxbput(&xb," weight=\"bold\"");
197 if (flags & HTML_IF)
198 agxbput(&xb," style=\"italic\"");
199 if (flags & HTML_UL)
200 agxbput(&xb," underline=\"single\"");
201 if (flags & HTML_S)
202 agxbput(&xb," strikethrough=\"true\"");
203 agxbput (&xb,">");
204
205 if (flags & HTML_SUP)
206 agxbput(&xb,"<sup>");
207 if (flags & HTML_SUB)
208 agxbput(&xb,"<sub>");
209
210 const xml_flags_t xml_flags = {.raw = 1, .dash = 1, .nbsp = 1};
211 xml_escape(span->str, xml_flags, agxbput_int, &xb);
212
213 if (flags & HTML_SUB)
214 agxbput(&xb,"</sub>");
215 if (flags & HTML_SUP)
216 agxbput(&xb,"</sup>");
217
218 agxbput (&xb,"</span>");
219 if (!pango_parse_markup (agxbuse(&xb), -1, 0, &attrs, &text, NULL, &error)) {
220 fprintf (stderr, "Error - pango_parse_markup: %s\n", error->message);
221 text = span->str;
222 attrs = NULL;
223 }
224 agxbfree (&xb);
225 }
226 else {
227 text = span->str;
228 attrs = NULL;
229 }
230#else
231 text = span->str;
232#endif
233
234 layout = pango_layout_new (context);
235 span->layout = layout; /* layout free with textspan - see labels.c */
236 span->free_layout = pango_free_layout; /* function for freeing pango layout */
237
238 pango_layout_set_text (layout, text, -1);
239 pango_layout_set_font_description (layout, desc);
240#ifdef ENABLE_PANGO_MARKUP
241 if (attrs)
242 pango_layout_set_attributes (layout, attrs);
243#endif
244
245 pango_layout_get_extents (layout, NULL, &logical_rect);
246
247 /* if pango doesn't like the font then it sets width=0 but height = garbage */
248 if (logical_rect.width == 0)
249 logical_rect.height = 0;
250
251 textlayout_scale = POINTS_PER_INCH / (FONT_DPI * PANGO_SCALE);
252 span->size.x = logical_rect.width * textlayout_scale;
253 span->size.y = logical_rect.height * textlayout_scale;
254
255 /* The y offset from baseline to 0,0 of the bitmap representation */
256 span->yoffset_layout = pango_layout_get_baseline (layout) * textlayout_scale;
257
258 /* The distance below midline for y centering of text strings */
259 span->yoffset_centerline = 0.05 * span->font->size;
260
261 return logical_rect.width != 0 || strcmp(text, "") == 0;
262}
263
267
269 {0, "textlayout", 10, &pango_textlayout_engine, NULL},
270 {0, NULL, 0, NULL, NULL}
271};
static void agxbfree(agxbuf *xb)
free any malloced resources
Definition agxbuf.h:77
static size_t agxbput(agxbuf *xb, const char *s)
append string s into xb
Definition agxbuf.h:249
static char * agxbuse(agxbuf *xb)
Definition agxbuf.h:286
Memory allocation wrappers that exit on failure.
static char * gv_strdup(const char *original)
Definition alloc.h:101
void error(int level, const char *s,...)
Definition error.c:83
static int flags
Definition gc.c:61
#define POINTS_PER_INCH
Definition geom.h:64
static double len(glCompPoint p)
Definition glutils.c:150
void free(void *)
node NULL
Definition grammar.y:149
gv_font_map * get_font_mapping(PangoFontMap *pfm)
static gvtextlayout_engine_t pango_textlayout_engine
static int agxbput_int(void *buffer, const char *s)
gvplugin_installed_t gvtextlayout_pango_types[]
static char * pango_psfontResolve(PostscriptAlias *pa)
#define FONT_DPI
static bool pango_textlayout(textspan_t *span, char **fontpath)
static void pango_free_layout(void *layout)
$2 font
Definition htmlparse.y:498
static int layout(graph_t *g, layout_info *infop)
Definition layout.c:809
ingroup plugin_api
Definition gvplugin.h:35
Definition gvpr.c:66
double x
Definition geom.h:29
double y
Definition geom.h:29
char * name
Definition textspan.h:54
PostscriptAlias * postscript_alias
Definition textspan.h:56
unsigned int flags
Definition textspan.h:58
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
unsigned raw
Definition utils.h:40
#define HTML_IF
Definition textspan.h:30
#define HTML_UL
Definition textspan.h:31
#define HTML_BF
Definition textspan.h:29
#define HTML_SUP
Definition textspan.h:32
#define HTML_S
Definition textspan.h:34
#define HTML_SUB
Definition textspan.h:33
Definition grammar.c:93
int xml_escape(const char *s, xml_flags_t flags, int(*cb)(void *state, const char *s), void *state)
Definition xml.c:179