Beispiel #1
0
struct TEXT_WIDGET_HANDLE text_widget_init ( float x_mm, float y_mm,
					     float width_mm,
					     float height_mm,
					     float dpmm_x,
					     float dpmm_y )
{
  struct TEXT_WIDGET_HANDLE handle;
  handle.d = malloc( sizeof( struct TEXT_WIDGET_PRIVATE ) );
  handle.d->x_mm = x_mm;
  handle.d->y_mm = y_mm;
  handle.d->dpmm_x = dpmm_x;
  handle.d->dpmm_y = dpmm_y;
  handle.d->font_map = pango_ft2_font_map_new();

  // Note: FreeType works in DPI.
  pango_ft2_font_map_set_resolution( (PangoFT2FontMap*)handle.d->font_map,
				     dpmm_x * 25.4, dpmm_y * 25.4 );

  handle.d->context  = pango_font_map_create_context( handle.d->font_map );
  handle.d->layout   = pango_layout_new( handle.d->context );

  // Pango works in Pango Units. Not exactly clear how the resolution of
  // the font and the size of the rendering box fit together.
  int width = pango_units_from_double( dpmm_x * width_mm );
  int height = pango_units_from_double( dpmm_y * height_mm );
  pango_layout_set_width( handle.d->layout, width );
  pango_layout_set_height( handle.d->layout, height );

  handle.d->foreground = vgCreatePaint();
  vgSetParameterfv( handle.d->foreground, VG_PAINT_COLOR, 4, DEFAULT_FOREGROUND );

  return handle;
}
TextAsset::Size
TextAsset::computeSizeOfText(cairo_t* cairoContext,
                             const std::string textString,
                             int bounds,
                             PangoFontDescription* font,
                             Rect* tight,
                             float* lineHeightOut)
{
    PangoLayout* layout = pango_cairo_create_layout(cairoContext);

    // Kerning
    PangoAttrList* attr_list = pango_attr_list_new();
    PangoAttribute* spacing_attr = pango_attr_letter_spacing_new(pango_units_from_double(_kern));
    pango_attr_list_insert(attr_list, spacing_attr);
    pango_layout_set_attributes(layout, attr_list);

    pango_cairo_context_set_resolution(pango_layout_get_context(layout), DISPLAY_RESOLUTION);
    pango_layout_set_text(layout, textString.c_str(), (int)textString.length());
    pango_layout_set_alignment(layout, _alignment);
    pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR);

    const Size maxTextureSize(bounds, 1024);
    pango_layout_set_width(layout, pango_units_from_double(maxTextureSize.width));
    pango_layout_set_height(layout, pango_units_from_double(maxTextureSize.height));
    pango_layout_set_font_description(layout, font);
    applyLeading(cairoContext, layout, font);

    PangoRectangle estimateSize;
    PangoRectangle ink;
    pango_layout_get_pixel_extents(layout, &ink, &estimateSize);

    // If the text is right or center aligned the offsets will contain all the
    // leading space.  We ignore that for the size because drawText will draw
    // in the larger box.  The tight box below will get the offsets so we know
    // where to draw so the text lands in the same tight box.
    Size res(estimateSize.width, estimateSize.height);

    if (tight != NULL) {
        float lineHeight;
        float xHeight = charHeight(cairoContext, font, 'x', &lineHeight);
        if (lineHeightOut != NULL) {
            *lineHeightOut = lineHeight;
        }
        const float capHeight = charHeight(cairoContext, font, 'Y');
        const float ascender = pango_units_to_double(pango_layout_get_baseline(layout));
        const float topSpace = ascender - capHeight;
        const float bottomSpace = MAX(lineHeight - ascender - (capHeight - xHeight), 0);
        if (res.height > topSpace + bottomSpace) {
            *tight = Rect(estimateSize.x,
                          estimateSize.y + topSpace,
                          res.width,
                          res.height - topSpace - bottomSpace);
        } else {
            *tight = Rect(0, 0, res.width, res.height);
        }
    }
    g_object_unref(layout);

    return res;
}
Beispiel #3
0
void TextRenderer::OnButtonPressEvent(GdkEventButton* event)
{
    if( event->type != GDK_BUTTON_PRESS || !IsLeftButton(event) )
        return;

    Point lct((int)event->x, (int)event->y);
    lct = GetTransition().DevToRel(lct);
    if( CalcTextPlc().Contains(lct) )
    {
        double x = lct.x, y = lct.y;
        {
            CairoStateSave save(caiCont);
            ApplyTextTrans();

            caiCont->device_to_user(x, y);
        }

        int idx, trail;
        utf8::trans tr(GetText());
        if( panLay->xy_to_index(pango_units_from_double(x), pango_units_from_double(y), idx, trail) )
        {
            int new_pos = tr.to_offset(idx);
            // видимо в случае "сложных" букв trail может принимать и отличные от
            // {0, 1} значения (восточные иероглифы?), но нам требуется точность до целого символа
            if( trail )
                new_pos++;

            MoveCursor( new_pos );
        }
        else
            MoveCursor( tr.length() );
    }
}
Beispiel #4
0
static void
e_contact_output (GtkPrintContext *context,
                  PangoFontDescription *font,
                  gdouble x,
                  gdouble y,
                  gdouble width,
                  const gchar *text)
{
	PangoLayout *layout;
	gdouble indent;
	cairo_t *cr;

	layout = gtk_print_context_create_pango_layout (context);

	if (width == -1 || get_font_width (context, font, text) <= width)
		indent = .0;
	else
		indent = get_font_width (context, font, "     ");

	pango_layout_set_font_description (layout, font);
	pango_layout_set_text (layout, text, -1);
	pango_layout_set_width (layout, pango_units_from_double (width));
	pango_layout_set_indent (layout, pango_units_from_double (indent));
	pango_layout_set_wrap (layout, PANGO_WRAP_WORD_CHAR);

	cr = gtk_print_context_get_cairo_context (context);

	cairo_save (cr);
	cairo_move_to (cr, x, y);
	pango_cairo_show_layout (cr, layout);
	cairo_restore (cr);

	g_object_unref (layout);
}
/**
 * pango_matrix_transform_rectangle:
 * @matrix: a #PangoMatrix, or %NULL
 * @rect: (inout) (allow-none): in/out bounding box in Pango units, or %NULL
 *
 * First transforms @rect using @matrix, then calculates the bounding box
 * of the transformed rectangle.  The rectangle should be in Pango units.
 *
 * This function is useful for example when you want to draw a rotated
 * @PangoLayout to an image buffer, and want to know how large the image
 * should be and how much you should shift the layout when rendering.
 *
 * If you have a rectangle in device units (pixels), use
 * pango_matrix_transform_pixel_rectangle().
 *
 * If you have the rectangle in Pango units and want to convert to
 * transformed pixel bounding box, it is more accurate to transform it first
 * (using this function) and pass the result to pango_extents_to_pixels(),
 * first argument, for an inclusive rounded rectangle.
 * However, there are valid reasons that you may want to convert
 * to pixels first and then transform, for example when the transformed
 * coordinates may overflow in Pango units (large matrix translation for
 * example).
 *
 * Since: 1.16
 **/
