Graphviz 13.0.0~dev.20250424.1043
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 <common/utils.h>
21#include <util/agxbuf.h>
22#include <util/alloc.h>
23#include <util/gv_math.h>
24#include <util/xml.h>
25
26#include <pango/pangocairo.h>
27#include "gvgetfontlist.h"
28#ifdef HAVE_PANGO_FC_FONT_LOCK_FACE
29#include <pango/pangofc-font.h>
30#endif
31
32static void pango_free_layout (void *layout)
33{
34 g_object_unref(layout);
35}
36
38{
39 agxbuf buf = {0};
40 agxbprint(&buf, "%s,", pa->family);
41 if (pa->weight) {
42 agxbprint(&buf, " %s", pa->weight);
43 }
44 if (pa->stretch) {
45 agxbprint(&buf, " %s", pa->stretch);
46 }
47 if (pa->style) {
48 agxbprint(&buf, " %s", pa->style);
49 }
50 return agxbdisown(&buf);
51}
52
53#define FONT_DPI 96.
54
55#define ENABLE_PANGO_MARKUP
56
57// wrapper to handle difference in calling conventions between `agxbput` and
58// `gv_xml_escape`’s `cb`
59static int agxbput_int(void *buffer, const char *s) {
60 size_t len = agxbput(buffer, s);
61 assert(len <= INT_MAX);
62 return (int)len;
63}
64
65static bool pango_textlayout(textspan_t * span, char **fontpath)
66{
67 static agxbuf buf; // returned in fontpath, only good until next call
68 static PangoFontMap *fontmap;
69 static PangoContext *context;
70 static PangoFontDescription *desc;
71 static char *fontname;
72 static double fontsize;
73 static gv_font_map* gv_fmap;
74 char *fnt, *psfnt = NULL;
75 PangoFont *font;
76#ifdef ENABLE_PANGO_MARKUP
77 PangoAttrList *attrs;
78 GError *error = NULL;
79 int flags;
80#endif
81 bool text_needs_free = false;
82 char *text;
83
84 if (!context) {
85 fontmap = pango_cairo_font_map_new();
86 gv_fmap = get_font_mapping(fontmap);
87 context = pango_font_map_create_context (fontmap);
88 cairo_font_options_t* options = cairo_font_options_create();
89 cairo_font_options_set_antialias(options,CAIRO_ANTIALIAS_GRAY);
90 cairo_font_options_set_hint_style(options,CAIRO_HINT_STYLE_FULL);
91 cairo_font_options_set_hint_metrics(options,CAIRO_HINT_METRICS_ON);
92 cairo_font_options_set_subpixel_order(options,CAIRO_SUBPIXEL_ORDER_BGR);
93 pango_cairo_context_set_font_options(context, options);
94 pango_cairo_context_set_resolution(context, FONT_DPI);
95 cairo_font_options_destroy(options);
96 g_object_unref(fontmap);
97 }
98
99 if (!fontname || strcmp(fontname, span->font->name) != 0 ||
100 !is_exactly_equal(fontsize, span->font->size)) {
101
102 /* check if the conversion to Pango units below will overflow */
103 if (INT_MAX / PANGO_SCALE < span->font->size) {
104 return false;
105 }
106
107 free(fontname);
108 fontname = gv_strdup(span->font->name);
109 fontsize = span->font->size;
110 pango_font_description_free (desc);
111
113 bool psfnt_needs_free = false;
114 if (pA) {
115 psfnt = fnt = gv_fmap[pA->xfig_code].gv_font;
116 if(!psfnt) {
117 psfnt = fnt = pango_psfontResolve (pA);
118 psfnt_needs_free = true;
119 }
120 }
121 else
122 fnt = fontname;
123
124 desc = pango_font_description_from_string(fnt);
125 /* all text layout is done at a scale of FONT_DPI (nominaly 96.) */
126 pango_font_description_set_size (desc, (int)(fontsize * PANGO_SCALE));
127
128 if (fontpath && (font = pango_font_map_load_font(fontmap, context, desc))) { /* -v support */
129 const char *fontclass = G_OBJECT_CLASS_NAME(G_OBJECT_GET_CLASS(font));
130
131 agxbclear(&buf);
132 if (psfnt) {
133 agxbprint(&buf, "(ps:pango %s) ", psfnt);
134 }
135 agxbprint(&buf, "(%s) ", fontclass);
136#ifdef HAVE_PANGO_FC_FONT_LOCK_FACE
137 if (strcmp(fontclass, "PangoCairoFcFont") == 0) {
138 PangoFcFont *fcfont = PANGO_FC_FONT(font);
139// `pango_fc_font_lock_face` arrived in Pango 1.4 and then was deprecated in
140// 1.44. Its replacement is `pango_font_get_hb_font`. However this replacement
141// does not seem to provide access to the underlying FreeType font information
142// we want. Since this code path is only enabled when `pango_fc_font_lock_face`
143// is available, suppress deprecation warnings and we will have to deal with the
144// loss of this informational output altogether when Pango finally removes it.
145#if __GNUC__
146#pragma GCC diagnostic push
147#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
148#endif
149 FT_Face face = pango_fc_font_lock_face(fcfont);
150#ifdef __GNUC__
151#pragma GCC diagnostic pop
152#endif
153 if (face) {
154 agxbprint(&buf, "\"%s, %s\" ", face->family_name, face->style_name);
155
156 FT_Stream stream = face->stream;
157 if (stream) {
158 FT_StreamDesc streamdesc = stream->pathname;
159 if (streamdesc.pointer)
160 agxbput(&buf, streamdesc.pointer);
161 else
162 agxbput(&buf, "*no pathname available*");
163 }
164 else
165 agxbput(&buf, "*no stream available*");
166 }
167#if __GNUC__
168#pragma GCC diagnostic push
169#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
170#endif
171 pango_fc_font_unlock_face(fcfont);
172#ifdef __GNUC__
173#pragma GCC diagnostic pop
174#endif
175 }
176 else
177#endif
178 {
179 PangoFontDescription *tdesc = pango_font_describe(font);
180 char *tfont = pango_font_description_to_string(tdesc);
181 agxbprint(&buf, "\"%s\" ", tfont);
182 g_free(tfont);
183 }
184 *fontpath = agxbuse(&buf);
185 }
186 if (psfnt_needs_free) {
187 free(psfnt);
188 }
189 }
190
191#ifdef ENABLE_PANGO_MARKUP
192 if (span->font && (flags = span->font->flags)) {
193 agxbuf xb = {0};
194
195 agxbput(&xb,"<span");
196
197 if (flags & HTML_BF)
198 agxbput(&xb," weight=\"bold\"");
199 if (flags & HTML_IF)
200 agxbput(&xb," style=\"italic\"");
201 if (flags & HTML_UL)
202 agxbput(&xb," underline=\"single\"");
203 if (flags & HTML_S)
204 agxbput(&xb," strikethrough=\"true\"");
205 agxbput (&xb,">");
206
207 if (flags & HTML_SUP)
208 agxbput(&xb,"<sup>");
209 if (flags & HTML_SUB)
210 agxbput(&xb,"<sub>");
211
212 const xml_flags_t xml_flags = {.raw = 1, .dash = 1, .nbsp = 1};
213 gv_xml_escape(span->str, xml_flags, agxbput_int, &xb);
214
215 if (flags & HTML_SUB)
216 agxbput(&xb,"</sub>");
217 if (flags & HTML_SUP)
218 agxbput(&xb,"</sup>");
219
220 agxbput (&xb,"</span>");
221 if (!pango_parse_markup (agxbuse(&xb), -1, 0, &attrs, &text, NULL, &error)) {
222 fprintf (stderr, "Error - pango_parse_markup: %s\n", error->message);
223 text = span->str;
224 attrs = NULL;
225 } else {
226 text_needs_free = true;
227 }
228 agxbfree (&xb);
229 }
230 else {
231 text = span->str;
232 attrs = NULL;
233 }
234#else
235 text = span->str;
236#endif
237
238 PangoLayout *layout = pango_layout_new (context);
239 span->layout = layout; /* layout free with textspan - see labels.c */
240 span->free_layout = pango_free_layout; /* function for freeing pango layout */
241
242 pango_layout_set_text (layout, text, -1);
243 pango_layout_set_font_description (layout, desc);
244#ifdef ENABLE_PANGO_MARKUP
245 if (attrs)
246 pango_layout_set_attributes (layout, attrs);
247#endif
248
249 PangoRectangle logical_rect;
250 pango_layout_get_extents (layout, NULL, &logical_rect);
251
252 /* if pango doesn't like the font then it sets width=0 but height = garbage */
253 if (logical_rect.width == 0)
254 logical_rect.height = 0;
255
256 const double textlayout_scale = POINTS_PER_INCH / (FONT_DPI * PANGO_SCALE);
257 span->size.x = logical_rect.width * textlayout_scale;
258 span->size.y = logical_rect.height * textlayout_scale;
259
260 /* The y offset from baseline to 0,0 of the bitmap representation */
261 span->yoffset_layout = pango_layout_get_baseline (layout) * textlayout_scale;
262
263 /* The distance below midline for y centering of text strings */
264 span->yoffset_centerline = 0.05 * span->font->size;
265
266 const bool rc = logical_rect.width != 0 || strcmp(text, "") == 0;
267 if (text_needs_free) {
268 g_free(text);
269 }
270 return rc;
271}
272
276
278 {0, "textlayout", 10, &pango_textlayout_engine, NULL},
279 {0, NULL, 0, NULL, NULL}
280};
static void agxbfree(agxbuf *xb)
free any malloced resources
Definition agxbuf.h:78
static int agxbprint(agxbuf *xb, const char *fmt,...)
Printf-style output to an agxbuf.
Definition agxbuf.h:234
static void agxbclear(agxbuf *xb)
resets pointer to data
Definition agxbuf.h:294
static WUR char * agxbuse(agxbuf *xb)
Definition agxbuf.h:307
static char * agxbdisown(agxbuf *xb)
Definition agxbuf.h:327
Memory allocation wrappers that exit on failure.
static char * gv_strdup(const char *original)
Definition alloc.h:101
static int flags
Definition gc.c:61
#define POINTS_PER_INCH
Definition geom.h:58
static double len(glCompPoint p)
Definition glutils.c:150
void free(void *)
node NULL
Definition grammar.y:163
Arithmetic helper functions.
static bool is_exactly_equal(double a, double b)
are two values precisely the same?
Definition gv_math.h:44
agxbput(xb, staging)
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:300
table Syntax error
Definition htmlparse.y:294
static int layout(graph_t *g, layout_info *infop)
Definition layout.c:814
ingroup plugin_api
Definition gvplugin.h:35
Definition gvpr.c:60
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
options to tweak the behavior of XML escaping
Definition xml.h:30
unsigned raw
assume no embedded escapes, and escape "\n" and "\r"
Definition xml.h:32
#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 gv_xml_escape(const char *s, xml_flags_t flags, int(*cb)(void *state, const char *s), void *state)
Definition xml.c:178
XML escaping functionality.