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