Graphviz 13.0.0~dev.20241220.2304
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
25#include <pango/pangocairo.h>
26#include "gvgetfontlist.h"
27#ifdef HAVE_PANGO_FC_FONT_LOCK_FACE
28#include <pango/pangofc-font.h>
29#endif
30
31static void pango_free_layout (void *layout)
32{
33 g_object_unref(layout);
34}
35
37{
38 agxbuf buf = {0};
39 agxbprint(&buf, "%s,", pa->family);
40 if (pa->weight) {
41 agxbprint(&buf, " %s", pa->weight);
42 }
43 if (pa->stretch) {
44 agxbprint(&buf, " %s", pa->stretch);
45 }
46 if (pa->style) {
47 agxbprint(&buf, " %s", pa->style);
48 }
49 return agxbdisown(&buf);
50}
51
52#define FONT_DPI 96.
53
54#define ENABLE_PANGO_MARKUP
55
56// wrapper to handle difference in calling conventions between `agxbput` and
57// `xml_escape`’s `cb`
58static int agxbput_int(void *buffer, const char *s) {
59 size_t len = agxbput(buffer, s);
60 assert(len <= INT_MAX);
61 return (int)len;
62}
63
64static bool pango_textlayout(textspan_t * span, char **fontpath)
65{
66 static agxbuf buf; // returned in fontpath, only good until next call
67 static PangoFontMap *fontmap;
68 static PangoContext *context;
69 static PangoFontDescription *desc;
70 static char *fontname;
71 static double fontsize;
72 static gv_font_map* gv_fmap;
73 char *fnt, *psfnt = NULL;
74 PangoFont *font;
75#ifdef ENABLE_PANGO_MARKUP
76 PangoAttrList *attrs;
77 GError *error = NULL;
78 int flags;
79#endif
80 char *text;
81
82 if (!context) {
83 fontmap = pango_cairo_font_map_new();
84 gv_fmap = get_font_mapping(fontmap);
85 context = pango_font_map_create_context (fontmap);
86 cairo_font_options_t* options = cairo_font_options_create();
87 cairo_font_options_set_antialias(options,CAIRO_ANTIALIAS_GRAY);
88 cairo_font_options_set_hint_style(options,CAIRO_HINT_STYLE_FULL);
89 cairo_font_options_set_hint_metrics(options,CAIRO_HINT_METRICS_ON);
90 cairo_font_options_set_subpixel_order(options,CAIRO_SUBPIXEL_ORDER_BGR);
91 pango_cairo_context_set_font_options(context, options);
92 pango_cairo_context_set_resolution(context, FONT_DPI);
93 cairo_font_options_destroy(options);
94 g_object_unref(fontmap);
95 }
96
97 if (!fontname || strcmp(fontname, span->font->name) != 0 ||
98 !is_exactly_equal(fontsize, span->font->size)) {
99
100 /* check if the conversion to Pango units below will overflow */
101 if (INT_MAX / PANGO_SCALE < span->font->size) {
102 return false;
103 }
104
105 free(fontname);
106 fontname = gv_strdup(span->font->name);
107 fontsize = span->font->size;
108 pango_font_description_free (desc);
109
111 bool psfnt_needs_free = false;
112 if (pA) {
113 psfnt = fnt = gv_fmap[pA->xfig_code].gv_font;
114 if(!psfnt) {
115 psfnt = fnt = pango_psfontResolve (pA);
116 psfnt_needs_free = true;
117 }
118 }
119 else
120 fnt = fontname;
121
122 desc = pango_font_description_from_string(fnt);
123 /* all text layout is done at a scale of FONT_DPI (nominaly 96.) */
124 pango_font_description_set_size (desc, (int)(fontsize * PANGO_SCALE));
125
126 if (fontpath && (font = pango_font_map_load_font(fontmap, context, desc))) { /* -v support */
127 const char *fontclass = G_OBJECT_CLASS_NAME(G_OBJECT_GET_CLASS(font));
128
129 agxbclear(&buf);
130 if (psfnt) {
131 agxbprint(&buf, "(ps:pango %s) ", psfnt);
132 }
133 agxbprint(&buf, "(%s) ", fontclass);
134#ifdef HAVE_PANGO_FC_FONT_LOCK_FACE
135 if (strcmp(fontclass, "PangoCairoFcFont") == 0) {
136 PangoFcFont *fcfont = PANGO_FC_FONT(font);
137// `pango_fc_font_lock_face` arrived in Pango 1.4 and then was deprecated in
138// 1.44. Its replacement is `pango_font_get_hb_font`. However this replacement
139// does not seem to provide access to the underlying FreeType font information
140// we want. Since this code path is only enabled when `pango_fc_font_lock_face`
141// is available, suppress deprecation warnings and we will have to deal with the
142// loss of this informational output altogether when Pango finally removes it.
143#if __GNUC__
144#pragma GCC diagnostic push
145#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
146#endif
147 FT_Face face = pango_fc_font_lock_face(fcfont);
148#ifdef __GNUC__
149#pragma GCC diagnostic pop
150#endif
151 if (face) {
152 agxbprint(&buf, "\"%s, %s\" ", face->family_name, face->style_name);
153
154 FT_Stream stream = face->stream;
155 if (stream) {
156 FT_StreamDesc streamdesc = stream->pathname;
157 if (streamdesc.pointer)
158 agxbput(&buf, streamdesc.pointer);
159 else
160 agxbput(&buf, "*no pathname available*");
161 }
162 else
163 agxbput(&buf, "*no stream available*");
164 }
165#if __GNUC__
166#pragma GCC diagnostic push
167#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
168#endif
169 pango_fc_font_unlock_face(fcfont);
170#ifdef __GNUC__
171#pragma GCC diagnostic pop
172#endif
173 }
174 else
175#endif
176 {
177 PangoFontDescription *tdesc = pango_font_describe(font);
178 char *tfont = pango_font_description_to_string(tdesc);
179 agxbprint(&buf, "\"%s\" ", tfont);
180 g_free(tfont);
181 }
182 *fontpath = agxbuse(&buf);
183 }
184 if (psfnt_needs_free) {
185 free(psfnt);
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 PangoLayout *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 PangoRectangle logical_rect;
246 pango_layout_get_extents (layout, NULL, &logical_rect);
247
248 /* if pango doesn't like the font then it sets width=0 but height = garbage */
249 if (logical_rect.width == 0)
250 logical_rect.height = 0;
251
252 const double textlayout_scale = POINTS_PER_INCH / (FONT_DPI * PANGO_SCALE);
253 span->size.x = logical_rect.width * textlayout_scale;
254 span->size.y = logical_rect.height * textlayout_scale;
255
256 /* The y offset from baseline to 0,0 of the bitmap representation */
257 span->yoffset_layout = pango_layout_get_baseline (layout) * textlayout_scale;
258
259 /* The distance below midline for y centering of text strings */
260 span->yoffset_centerline = 0.05 * span->font->size;
261
262 return logical_rect.width != 0 || strcmp(text, "") == 0;
263}
264
268
270 {0, "textlayout", 10, &pango_textlayout_engine, NULL},
271 {0, NULL, 0, NULL, NULL}
272};
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:64
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:43
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:811
ingroup plugin_api
Definition gvplugin.h:35
Definition gvpr.c:64
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