static void svg_begin_anchor(GVJ_t * job, char *href, char *tooltip, char *target, char *id) { gvputs(job, "<g"); if (id) { gvputs(job, " id=\"a_"); gvputs(job, xml_string(id)); gvputs(job, "\""); } gvputs(job, ">"); gvputs(job, "<a"); #if 0 /* the svg spec implies this can be omitted: http://www.w3.org/TR/SVG/linking.html#Links */ gvputs(job, " xlink:type=\"simple\""); #endif if (href && href[0]) { gvputs(job, " xlink:href=\""); gvputs(job, href); gvputs(job, "\""); } #if 0 /* linking to itself, just so that it can have a xlink:link in the anchor, seems wrong. * it changes the behavior in browsers, the link apears in the bottom information bar */ else { assert(id && id[0]); /* there should always be an id available */ gvputs(job, " xlink:href=\"#"); gvputs(job, xml_url_string(href)); gvputs(job, "\""); } #endif if (tooltip && tooltip[0]) { gvputs(job, " xlink:title=\""); gvputs(job, xml_string0(tooltip, 1)); gvputs(job, "\""); } if (target && target[0]) { gvputs(job, " target=\""); gvputs(job, xml_string(target)); gvputs(job, "\""); } gvputs(job, ">\n"); }
static void svg_textspan(GVJ_t * job, pointf p, textspan_t * span) { obj_state_t *obj = job->obj; PostscriptAlias *pA; char *family = NULL, *weight = NULL, *stretch = NULL, *style = NULL; unsigned int flags; gvputs(job, "<text"); switch (span->just) { case 'l': gvputs(job, " text-anchor=\"start\""); break; case 'r': gvputs(job, " text-anchor=\"end\""); break; default: case 'n': gvputs(job, " text-anchor=\"middle\""); break; } p.y += span->yoffset_centerline; if (!obj->labeledgealigned) gvprintf(job, " x=\"%g\" y=\"%g\"", p.x, -p.y); pA = span->font->postscript_alias; if (pA) { switch (GD_fontnames(job->gvc->g)) { case PSFONTS: family = pA->name; weight = pA->weight; style = pA->style; break; case SVGFONTS: family = pA->svg_font_family; weight = pA->svg_font_weight; style = pA->svg_font_style; break; default: case NATIVEFONTS: family = pA->family; weight = pA->weight; style = pA->style; break; } stretch = pA->stretch; gvprintf(job, " font-family=\"%s", family); if (pA->svg_font_family) gvprintf(job, ",%s", pA->svg_font_family); gvputs(job, "\""); if (weight) gvprintf(job, " font-weight=\"%s\"", weight); if (stretch) gvprintf(job, " font-stretch=\"%s\"", stretch); if (style) gvprintf(job, " font-style=\"%s\"", style); } else gvprintf(job, " font-family=\"%s\"", span->font->name); if ((span->font) && (flags = span->font->flags)) { if ((flags & HTML_BF) && !weight) gvprintf(job, " font-weight=\"bold\""); if ((flags & HTML_IF) && !style) gvprintf(job, " font-style=\"italic\""); if ((flags & (HTML_UL|HTML_S|HTML_OL))) { int comma = 0; gvprintf(job, " text-decoration=\""); if ((flags & HTML_UL)) { gvprintf(job, "underline"); comma = 1; } if ((flags & HTML_OL)) { gvprintf(job, "%soverline", (comma?",":"")); comma = 1; } if ((flags & HTML_S)) gvprintf(job, "%sline-through", (comma?",":"")); gvprintf(job, "\""); } if ((flags & HTML_SUP)) gvprintf(job, " baseline-shift=\"super\""); if ((flags & HTML_SUB)) gvprintf(job, " baseline-shift=\"sub\""); } gvprintf(job, " font-size=\"%.2f\"", span->font->size); switch (obj->pencolor.type) { case COLOR_STRING: if (strcasecmp(obj->pencolor.u.string, "black")) gvprintf(job, " fill=\"%s\"", obj->pencolor.u.string); break; case RGBA_BYTE: gvprintf(job, " fill=\"#%02x%02x%02x\"", obj->pencolor.u.rgba[0], obj->pencolor.u.rgba[1], obj->pencolor.u.rgba[2]); break; default: assert(0); /* internal error */ } gvputs(job, ">"); if (obj->labeledgealigned) { gvprintf (job, "<textPath xlink:href=\"#%s_p\" startOffset=\"50%%\">", xml_string(obj->id)); gvprintf (job, "<tspan x=\"0\" dy=\"%g\">", -p.y); } gvputs(job, xml_string0(span->str, TRUE)); if (obj->labeledgealigned) gvprintf (job, "</tspan></textPath>"); gvputs(job, "</text>\n"); }
char *xml_string(char *s) { return xml_string0 (s, FALSE); }
static boolean pango_textlayout(textspan_t * span, char **fontpath) { static char buf[1024]; /* returned in fontpath, only good until next call */ static PangoFontMap *fontmap; static PangoContext *context; static PangoFontDescription *desc; static char *fontname; static double fontsize; static gv_font_map* gv_fmap; char *fnt, *psfnt = NULL; PangoLayout *layout; PangoRectangle logical_rect; cairo_font_options_t* options; PangoFont *font; #ifdef ENABLE_PANGO_MARKUP PangoAttrList *attrs; GError *error = NULL; int flags; #endif char *text; double textlayout_scale; PostscriptAlias *pA; if (!context) { fontmap = pango_cairo_font_map_new(); gv_fmap = get_font_mapping(fontmap); #ifdef HAVE_PANGO_FONT_MAP_CREATE_CONTEXT context = pango_font_map_create_context (fontmap); #else context = pango_cairo_font_map_create_context (PANGO_CAIRO_FONT_MAP(fontmap)); #endif options=cairo_font_options_create(); cairo_font_options_set_antialias(options,CAIRO_ANTIALIAS_GRAY); cairo_font_options_set_hint_style(options,CAIRO_HINT_STYLE_FULL); cairo_font_options_set_hint_metrics(options,CAIRO_HINT_METRICS_ON); cairo_font_options_set_subpixel_order(options,CAIRO_SUBPIXEL_ORDER_BGR); pango_cairo_context_set_font_options(context, options); pango_cairo_context_set_resolution(context, FONT_DPI); cairo_font_options_destroy(options); g_object_unref(fontmap); } if (!fontname || strcmp(fontname, span->font->name) != 0 || fontsize != span->font->size) { fontname = span->font->name; fontsize = span->font->size; pango_font_description_free (desc); pA = span->font->postscript_alias; if (pA) { psfnt = fnt = gv_fmap[pA->xfig_code].gv_font; if(!psfnt) psfnt = fnt = pango_psfontResolve (pA); } else fnt = fontname; desc = pango_font_description_from_string(fnt); /* all text layout is done at a scale of FONT_DPI (nominaly 96.) */ pango_font_description_set_size (desc, (gint)(fontsize * PANGO_SCALE)); if (fontpath && (font = pango_font_map_load_font(fontmap, context, desc))) { /* -v support */ const char *fontclass; fontclass = G_OBJECT_CLASS_NAME(G_OBJECT_GET_CLASS(font)); buf[0] = '\0'; if (psfnt) { strcat(buf, "(ps:pango "); strcat(buf, psfnt); strcat(buf, ") "); } strcat(buf, "("); strcat(buf, fontclass); strcat(buf, ") "); #ifdef HAVE_PANGO_FC_FONT_LOCK_FACE if (strcmp(fontclass, "PangoCairoFcFont") == 0) { FT_Face face; PangoFcFont *fcfont; FT_Stream stream; FT_StreamDesc streamdesc; fcfont = PANGO_FC_FONT(font); face = pango_fc_font_lock_face(fcfont); if (face) { strcat(buf, "\""); strcat(buf, face->family_name); strcat(buf, ", "); strcat(buf, face->style_name); strcat(buf, "\" "); stream = face->stream; if (stream) { streamdesc = stream->pathname; if (streamdesc.pointer) strcat(buf, (char*)streamdesc.pointer); else strcat(buf, "*no pathname available*"); } else strcat(buf, "*no stream available*"); } pango_fc_font_unlock_face(fcfont); } else #endif { PangoFontDescription *tdesc; char *tfont; tdesc = pango_font_describe(font); tfont = pango_font_description_to_string(tdesc); strcat(buf, "\""); strcat(buf, tfont); strcat(buf, "\" "); g_free(tfont); } *fontpath = buf; } } #ifdef ENABLE_PANGO_MARKUP if ((span->font) && (flags = span->font->flags)) { unsigned char buf[BUFSIZ]; agxbuf xb; agxbinit(&xb, BUFSIZ, buf); agxbput(&xb,"<span"); if (flags & HTML_BF) agxbput(&xb," weight=\"bold\""); if (flags & HTML_IF) agxbput(&xb," style=\"italic\""); if (flags & HTML_UL) agxbput(&xb," underline=\"single\""); if (flags & HTML_S) agxbput(&xb," strikethrough=\"true\""); agxbput (&xb,">"); if (flags & HTML_SUP) agxbput(&xb,"<sup>"); if (flags & HTML_SUB) agxbput(&xb,"<sub>"); agxbput (&xb,xml_string0(span->str, TRUE)); if (flags & HTML_SUB) agxbput(&xb,"</sub>"); if (flags & HTML_SUP) agxbput(&xb,"</sup>"); agxbput (&xb,"</span>"); if (!pango_parse_markup (agxbuse(&xb), -1, 0, &attrs, &text, NULL, &error)) { fprintf (stderr, "Error - pango_parse_markup: %s\n", error->message); text = span->str; attrs = NULL; } agxbfree (&xb); } else { text = span->str; attrs = NULL; } #else text = span->str; #endif layout = pango_layout_new (context); span->layout = (void *)layout; /* layout free with textspan - see labels.c */ span->free_layout = pango_free_layout; /* function for freeing pango layout */ pango_layout_set_text (layout, text, -1); pango_layout_set_font_description (layout, desc); #ifdef ENABLE_PANGO_MARKUP if (attrs) pango_layout_set_attributes (layout, attrs); #endif pango_layout_get_extents (layout, NULL, &logical_rect); /* if pango doesn't like the font then it sets width=0 but height = garbage */ if (logical_rect.width == 0) logical_rect.height = 0; textlayout_scale = POINTS_PER_INCH / (FONT_DPI * PANGO_SCALE); span->size.x = (int)(logical_rect.width * textlayout_scale + 1); /* round up so that width/height are never too small */ span->size.y = (int)(logical_rect.height * textlayout_scale + 1); /* FIXME -- Horrible kluge !!! */ /* For now we are using pango for single line blocks only. * The logical_rect.height seems to be too high from the font metrics on some platforms. * Use an assumed height based on the point size. */ span->size.y = (int)(span->font->size * 1.1 + .5); /* The y offset from baseline to 0,0 of the bitmap representation */ #if !defined(WIN32) && defined PANGO_VERSION_MAJOR && (PANGO_VERSION_MAJOR >= 1) span->yoffset_layout = pango_layout_get_baseline (layout) * textlayout_scale; #else { /* do it the hard way on rhel5/centos5 */ PangoLayoutIter *iter = pango_layout_get_iter (layout); span->yoffset_layout = pango_layout_iter_get_baseline (iter) * textlayout_scale; } #endif /* The distance below midline for y centering of text strings */ span->yoffset_centerline = 0.2 * span->font->size; if (logical_rect.width == 0) return FALSE; return TRUE; }