void
pango_matrix_transform_rectangle (const PangoMatrix *matrix,
				  PangoRectangle    *rect)
{
  int i;
  double quad_x[4], quad_y[4];
  double dx1, dy1;
  double dx2, dy2;
  double min_x, max_x;
  double min_y, max_y;

  if (!rect || !matrix)
    return;

  quad_x[0] = pango_units_to_double (rect->x);
  quad_y[0] = pango_units_to_double (rect->y);
  pango_matrix_transform_point (matrix, &quad_x[0], &quad_y[0]);

  dx1 = pango_units_to_double (rect->width);
  dy1 = 0;
  pango_matrix_transform_distance (matrix, &dx1, &dy1);
  quad_x[1] = quad_x[0] + dx1;
  quad_y[1] = quad_y[0] + dy1;

  dx2 = 0;
  dy2 = pango_units_to_double (rect->height);
  pango_matrix_transform_distance (matrix, &dx2, &dy2);
  quad_x[2] = quad_x[0] + dx2;
  quad_y[2] = quad_y[0] + dy2;

  quad_x[3] = quad_x[0] + dx1 + dx2;
  quad_y[3] = quad_y[0] + dy1 + dy2;

  min_x = max_x = quad_x[0];
  min_y = max_y = quad_y[0];

  for (i=1; i < 4; i++) {
      if (quad_x[i] < min_x)
	  min_x = quad_x[i];
      else if (quad_x[i] > max_x)
	  max_x = quad_x[i];

      if (quad_y[i] < min_y)
	  min_y = quad_y[i];
      else if (quad_y[i] > max_y)
	  max_y = quad_y[i];
  }

  rect->x      = pango_units_from_double (min_x);
  rect->y      = pango_units_from_double (min_y);
  rect->width  = pango_units_from_double (max_x) - rect->x;
  rect->height = pango_units_from_double (max_y) - rect->y;
}
Beispiel #6
0
Datei: cawc.c Projekt: Roger/caw
static PyObject *
_pango_layout_set_width_height(PyObject *self, PyObject *args)
{
    PangoLayout *layout;
    int width, height;

    if (!PyArg_ParseTuple(args, "lii", &layout, &width, &height))
        return NULL;

    pango_layout_set_width(layout, pango_units_from_double(width));
    pango_layout_set_height(layout, pango_units_from_double(height));
    Py_RETURN_NONE;
}
void
TextAsset::drawText(cairo_t* cairoContext,
                    const std::string& textString,
                    const Rect& rect,
                    PangoFontDescription* inFontDescription,
                    bool outlineEnabled)
{
    cairo_move_to(cairoContext, rect.x, rect.y);

    PangoLayout* layout = pango_cairo_create_layout(cairoContext);

    // Kerning
    PangoAttrList* attr_list = pango_attr_list_new();
    PangoAttribute* spacing_attr = pango_attr_letter_spacing_new(pango_units_from_double(_kern));
    pango_attr_list_insert(attr_list, spacing_attr);
    pango_layout_set_attributes(layout, attr_list);

    pango_cairo_context_set_resolution(pango_layout_get_context(layout), DISPLAY_RESOLUTION);
    pango_layout_set_text(layout, textString.c_str(), textString.length());
    pango_layout_set_font_description(layout, inFontDescription);
    pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR);
    pango_layout_set_width(layout, pango_units_from_double(rect.size.width + WIDTH_PADDING));
    pango_layout_set_height(layout, pango_units_from_double(rect.size.height + HEIGHT_PADDING));
    pango_layout_set_alignment(layout, _alignment);
    applyLeading(cairoContext, layout, inFontDescription);

    pango_cairo_show_layout(cairoContext, layout);

    // Core Text defines positive outline width values as stroke only
    if (_outlineThickness <= 0.0f) {
        cairo_fill_preserve(cairoContext);
    }

    // Outline
    if (outlineEnabled && _outlineThickness != 0.0f) {
        const float outlineThickness = (fabsf(_outlineThickness) / 100.0f) * _fontSize * CLIENT_TO_SERVER_SCALE;
        cairo_set_source_rgba(cairoContext,
                              _outlineColor.red,
                              _outlineColor.green,
                              _outlineColor.blue,
                              _outlineColor.alpha);
        pango_cairo_layout_path(cairoContext, layout);
        cairo_set_line_width(cairoContext, outlineThickness);
        cairo_stroke(cairoContext);
    } else {
        cairo_new_path(cairoContext);
    }

    g_object_unref(layout);
}
Beispiel #8
0
static PangoLayout *
make_new_page (PangoContext * context, PangoFontDescription * desc,
				gdouble height, gdouble width)
{
	PangoLayout *layout;

	layout = pango_layout_new (context);
	pango_layout_set_justify (layout, TRUE);
	pango_layout_set_spacing (layout, 1.5 * PANGO_SCALE);
	pango_layout_set_width (layout, pango_units_from_double(width - SIDE_MARGIN));
	pango_layout_set_height (layout, pango_units_from_double(height - EDGE_MARGIN));
	pango_layout_set_wrap (layout, PANGO_WRAP_WORD_CHAR);
	pango_layout_set_font_description (layout, desc);
	return layout;
}
void
TextAsset::applyLeading(cairo_t* cairoContext, PangoLayout* layout, PangoFontDescription* font) const
{
    float lineHeight;
    charHeight(cairoContext, font, 'a', &lineHeight);

    const float lineSpacing = (_leadingMultiplier - 1.0) * lineHeight;
    pango_layout_set_spacing(layout, pango_units_from_double(lineSpacing));
}
  void PrintNotesNoteAddin::on_begin_print(const Glib::RefPtr<Gtk::PrintContext>& context)
  {
    m_timestamp_footer = create_layout_for_timestamp(context);
    // Create and initialize the page margins
    m_margin_top = cm_to_pixel (1.5, context->get_dpi_y());
    m_margin_left = cm_to_pixel (1, context->get_dpi_x());
    m_margin_right = cm_to_pixel (1, context->get_dpi_x());
    m_margin_bottom = 0;
    double max_height = pango_units_from_double(context->get_height()
                                                - m_margin_top - m_margin_bottom
                                                - compute_footer_height(context));

    DBG_OUT("margins = %d %d %d %d", m_margin_top, m_margin_left,
            m_margin_right, m_margin_bottom);

    m_page_breaks.clear();

    Gtk::TextIter position;
    Gtk::TextIter end_iter;
    get_buffer()->get_bounds (position, end_iter);

    double page_height = 0;
    bool done = position.compare (end_iter) >= 0;
    while (!done) {
      Gtk::TextIter line_end = position;
      if (!line_end.ends_line ()) {
        line_end.forward_to_line_end ();
      }

      int paragraph_number = position.get_line();
      int indentation = 0;
      Glib::RefPtr<Pango::Layout> layout = create_layout_for_paragraph(
        context, position, line_end, indentation);

      Pango::Rectangle ink_rect;
      Pango::Rectangle logical_rect;
      for(int line_in_paragraph = 0;  line_in_paragraph < layout->get_line_count();
          line_in_paragraph++) {
        Glib::RefPtr<Pango::LayoutLine> line = layout->get_line(line_in_paragraph);
        line->get_extents (ink_rect, logical_rect);

        if ((page_height + logical_rect.get_height()) >= max_height) {
          PageBreak(paragraph_number, line_in_paragraph);
          m_page_breaks.push_back (PageBreak(paragraph_number, line_in_paragraph));
          page_height = 0;
        }

        page_height += logical_rect.get_height();

      }
      position.forward_line ();
      done = position.compare (end_iter) >= 0;
    }

    m_print_op->set_n_pages(m_page_breaks.size() + 1);
  }
  Glib::RefPtr<Pango::Layout> 
  PrintNotesNoteAddin::create_layout_for_paragraph(const Glib::RefPtr<Gtk::PrintContext> & context, 
                                                   Gtk::TextIter p_start,
                                                   Gtk::TextIter p_end,
                                                   int & indentation)
  {
    Glib::RefPtr<Pango::Layout> layout = context->create_pango_layout();

    layout->set_font_description(
      get_window()->editor()->get_pango_context()->get_font_description());
    int start_index = p_start.get_line_index();
    indentation = 0;

    double dpiX = context->get_dpi_x();
    {
      Pango::AttrList attr_list;

      Gtk::TextIter segm_start = p_start;
      Gtk::TextIter segm_end;

      while (segm_start.compare (p_end) < 0) {
        segm_end = segm_start;
        std::list<Pango::Attribute> attrs;
        get_paragraph_attributes (layout, dpiX, indentation,
                                  segm_end, p_end, attrs);

        guint si = (guint) (segm_start.get_line_index() - start_index);
        guint ei = (guint) (segm_end.get_line_index() - start_index);

        for(std::list<Pango::Attribute>::iterator iter = attrs.begin();
            iter != attrs.end(); ++iter) {
          
          Pango::Attribute & a(*iter);
          a.set_start_index(si);
          a.set_end_index(ei);
          attr_list.insert(a);
        }
        segm_start = segm_end;
      }

      layout->set_attributes(attr_list);
    }

    gnote::DepthNoteTag::Ptr depth = get_buffer()->find_depth_tag(p_start);
    if(depth) {
        indentation += ((int) (dpiX / 3)) * depth->get_depth();
    }
    layout->set_width(pango_units_from_double((int)context->get_width() -
                                              m_margin_left - m_margin_right - indentation));
    layout->set_wrap (Pango::WRAP_WORD_CHAR);
    layout->set_text (get_buffer()->get_slice (p_start, p_end, false));
    return layout;
  }
