TGlyphInfo *glyph_cache_get_info(TGlyphCache *cache, gunichar glyph) { TGlyphInfo *gfi; XftFont *xftfont; PangoFont *font; PangoGlyph pglyph; PangoRectangle ink, logical; gint ascent, descent; gint x_offset; gint nominal_width; double scale_y, scale_x; if (!cache->hash) return NULL; gfi = g_hash_table_lookup(cache->hash, GINT_TO_POINTER(glyph)); if (gfi) return gfi; font = pango_fontset_get_font(cache->font_set, glyph); pglyph = pango_fc_font_get_glyph(PANGO_FC_FONT(font), glyph); if (!pglyph) { fprintf (stderr, "Error: Unable to find glyph %d.\n", glyph); if (!pglyph) pglyph = pango_fc_font_get_glyph(PANGO_FC_FONT(font), glyph); if (!pglyph) pglyph = PANGO_GET_UNKNOWN_GLYPH (glyph); if (!pglyph) return NULL; } pango_font_get_glyph_extents(font, pglyph, &ink, &logical); ascent = PANGO_ASCENT(logical); descent = PANGO_DESCENT(logical); xftfont = pango_xft_font_get_font(font); x_offset = 0; nominal_width = cache->width; if (g_unichar_iswide(glyph)) nominal_width *= 2; scale_x = scale_y = 1.0; if (logical.width > nominal_width) { if (logical.width) scale_x = (double)nominal_width / (double)logical.width; else scale_x = 1.0; } if (logical.height != cache->height) { double scale; if (ascent) { scale_y = (double)cache->ascent / (double)ascent; } else { scale_y = 1.0; } if (descent) { scale = (double)cache->descent / (double)descent; if (scale < scale_y) scale_y = scale; } } if (scale_x >= 1.0) { scale_x = 1.0; x_offset += (nominal_width - logical.width) / 2; } if (scale_x < 1.0 || scale_y != 1.0) { FcBool scalable; FcPatternGetBool(xftfont->pattern, FC_SCALABLE, 0, &scalable); if (!scalable) { /* Bah. Need better handling of non-scalable fonts */ if (scale_x < 1.0) scale_x = 1.0; scale_y = 1.0; } else if (scale_x < 1.0 || scale_y != 1.0) { FcPattern *pattern; FcMatrix mat; pattern = FcPatternDuplicate(xftfont->pattern); FcMatrixInit (&mat); FcMatrixScale(&mat, scale_x, scale_y); FcPatternDel (pattern, FC_MATRIX); FcPatternAddMatrix(pattern, FC_MATRIX, &mat); xftfont = XftFontOpenPattern( GDK_DISPLAY_XDISPLAY(cache->display), pattern ); } ascent = ascent * scale_y; } g_object_unref(font); // gfi = calloc(sizeof(TGlyphInfo), 1); gfi = g_slice_new(TGlyphInfo); gfi->font = xftfont; gfi->x_offset = PANGO_PIXELS(x_offset); gfi->y_offset = cache->ascent + (cache->ascent - ascent); gfi->y_offset = PANGO_PIXELS(gfi->y_offset); g_hash_table_insert(cache->hash, GINT_TO_POINTER(glyph), gfi); return gfi; }
gboolean text_get_extents (const gchar *fontname, const gchar *text, gint *width, gint *height, gint *ascent, gint *descent) { PangoFontDescription *font_desc; PangoContext *context; PangoLayout *layout; PangoFontMap *fontmap; PangoRectangle rect; g_return_val_if_fail (fontname != NULL, FALSE); g_return_val_if_fail (text != NULL, FALSE); fontmap = pango_cairo_font_map_new_for_font_type (CAIRO_FONT_TYPE_FT); if (! fontmap) g_error ("You are using a Pango that has been built against a cairo " "that lacks the Freetype font backend"); pango_cairo_font_map_set_resolution (PANGO_CAIRO_FONT_MAP (fontmap), 72.0); /* FIXME: resolution */ context = pango_font_map_create_context (fontmap); g_object_unref (fontmap); layout = pango_layout_new (context); g_object_unref (context); font_desc = pango_font_description_from_string (fontname); pango_layout_set_font_description (layout, font_desc); pango_font_description_free (font_desc); pango_layout_set_text (layout, text, -1); pango_layout_get_pixel_extents (layout, NULL, &rect); if (width) *width = rect.width; if (height) *height = rect.height; if (ascent || descent) { PangoLayoutIter *iter; PangoLayoutLine *line; iter = pango_layout_get_iter (layout); line = pango_layout_iter_get_line_readonly (iter); pango_layout_iter_free (iter); pango_layout_line_get_pixel_extents (line, NULL, &rect); if (ascent) *ascent = PANGO_ASCENT (rect); if (descent) *descent = - PANGO_DESCENT (rect); } g_object_unref (layout); return TRUE; }
static void gwy_vruler_real_draw_ticks(GwyRuler *ruler, gint pixelsize, gint min_label_spacing, gint min_tick_spacing) { gdouble lower, upper, max; gint text_size, labels, i, scale_depth; gdouble range, measure, base, step, first; GwyScaleScale scale; GwySIValueFormat *format; PangoLayout *layout; PangoRectangle rect; gchar *unit_str; gint unitstr_len, j; gint width, tick_length, xthickness, ythickness; gboolean units_drawn; GtkWidget *widget; GdkGC *gc; gint digit_width, digit_xoffset; const gchar *utf8p, *utf8next; gint ascent, descent, ypos; struct { GwyScaleScale scale; double base; } tick_info[4]; widget = GTK_WIDGET(ruler); xthickness = widget->style->xthickness; ythickness = widget->style->ythickness; format = ruler->vformat; upper = ruler->upper; lower = ruler->lower; if (upper <= lower || pixelsize < 2 || pixelsize > 10000) return; max = ruler->max_size; if (max == 0) max = MAX(fabs(lower), fabs(upper)); range = upper - lower; measure = range/format->magnitude / pixelsize; max /= format->magnitude; switch (ruler->units_placement && ruler->units) { case GWY_UNITS_PLACEMENT_AT_ZERO: unit_str = g_strdup_printf("%d %s", (lower > 0) ? (gint)(lower/format->magnitude) : 0, format->units); break; default: unit_str = g_strdup_printf("%d", (gint)max); break; } layout = gtk_widget_create_pango_layout(widget, "012456789"); pango_layout_get_extents(layout, NULL, &rect); digit_width = PANGO_PIXELS(rect.width)/10 + 1; digit_xoffset = rect.x; pango_layout_set_markup(layout, unit_str, -1); pango_layout_get_extents(layout, &rect, NULL); ascent = PANGO_ASCENT(rect); descent = PANGO_DESCENT(rect); text_size = g_utf8_strlen(pango_layout_get_text(layout), -1); text_size = PANGO_PIXELS(ascent + descent)*text_size; /* reallocate unit_str with some margin */ unitstr_len = strlen(unit_str) + 16; unit_str = g_renew(gchar, unit_str, unitstr_len); /* fit as many labels as you can */ labels = floor(pixelsize/(text_size + ythickness + min_label_spacing)); labels = MAX(labels, 1); if (labels > 6) labels = 6 + (labels - 5)/2; step = range/format->magnitude / labels; base = compute_base(step, 10); step /= base; if (step >= 5.0 || base < 1.0) { scale = GWY_SCALE_1; base *= 10; } else if (step >= 2.5) scale = GWY_SCALE_5; else if (step >= 2.0) scale = GWY_SCALE_2_5; else scale = GWY_SCALE_2; step = steps[scale]; /* draw labels */ width = widget->allocation.width - 2*xthickness; units_drawn = FALSE; first = floor(lower/format->magnitude / (base*step))*base*step; for (i = 0; ; i++) { gint pos; gdouble val; val = i*step*base + first; pos = floor((val - lower/format->magnitude)/measure); if (pos >= pixelsize) break; if (pos < 0) continue; if (!units_drawn && (upper < 0 || val >= 0) && ruler->units_placement == GWY_UNITS_PLACEMENT_AT_ZERO && ruler->units) { g_snprintf(unit_str, unitstr_len, "%d %s", ROUND(val), format->units); units_drawn = TRUE; } else g_snprintf(unit_str, unitstr_len, "%d", ROUND(val)); pango_layout_set_markup(layout, unit_str, -1); utf8p = unit_str; utf8next = g_utf8_next_char(utf8p); j = 0; ypos = pos + ythickness + 1; while (*utf8p) { pango_layout_set_text(layout, utf8p, utf8next - utf8p); pango_layout_get_extents(layout, &rect, NULL); gtk_paint_layout(widget->style, ruler->backing_store, GTK_WIDGET_STATE(widget), FALSE, NULL, widget, "vruler", xthickness + 1 + PANGO_PIXELS(digit_xoffset), ypos, layout); utf8p = utf8next; utf8next = g_utf8_next_char(utf8p); ypos += PANGO_PIXELS(PANGO_ASCENT(rect) + PANGO_DESCENT(rect)) + 2; j++; } } /* draw tick marks, from smallest to largest */ scale_depth = 0; while (scale && scale_depth < (gint)G_N_ELEMENTS(tick_info)) { tick_info[scale_depth].scale = scale; tick_info[scale_depth].base = base; scale = next_scale(scale, &base, measure, min_tick_spacing); scale_depth++; } scale_depth--; gc = widget->style->fg_gc[GTK_STATE_NORMAL]; while (scale_depth > -1) { tick_length = width/(scale_depth + 1) - 2; scale = tick_info[scale_depth].scale; base = tick_info[scale_depth].base; step = steps[scale]; first = floor(lower/format->magnitude / (base*step))*base*step; for (i = 0; ; i++) { gint pos; gdouble val; val = (i + 0.000001)*step*base + first; pos = floor((val - lower/format->magnitude)/measure); if (pos >= pixelsize) break; if (pos < 0) continue; gdk_draw_line(ruler->backing_store, gc, width + xthickness - tick_length, pos, width + xthickness, pos); } scale_depth--; } g_free(unit_str); g_object_unref(layout); }