Graphviz  2.41.20171026.1811
gvtextlayout_pango.c
Go to the documentation of this file.
1 /* $Id$ $Revision$ */
2 /* vim:set shiftwidth=4 ts=8: */
3 
4 /*************************************************************************
5  * Copyright (c) 2011 AT&T Intellectual Property
6  * All rights reserved. This program and the accompanying materials
7  * are made available under the terms of the Eclipse Public License v1.0
8  * which accompanies this distribution, and is available at
9  * http://www.eclipse.org/legal/epl-v10.html
10  *
11  * Contributors: See CVS logs. Details at http://www.graphviz.org/
12  *************************************************************************/
13 
14 #include "config.h"
15 
16 #include <stdlib.h>
17 #include <string.h>
18 #include "gvplugin_render.h"
19 #include "agxbuf.h"
20 #include "utils.h"
21 #include "gvplugin_textlayout.h"
22 
23 #include <pango/pangocairo.h>
24 #include "gvgetfontlist.h"
25 #ifdef HAVE_PANGO_FC_FONT_LOCK_FACE
26 #include <pango/pangofc-font.h>
27 #endif
28 
29 #define N_NEW(n,t) (t*)malloc((n)*sizeof(t))
30 
31 static void pango_free_layout (void *layout)
32 {
33  g_object_unref((PangoLayout*)layout);
34 }
35 
36 static char* pango_psfontResolve (PostscriptAlias* pa)
37 {
38  static char buf[1024];
39  strcpy(buf, pa->family);
40  strcat(buf, ",");
41  if (pa->weight) {
42  strcat(buf, " ");
43  strcat(buf, pa->weight);
44  }
45  if (pa->stretch) {
46  strcat(buf, " ");
47  strcat(buf, pa->stretch);
48  }
49  if (pa->style) {
50  strcat(buf, " ");
51  strcat(buf, pa->style);
52  }
53  return buf;
54 }
55 
56 #define FONT_DPI 96.
57 
58 #define ENABLE_PANGO_MARKUP
59 #ifdef ENABLE_PANGO_MARKUP
60 #define FULL_MARKUP "<span weight=\"bold\" style=\"italic\" underline=\"single\"><sup><sub></sub></sup></span>"
61 #endif
62 
63 static boolean pango_textlayout(textspan_t * span, char **fontpath)
64 {
65  static char buf[1024]; /* returned in fontpath, only good until next call */
66  static PangoFontMap *fontmap;
67  static PangoContext *context;
68  static PangoFontDescription *desc;
69  static char *fontname;
70  static double fontsize;
71  static gv_font_map* gv_fmap;
72  char *fnt, *psfnt = NULL;
73  PangoLayout *layout;
74  PangoRectangle logical_rect;
75  cairo_font_options_t* options;
76  PangoFont *font;
77 #ifdef ENABLE_PANGO_MARKUP
78  PangoAttrList *attrs;
79  GError *error = NULL;
80  int flags;
81 #endif
82  char *text;
83  double textlayout_scale;
84  PostscriptAlias *pA;
85 
86  if (!context) {
87  fontmap = pango_cairo_font_map_new();
88  gv_fmap = get_font_mapping(fontmap);
89 #ifdef HAVE_PANGO_FONT_MAP_CREATE_CONTEXT
90  context = pango_font_map_create_context (fontmap);
91 #else
92  context = pango_cairo_font_map_create_context (PANGO_CAIRO_FONT_MAP(fontmap));
93 #endif
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  fontname = span->font->name;
107  fontsize = span->font->size;
108  pango_font_description_free (desc);
109 
110  pA = span->font->postscript_alias;
111  if (pA) {
112  psfnt = fnt = gv_fmap[pA->xfig_code].gv_font;
113  if(!psfnt)
114  psfnt = fnt = pango_psfontResolve (pA);
115  }
116  else
117  fnt = fontname;
118 
119  desc = pango_font_description_from_string(fnt);
120  /* all text layout is done at a scale of FONT_DPI (nominaly 96.) */
121  pango_font_description_set_size (desc, (gint)(fontsize * PANGO_SCALE));
122 
123  if (fontpath && (font = pango_font_map_load_font(fontmap, context, desc))) { /* -v support */
124  const char *fontclass;
125 
126  fontclass = G_OBJECT_CLASS_NAME(G_OBJECT_GET_CLASS(font));
127 
128  buf[0] = '\0';
129  if (psfnt) {
130  strcat(buf, "(ps:pango ");
131  strcat(buf, psfnt);
132  strcat(buf, ") ");
133  }
134  strcat(buf, "(");
135  strcat(buf, fontclass);
136  strcat(buf, ") ");
137 #ifdef HAVE_PANGO_FC_FONT_LOCK_FACE
138  if (strcmp(fontclass, "PangoCairoFcFont") == 0) {
139  FT_Face face;
140  PangoFcFont *fcfont;
141  FT_Stream stream;
142  FT_StreamDesc streamdesc;
143  fcfont = PANGO_FC_FONT(font);
144  face = pango_fc_font_lock_face(fcfont);
145  if (face) {
146  strcat(buf, "\"");
147  strcat(buf, face->family_name);
148  strcat(buf, ", ");
149  strcat(buf, face->style_name);
150  strcat(buf, "\" ");
151 
152  stream = face->stream;
153  if (stream) {
154  streamdesc = stream->pathname;
155  if (streamdesc.pointer)
156  strcat(buf, (char*)streamdesc.pointer);
157  else
158  strcat(buf, "*no pathname available*");
159  }
160  else
161  strcat(buf, "*no stream available*");
162  }
163  pango_fc_font_unlock_face(fcfont);
164  }
165  else
166 #endif
167  {
168  PangoFontDescription *tdesc;
169  char *tfont;
170 
171  tdesc = pango_font_describe(font);
172  tfont = pango_font_description_to_string(tdesc);
173  strcat(buf, "\"");
174  strcat(buf, tfont);
175  strcat(buf, "\" ");
176  g_free(tfont);
177  }
178  *fontpath = buf;
179  }
180  }
181 
182 #ifdef ENABLE_PANGO_MARKUP
183  if ((span->font) && (flags = span->font->flags)) {
184  unsigned char buf[BUFSIZ];
185  agxbuf xb;
186 
187  agxbinit(&xb, BUFSIZ, buf);
188  agxbput(&xb,"<span");
189 
190  if (flags & HTML_BF)
191  agxbput(&xb," weight=\"bold\"");
192  if (flags & HTML_IF)
193  agxbput(&xb," style=\"italic\"");
194  if (flags & HTML_UL)
195  agxbput(&xb," underline=\"single\"");
196  if (flags & HTML_S)
197  agxbput(&xb," strikethrough=\"true\"");
198  agxbput (&xb,">");
199 
200  if (flags & HTML_SUP)
201  agxbput(&xb,"<sup>");
202  if (flags & HTML_SUB)
203  agxbput(&xb,"<sub>");
204 
205  agxbput (&xb,xml_string0(span->str, TRUE));
206 
207  if (flags & HTML_SUB)
208  agxbput(&xb,"</sub>");
209  if (flags & HTML_SUP)
210  agxbput(&xb,"</sup>");
211 
212  agxbput (&xb,"</span>");
213  if (!pango_parse_markup (agxbuse(&xb), -1, 0, &attrs, &text, NULL, &error)) {
214  fprintf (stderr, "Error - pango_parse_markup: %s\n", error->message);
215  text = span->str;
216  attrs = NULL;
217  }
218  agxbfree (&xb);
219  }
220  else {
221  text = span->str;
222  attrs = NULL;
223  }
224 #else
225  text = span->str;
226 #endif
227 
228  layout = pango_layout_new (context);
229  span->layout = (void *)layout; /* layout free with textspan - see labels.c */
230  span->free_layout = pango_free_layout; /* function for freeing pango layout */
231 
232  pango_layout_set_text (layout, text, -1);
233  pango_layout_set_font_description (layout, desc);
234 #ifdef ENABLE_PANGO_MARKUP
235  if (attrs)
236  pango_layout_set_attributes (layout, attrs);
237 #endif
238 
239  pango_layout_get_extents (layout, NULL, &logical_rect);
240 
241  /* if pango doesn't like the font then it sets width=0 but height = garbage */
242  if (logical_rect.width == 0)
243  logical_rect.height = 0;
244 
245  textlayout_scale = POINTS_PER_INCH / (FONT_DPI * PANGO_SCALE);
246  span->size.x = (int)(logical_rect.width * textlayout_scale + 1); /* round up so that width/height are never too small */
247  span->size.y = (int)(logical_rect.height * textlayout_scale + 1);
248 
249  /* FIXME -- Horrible kluge !!! */
250 
251  /* For now we are using pango for single line blocks only.
252  * The logical_rect.height seems to be too high from the font metrics on some platforms.
253  * Use an assumed height based on the point size.
254  */
255 
256  span->size.y = (int)(span->font->size * 1.1 + .5);
257 
258  /* The y offset from baseline to 0,0 of the bitmap representation */
259 #if !defined(_WIN32) && defined PANGO_VERSION_MAJOR && (PANGO_VERSION_MAJOR >= 1)
260  span->yoffset_layout = pango_layout_get_baseline (layout) * textlayout_scale;
261 #else
262  {
263  /* do it the hard way on rhel5/centos5 */
264  PangoLayoutIter *iter = pango_layout_get_iter (layout);
265  span->yoffset_layout = pango_layout_iter_get_baseline (iter) * textlayout_scale;
266  }
267 #endif
268 
269  /* The distance below midline for y centering of text strings */
270  span->yoffset_centerline = 0.2 * span->font->size;
271 
272  if (logical_rect.width == 0)
273  return FALSE;
274  return TRUE;
275 }
276 
277 static gvtextlayout_engine_t pango_textlayout_engine = {
278  pango_textlayout,
279 };
280 
282  {0, "textlayout", 10, &pango_textlayout_engine, NULL},
283  {0, NULL, 0, NULL, NULL}
284 };
pointf size
Definition: textspan.h:64
#define agxbuse(X)
Definition: agxbuf.h:83
#define HTML_S
Definition: textspan.h:29
#define HTML_IF
Definition: textspan.h:25
bool layout(Agraph_t *g, const char *engine)
Definition: gv.cpp:809
char * weight
Definition: textspan.h:35
#define HTML_BF
Definition: textspan.h:24
double size
Definition: textspan.h:52
char * stretch
Definition: textspan.h:36
size_t agxbput(agxbuf *xb, const char *s)
Definition: agxbuf.c:84
char * name
Definition: textspan.h:49
gvplugin_installed_t gvtextlayout_pango_types[]
#define HTML_SUB
Definition: textspan.h:28
#define POINTS_PER_INCH
Definition: geom.h:62
char * str
Definition: textspan.h:59
unsigned int flags
Definition: textspan.h:53
int
Definition: grammar.c:1264
double y
Definition: geom.h:28
char * gv_font
Definition: gvgetfontlist.h:25
double yoffset_centerline
Definition: textspan.h:63
PostscriptAlias * postscript_alias
Definition: textspan.h:51
void agxbinit(agxbuf *xb, unsigned int hint, unsigned char *init)
Definition: agxbuf.c:25
#define HTML_UL
Definition: textspan.h:26
gv_font_map * get_font_mapping(PangoFontMap *pfm)
#define NULL
Definition: logic.h:39
double yoffset_layout
Definition: textspan.h:63
double x
Definition: geom.h:28
#define HTML_SUP
Definition: textspan.h:27
char * style
Definition: textspan.h:37
#define FONT_DPI
void(* free_layout)(void *layout)
Definition: textspan.h:62
Definition: agxbuf.h:34
char * family
Definition: textspan.h:34
void agxbfree(agxbuf *xb)
Definition: agxbuf.c:94
#define FALSE
Definition: cgraph.h:35
textfont_t * font
Definition: textspan.h:60
char * xml_string0(char *s, boolean raw)
Definition: labels.c:497
void * layout
Definition: textspan.h:61
#define TRUE
Definition: cgraph.h:38