static gboolean
_pango_cairo_font_private_glyph_extents_cache_init (PangoCairoFontPrivate *cf_priv)
{
  cairo_scaled_font_t *scaled_font = _pango_cairo_font_private_get_scaled_font (cf_priv);
  cairo_font_extents_t font_extents;

  if (G_UNLIKELY (scaled_font == NULL || cairo_scaled_font_status (scaled_font) != CAIRO_STATUS_SUCCESS))
    return FALSE;

  cairo_scaled_font_extents (scaled_font, &font_extents);

  cf_priv->font_extents.x = 0;
  cf_priv->font_extents.width = 0;
  cf_priv->font_extents.height = pango_units_from_double (font_extents.ascent + font_extents.descent);
  switch (cf_priv->gravity)
    {
      default:
      case PANGO_GRAVITY_AUTO:
      case PANGO_GRAVITY_SOUTH:
	cf_priv->font_extents.y = - pango_units_from_double (font_extents.ascent);
	break;
      case PANGO_GRAVITY_NORTH:
	cf_priv->font_extents.y = - pango_units_from_double (font_extents.descent);
	break;
      case PANGO_GRAVITY_EAST:
      case PANGO_GRAVITY_WEST:
	{
	  int ascent = pango_units_from_double (font_extents.ascent + font_extents.descent) / 2;
	  if (cf_priv->is_hinted)
	    ascent = PANGO_UNITS_ROUND (ascent);
	  cf_priv->font_extents.y = - ascent;
	}
    }

  cf_priv->glyph_extents_cache = g_new0 (PangoCairoFontGlyphExtentsCacheEntry, GLYPH_CACHE_NUM_ENTRIES);
  /* Make sure all cache entries are invalid initially */
  cf_priv->glyph_extents_cache[0].glyph = 1; /* glyph 1 cannot happen in bucket 0 */

  return TRUE;
}
/* Fills in the glyph extents cache entry
 */
