예제 #1
0
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;
}
예제 #2
0
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;
}
예제 #3
0
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);
}