Graphviz  2.35.20130930.0449
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(textpara_t * para, 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 
88  if (!context) {
89  fontmap = pango_cairo_font_map_new();
90  gv_fmap = get_font_mapping(fontmap);
91  context = pango_cairo_font_map_create_context (PANGO_CAIRO_FONT_MAP(fontmap));
92  options=cairo_font_options_create();
93  cairo_font_options_set_antialias(options,CAIRO_ANTIALIAS_GRAY);
94  cairo_font_options_set_hint_style(options,CAIRO_HINT_STYLE_FULL);
95  cairo_font_options_set_hint_metrics(options,CAIRO_HINT_METRICS_ON);
96  cairo_font_options_set_subpixel_order(options,CAIRO_SUBPIXEL_ORDER_BGR);
97  pango_cairo_context_set_font_options(context, options);
98  pango_cairo_context_set_resolution(context, FONT_DPI);
99  cairo_font_options_destroy(options);
100  g_object_unref(fontmap);
101  }
102 
103  if (!fontname || strcmp(fontname, para->fontname) != 0 || fontsize != para->fontsize) {
104  fontname = para->fontname;
105  fontsize = para->fontsize;
106  pango_font_description_free (desc);
107 
108  if (para->postscript_alias) {
109  psfnt = fnt = gv_fmap[para->postscript_alias->xfig_code].gv_font;
110  if(!psfnt)
111  psfnt = fnt = pango_psfontResolve (para->postscript_alias);
112  }
113  else
114  fnt = fontname;
115 
116  desc = pango_font_description_from_string(fnt);
117  /* all text layout is done at a scale of FONT_DPI (nominaly 96.) */
118  pango_font_description_set_size (desc, (gint)(fontsize * PANGO_SCALE));
119 
120  if (fontpath && (font = pango_font_map_load_font(fontmap, context, desc))) { /* -v support */
121  const char *fontclass;
122 
123  fontclass = G_OBJECT_CLASS_NAME(G_OBJECT_GET_CLASS(font));
124 
125  buf[0] = '\0';
126  if (psfnt) {
127  strcat(buf, "(ps:pango ");
128  strcat(buf, psfnt);
129  strcat(buf, ") ");
130  }
131  strcat(buf, "(");
132  strcat(buf, fontclass);
133  strcat(buf, ") ");
134 #ifdef HAVE_PANGO_FC_FONT_LOCK_FACE
135  if (strcmp(fontclass, "PangoCairoFcFont") == 0) {
136  FT_Face face;
137  PangoFcFont *fcfont;
138  FT_Stream stream;
139  FT_StreamDesc streamdesc;
140  fcfont = PANGO_FC_FONT(font);
141  face = pango_fc_font_lock_face(fcfont);
142  if (face) {
143  strcat(buf, "\"");
144  strcat(buf, face->family_name);
145  strcat(buf, ", ");
146  strcat(buf, face->style_name);
147  strcat(buf, "\" ");
148 
149  stream = face->stream;
150  if (stream) {
151  streamdesc = stream->pathname;
152  if (streamdesc.pointer)
153  strcat(buf, (char*)streamdesc.pointer);
154  else
155  strcat(buf, "*no pathname available*");
156  }
157  else
158  strcat(buf, "*no stream available*");
159  }
160  pango_fc_font_unlock_face(fcfont);
161  }
162  else
163 #endif
164  {
165  PangoFontDescription *tdesc;
166  char *tfont;
167 
168  tdesc = pango_font_describe(font);
169  tfont = pango_font_description_to_string(tdesc);
170  strcat(buf, "\"");
171  strcat(buf, tfont);
172  strcat(buf, "\" ");
173  g_free(tfont);
174  }
175  *fontpath = buf;
176  }
177  }
178 
179 #ifdef ENABLE_PANGO_MARKUP
180  if ((para->font) && (flags = para->font->flags)) {
181  unsigned char buf[BUFSIZ];
182  agxbuf xb;
183 
184  agxbinit(&xb, BUFSIZ, buf);
185  agxbput(&xb,"<span");
186 
187  if (flags & HTML_BF)
188  agxbput(&xb," weight=\"bold\"");
189  if (flags & HTML_IF)
190  agxbput(&xb," style=\"italic\"");
191  if (flags & HTML_UL)
192  agxbput(&xb," underline=\"single\"");
193  if (flags & HTML_S)
194  agxbput(&xb," strikethrough=\"true\"");
195  agxbput (&xb,">");
196 
197  if (flags & HTML_SUP)
198  agxbput(&xb,"<sup>");
199  if (flags & HTML_SUB)
200  agxbput(&xb,"<sub>");
201 
202  agxbput (&xb,xml_string(para->str));
203 
204  if (flags & HTML_SUB)
205  agxbput(&xb,"</sub>");
206  if (flags & HTML_SUP)
207  agxbput(&xb,"</sup>");
208 
209  agxbput (&xb,"</span>");
210  if (!pango_parse_markup (agxbuse(&xb), -1, 0, &attrs, &text, NULL, &error)) {
211  fprintf (stderr, "Error - pango_parse_markup: %s\n", error->message);
212  text = para->str;
213  attrs = NULL;
214  }
215  agxbfree (&xb);
216  }
217  else {
218  text = para->str;
219  attrs = NULL;
220  }
221 #else
222  text = para->str;
223 #endif
224 
225  layout = pango_layout_new (context);
226  para->layout = (void *)layout; /* layout free with textpara - see labels.c */
227  para->free_layout = pango_free_layout; /* function for freeing pango layout */
228 
229  pango_layout_set_text (layout, text, -1);
230  pango_layout_set_font_description (layout, desc);
231 #ifdef ENABLE_PANGO_MARKUP
232  if (attrs)
233  pango_layout_set_attributes (layout, attrs);
234 #endif
235 
236  pango_layout_get_extents (layout, NULL, &logical_rect);
237 
238  /* if pango doesn't like the font then it sets width=0 but height = garbage */
239  if (logical_rect.width == 0)
240  logical_rect.height = 0;
241 
242  textlayout_scale = POINTS_PER_INCH / (FONT_DPI * PANGO_SCALE);
243  para->width = (int)(logical_rect.width * textlayout_scale + 1); /* round up so that width/height are never too small */
244  para->height = (int)(logical_rect.height * textlayout_scale + 1);
245 
246  /* FIXME -- Horrible kluge !!! */
247 
248  /* For now we are using pango for single line blocks only.
249  * The logical_rect.height seems to be too high from the font metrics on some platforms.
250  * Use an assumed height based on the point size.
251  */
252 
253  para->height = (int)(para->fontsize * 1.1 + .5);
254 
255  /* The y offset from baseline to 0,0 of the bitmap representation */
256 #if defined PANGO_VERSION_MAJOR && (PANGO_VERSION_MAJOR >= 1)
257  para->yoffset_layout = pango_layout_get_baseline (layout) * textlayout_scale;
258 #else
259  {
260  /* do it the hard way on rhel5/centos5 */
261  PangoLayoutIter *iter = pango_layout_get_iter (layout);
262  para->yoffset_layout = pango_layout_iter_get_baseline (iter) * textlayout_scale;
263  }
264 #endif
265 
266  /* The distance below midline for y centering of text strings */
267  para->yoffset_centerline = 0.2 * para->fontsize;
268 
269  if (logical_rect.width == 0)
270  return FALSE;
271  return TRUE;
272 }
273 
274 static gvtextlayout_engine_t pango_textlayout_engine = {
275  pango_textlayout,
276 };
277 #endif
278 
280 #ifdef HAVE_PANGOCAIRO
281  {0, "textlayout", 10, &pango_textlayout_engine, NULL},
282 #endif
283  {0, NULL, 0, NULL, NULL}
284 };