static void
compute_glyph_extents (PangoCairoFontPrivate  *cf_priv,
		       PangoGlyph              glyph,
		       PangoCairoFontGlyphExtentsCacheEntry *entry)
{
  cairo_text_extents_t extents;
  cairo_glyph_t cairo_glyph;

  cairo_glyph.index = glyph;
  cairo_glyph.x = 0;
  cairo_glyph.y = 0;

  cairo_scaled_font_glyph_extents (_pango_cairo_font_private_get_scaled_font (cf_priv),
				   &cairo_glyph, 1, &extents);

  entry->glyph = glyph;
  entry->width = pango_units_from_double (extents.x_advance);
  entry->ink_rect.x = pango_units_from_double (extents.x_bearing);
  entry->ink_rect.y = pango_units_from_double (extents.y_bearing);
  entry->ink_rect.width = pango_units_from_double (extents.width);
  entry->ink_rect.height = pango_units_from_double (extents.height);
}
  Glib::RefPtr<Pango::Layout> 
  PrintNotesNoteAddin::create_layout_for_timestamp(const Glib::RefPtr<Gtk::PrintContext> & context)
  {
    Glib::ustring timestamp = sharp::DateTime::now().to_string("%c");

    Glib::RefPtr<Pango::Layout> layout = context->create_pango_layout ();
    Pango::FontDescription font_desc = get_window()->editor()->get_pango_context()->get_font_description();
    font_desc.set_style(Pango::STYLE_NORMAL);
    font_desc.set_weight(Pango::WEIGHT_LIGHT);
    layout->set_font_description(font_desc);
    layout->set_width(pango_units_from_double((int) context->get_width()));

    layout->set_alignment(Pango::ALIGN_RIGHT);
    layout->set_text (timestamp);

    return layout;
  }
  Glib::RefPtr<Pango::Layout> 
  PrintNotesNoteAddin::create_layout_for_pagenumbers(const Glib::RefPtr<Gtk::PrintContext> & context, 
                                int page_number, int total_pages)
  {
    Glib::RefPtr<Pango::Layout> layout = context->create_pango_layout();
    Pango::FontDescription font_desc = get_window()->editor()->get_pango_context()->get_font_description();
    font_desc.set_style(Pango::STYLE_NORMAL);
    font_desc.set_weight(Pango::WEIGHT_LIGHT);
    layout->set_font_description(font_desc);
    layout->set_width(pango_units_from_double((int)context->get_width()));

    // %1 is the page number, %2 is the total number of pages
    Glib::ustring footer_left = Glib::ustring::compose(_("Page %1 of %2"),
                                  page_number, total_pages);
    layout->set_alignment(Pango::ALIGN_LEFT);
    layout->set_text (footer_left);

    return layout;
  }
Beispiel #16
0
void SetFontSize(Pango::FontDescription& dsc, double sz)
{
    dsc.set_size(pango_units_from_double(sz));
}
static PangoCairoFontHexBoxInfo *
_pango_cairo_font_private_get_hex_box_info (PangoCairoFontPrivate *cf_priv)
{
  static const char hexdigits[] = "0123456789ABCDEF";
  char c[2] = {0, 0};
  PangoFont *mini_font;
  PangoCairoFontHexBoxInfo *hbi;

  /* for metrics hinting */
  double scale_x = 1., scale_x_inv = 1., scale_y = 1., scale_y_inv = 1.;
  gboolean is_hinted;

  int i;
  int rows;
  double pad;
  double width = 0;
  double height = 0;
  cairo_font_options_t *font_options;
  cairo_font_extents_t font_extents;
  double size, mini_size;
  PangoFontDescription *desc;
  cairo_scaled_font_t *scaled_font, *scaled_mini_font;
  PangoMatrix pango_ctm;
  cairo_matrix_t cairo_ctm;
  PangoGravity gravity;

  if (!cf_priv)
    return NULL;

  if (cf_priv->hbi)
    return cf_priv->hbi;

  scaled_font = _pango_cairo_font_private_get_scaled_font (cf_priv);
  if (G_UNLIKELY (scaled_font == NULL || cairo_scaled_font_status (scaled_font) != CAIRO_STATUS_SUCCESS))
    return NULL;

  is_hinted = cf_priv->is_hinted;

  font_options = cairo_font_options_create ();
  desc = pango_font_describe_with_absolute_size ((PangoFont *)cf_priv->cfont);
  size = pango_font_description_get_size (desc) / (1.*PANGO_SCALE);
  gravity = pango_font_description_get_gravity (desc);

  cairo_scaled_font_get_ctm (scaled_font, &cairo_ctm);
  cairo_scaled_font_get_font_options (scaled_font, font_options);
  /* I started adding support for vertical hexboxes here, but it's too much
   * work.  Easier to do with cairo user fonts and vertical writing mode
   * support in cairo.
   */
  /*cairo_matrix_rotate (&cairo_ctm, pango_gravity_to_rotation (gravity));*/
  pango_ctm.xx = cairo_ctm.xx;
  pango_ctm.yx = cairo_ctm.yx;
  pango_ctm.xy = cairo_ctm.xy;
  pango_ctm.yy = cairo_ctm.yy;
  pango_ctm.x0 = cairo_ctm.x0;
  pango_ctm.y0 = cairo_ctm.y0;

  if (is_hinted)
    {
      /* prepare for some hinting */
      double x, y;

      x = 1.; y = 0.;
      cairo_matrix_transform_distance (&cairo_ctm, &x, &y);
      scale_x = sqrt (x*x + y*y);
      scale_x_inv = 1 / scale_x;

      x = 0.; y = 1.;
      cairo_matrix_transform_distance (&cairo_ctm, &x, &y);
      scale_y = sqrt (x*x + y*y);
      scale_y_inv = 1 / scale_y;
    }

/* we hint to the nearest device units */
#define HINT(value, scale, scale_inv) (ceil ((value-1e-5) * scale) * scale_inv)
#define HINT_X(value) HINT ((value), scale_x, scale_x_inv)
#define HINT_Y(value) HINT ((value), scale_y, scale_y_inv)

  /* create mini_font description */
  {
    PangoFontMap *fontmap;
    PangoContext *context;

    /* XXX this is racy.  need a ref'ing getter... */
    fontmap = pango_font_get_font_map ((PangoFont *)cf_priv->cfont);
    if (!fontmap)
      return NULL;
    fontmap = g_object_ref (fontmap);

    /* we inherit most font properties for the mini font.  just
     * change family and size.  means, you get bold hex digits
     * in the hexbox for a bold font.
     */

    /* We should rotate the box, not glyphs */
    pango_font_description_unset_fields (desc, PANGO_FONT_MASK_GRAVITY);

    pango_font_description_set_family_static (desc, "monospace");

    rows = 2;
    mini_size = size / 2.2;
    if (is_hinted)
      {
	mini_size = HINT_Y (mini_size);

	if (mini_size < 6.0)
	  {
	    rows = 1;
	    mini_size = MIN (MAX (size - 1, 0), 6.0);
	  }
      }

    pango_font_description_set_absolute_size (desc, pango_units_from_double (mini_size));

    /* load mini_font */

    context = pango_font_map_create_context (fontmap);

    pango_context_set_matrix (context, &pango_ctm);
    pango_context_set_language (context, pango_script_get_sample_language (PANGO_SCRIPT_LATIN));
    pango_cairo_context_set_font_options (context, font_options);
    mini_font = pango_font_map_load_font (fontmap, context, desc);

    g_object_unref (context);
    g_object_unref (fontmap);
  }

  pango_font_description_free (desc);
  cairo_font_options_destroy (font_options);


  scaled_mini_font = pango_cairo_font_get_scaled_font ((PangoCairoFont *) mini_font);

  for (i = 0 ; i < 16 ; i++)
    {
      cairo_text_extents_t extents;

      c[0] = hexdigits[i];
      cairo_scaled_font_text_extents (scaled_mini_font, c, &extents);
      width = MAX (width, extents.width);
      height = MAX (height, extents.height);
    }

  cairo_scaled_font_extents (scaled_font, &font_extents);
  if (font_extents.ascent + font_extents.descent <= 0)
    {
      font_extents.ascent = PANGO_UNKNOWN_GLYPH_HEIGHT;
      font_extents.descent = 0;
    }

  pad = (font_extents.ascent + font_extents.descent) / 43;
  pad = MIN (pad, mini_size);

  hbi = g_slice_new (PangoCairoFontHexBoxInfo);
  hbi->font = (PangoCairoFont *) mini_font;
  hbi->rows = rows;

  hbi->digit_width  = width;
  hbi->digit_height = height;

  hbi->pad_x = pad;
  hbi->pad_y = pad;

  if (is_hinted)
    {
      hbi->digit_width  = HINT_X (hbi->digit_width);
      hbi->digit_height = HINT_Y (hbi->digit_height);
      hbi->pad_x = HINT_X (hbi->pad_x);
      hbi->pad_y = HINT_Y (hbi->pad_y);
    }

  hbi->line_width = MIN (hbi->pad_x, hbi->pad_y);

  hbi->box_height = 3 * hbi->pad_y + rows * (hbi->pad_y + hbi->digit_height);

  if (rows == 1 || hbi->box_height <= font_extents.ascent)
    {
      hbi->box_descent = 2 * hbi->pad_y;
    }
  else if (hbi->box_height <= font_extents.ascent + font_extents.descent - 2 * hbi->pad_y)
    {
      hbi->box_descent = 2 * hbi->pad_y + hbi->box_height - font_extents.ascent;
    }
  else
    {
      hbi->box_descent = font_extents.descent * hbi->box_height /
			 (font_extents.ascent + font_extents.descent);
    }
  if (is_hinted)
    {
       hbi->box_descent = HINT_Y (hbi->box_descent);
    }

  cf_priv->hbi = hbi;
  return hbi;
}