Beispiel #1
0
static void
set_text_expansion (AboutRenderer *r, double er)
{
	const char *text = pango_layout_get_text (r->layout);
	GString *str = g_string_new (NULL);
	char *ntext;
	const char *p;

	r->expansion.rate = er;
	r->expansion.count = 0;

	/* Normalize to make sure diacriticals are combined.  */
	ntext = g_utf8_normalize (text, -1, G_NORMALIZE_DEFAULT_COMPOSE);

	/* Insert inter-letter spaces we can stretch.  */
	for (p = ntext; *p; p = g_utf8_next_char (p)) {
		gunichar uc = g_utf8_get_char (p);

		if (uc == UNICODE_ZERO_WIDTH_SPACE_C)
			continue;

		if (str->len) {
			g_string_append_unichar (str, UNICODE_ZERO_WIDTH_SPACE_C);
			r->expansion.count++;
		}
		g_string_append_unichar (str, uc);
	}

	g_free (ntext);
	pango_layout_set_text (r->layout, str->str, -1);
	g_string_free (str, TRUE);
}
Beispiel #2
0
static gunichar 
gail_scale_get_character_at_offset (AtkText *text,
                                    gint    offset)
{
  GtkWidget *widget;
  GtkScale *scale;
  PangoLayout *layout;
  const gchar *string;
  gchar *index;
  gunichar c;

  widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
  if (widget == NULL)
    /* State is defunct */
    return '\0';

  scale = GTK_SCALE (widget);

  layout = gtk_scale_get_layout (scale);
  if (!layout)
    return '\0';
  string = pango_layout_get_text (layout);
  if (offset >= g_utf8_strlen (string, -1))
    c = '\0';
  else
    {
      index = g_utf8_offset_to_pointer (string, offset);

      c = g_utf8_get_char (index);
    }

  return c;
}
Beispiel #3
0
std::string ttext::get_token(const gui2::tpoint & position, const char * delim) const
{
	recalculate();

	// Get the index of the character.
	int index, trailing;
	if (!pango_layout_xy_to_index(layout_, position.x * PANGO_SCALE,
		position.y * PANGO_SCALE, &index, &trailing)) {
		return "";
	}

	std::string txt = pango_layout_get_text(layout_);

	std::string d(delim);

	if (index < 0 || (static_cast<size_t>(index) >= txt.size()) || d.find(txt.at(index)) != std::string::npos) {
		return ""; // if the index is out of bounds, or the index character is a delimiter, return nothing
	}

	size_t l = index;
	while (l > 0 && (d.find(txt.at(l-1)) == std::string::npos)) {
		--l;
	}

	size_t r = index + 1;
	while (r < txt.size() && (d.find(txt.at(r)) == std::string::npos)) {
		++r;
	}

	return txt.substr(l,r-l);
}
Beispiel #4
0
static uint32_t
text_entry_try_invoke_preedit_action(struct text_entry *entry,
				     int32_t x, int32_t y,
				     uint32_t button,
				     enum wl_pointer_button_state state)
{
	int index, trailing;
	uint32_t cursor;
	const char *text;

	if (!entry->preedit.text)
		return 0;

	pango_layout_xy_to_index(entry->layout,
				 x * PANGO_SCALE, y * PANGO_SCALE,
				 &index, &trailing);

	text = pango_layout_get_text(entry->layout);
	cursor = g_utf8_offset_to_pointer(text + index, trailing) - text;

	if (cursor < entry->cursor ||
	    cursor > entry->cursor + strlen(entry->preedit.text)) {
		return 0;
	}

	if (state == WL_POINTER_BUTTON_STATE_RELEASED)
		wl_text_input_invoke_action(entry->text_input,
					    button,
					    cursor - entry->cursor);

	return 1;
}
Beispiel #5
0
static void
gail_scale_notify (GObject    *obj,
                   GParamSpec *pspec)
{
  GailScale *scale = GAIL_SCALE (obj);

  if (strcmp (pspec->name, "accessible-value") == 0)
    {
      GtkWidget *widget;

      widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
      if (widget)
        {
          GtkScale *gtk_scale;
          PangoLayout *layout;
          const gchar *txt;

          gtk_scale = GTK_SCALE (widget);
          layout = gtk_scale_get_layout (gtk_scale);
          if (layout)
            {
              txt = pango_layout_get_text (layout);
              if (txt)
                {
	          g_signal_emit_by_name (obj, "text_changed::delete", 0,
                                         gtk_text_buffer_get_char_count (scale->textutil->buffer));
                  gail_text_util_text_setup (scale->textutil, txt);
	          g_signal_emit_by_name (obj, "text_changed::insert", 0,
                                         g_utf8_strlen (txt, -1));
                }
            }
        }
    }
  G_OBJECT_CLASS (gail_scale_parent_class)->notify (obj, pspec);
}
Beispiel #6
0
static void
gail_scale_get_character_extents (AtkText      *text,
				  gint         offset,
		                  gint         *x,
                    		  gint 	       *y,
                                  gint 	       *width,
                                  gint 	       *height,
			          AtkCoordType coords)
{
  GtkWidget *widget;
  GtkScale *scale;
  PangoRectangle char_rect;
  PangoLayout *layout;
  gint index, x_layout, y_layout;
  const gchar *scale_text;
 
  widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));

  if (widget == NULL)
    /* State is defunct */
    return;

  scale = GTK_SCALE (widget);
  layout = gtk_scale_get_layout (scale);
  if (!layout)
    return;
  scale_text = pango_layout_get_text (layout);
  if (!scale_text)
    return;
  index = g_utf8_offset_to_pointer (scale_text, offset) - scale_text;
  gtk_scale_get_layout_offsets (scale, &x_layout, &y_layout);
  pango_layout_index_to_pos (layout, index, &char_rect);
  gail_misc_get_extents_from_pango_rectangle (widget, &char_rect, 
                    x_layout, y_layout, x, y, width, height, coords);
} 
Beispiel #7
0
static void
gnm_notebook_button_ensure_layout (GnmNotebookButton *nbb)
{
	const char *text = gtk_label_get_text (GTK_LABEL (nbb));

	if (nbb->layout) {
		if (strcmp (text, pango_layout_get_text (nbb->layout)) == 0)
			return;
		pango_layout_set_text (nbb->layout, text, -1);
		pango_layout_set_text (nbb->layout_active, text, -1);
	} else {
		PangoAttrList *attrs, *attrs_active;
		PangoAttribute *attr;
		PangoFontDescription *desc;
		GtkWidget *widget = GTK_WIDGET (nbb);
		GtkStyleContext *context =
			gtk_widget_get_style_context (widget);

		nbb->layout = gtk_widget_create_pango_layout (widget, text);
		nbb->layout_active = gtk_widget_create_pango_layout (widget, text);

		/* Common */
		attrs = pango_attr_list_new ();
		if (nbb->bg) {
			attr = go_color_to_pango
				(go_color_from_gdk_rgba (nbb->bg, NULL),
				 FALSE);
			attr->start_index = 0;
			attr->end_index = -1;
			pango_attr_list_insert (attrs, attr);
		}
		attrs_active = pango_attr_list_copy (attrs);

		/* Normal */
		gtk_style_context_get (context, GTK_STATE_FLAG_NORMAL,
				       "font", &desc, NULL);
		attr = pango_attr_font_desc_new (desc);
		attr->start_index = 0;
		attr->end_index = -1;
		pango_attr_list_insert (attrs, attr);
		pango_font_description_free (desc);
		pango_layout_set_attributes (nbb->layout, attrs);
		pango_attr_list_unref (attrs);

		/* Active */
		gtk_style_context_get (context, GTK_STATE_FLAG_ACTIVE,
				       "font", &desc, NULL);
		attr = pango_attr_font_desc_new (desc);
		attr->start_index = 0;
		attr->end_index = -1;
		pango_attr_list_insert (attrs_active, attr);
		pango_font_description_free (desc);
		pango_layout_set_attributes (nbb->layout_active, attrs_active);
		pango_attr_list_unref (attrs_active);
	}

	pango_layout_get_extents (nbb->layout, NULL, &nbb->logical);
	pango_layout_get_extents (nbb->layout_active, NULL, &nbb->logical_active);
}
Beispiel #8
0
static void
test_file (const gchar *filename, GString *string)
{
  gchar *contents;
  gchar *markup;
  gsize  length;
  GError *error = NULL;
  PangoLayout *layout;
  gchar *p;
  gint width = 0;
  gint ellipsize_at = 0;
  PangoEllipsizeMode ellipsize = PANGO_ELLIPSIZE_NONE;
  PangoWrapMode wrap = PANGO_WRAP_WORD;
  PangoFontDescription *desc;

  if (!g_file_get_contents (filename, &contents, &length, &error))
    {
      fprintf (stderr, "%s\n", error->message);
      g_error_free (error);
      return;
    }

  p = strchr (contents, '\n');
  g_assert (p);
  markup = p + 1;
  *p = '\0';

  parse_params (contents, &width, &ellipsize_at, &ellipsize, &wrap);

  layout = pango_layout_new (context);

  desc = pango_font_description_from_string ("Cantarell 11");
  pango_layout_set_font_description (layout, desc);
  pango_font_description_free (desc); 

  pango_layout_set_markup (layout, markup, length);
  g_free (contents);

  if (width != 0)
    pango_layout_set_width (layout, width * PANGO_SCALE);
  pango_layout_set_ellipsize (layout, ellipsize);
  pango_layout_set_wrap (layout, wrap);

  g_string_append (string, pango_layout_get_text (layout));
  g_string_append (string, "\n---\n\n");
  g_string_append_printf (string, "wrapped: %d\n", pango_layout_is_wrapped (layout));
  g_string_append_printf (string, "ellipsized: %d\n", pango_layout_is_ellipsized (layout));
  g_string_append_printf (string, "lines: %d\n", pango_layout_get_line_count (layout));
  if (width != 0)
    g_string_append_printf (string, "width: %d\n", pango_layout_get_width (layout));
  g_string_append (string, "\n---\n\n");
   dump_attrs (pango_layout_get_attributes (layout), string);
  g_string_append (string, "\n---\n\n");
  dump_lines (layout, string);
  g_string_append (string, "\n---\n\n");
  dump_runs (layout, string);

  g_object_unref (layout);
}
Beispiel #9
0
static void _mt_draw_string(MT_WINDOW *win, MT_STRING *str, int x_offset, int y_offset, MT_COLOR *color)
{
   MT_GTK_STRING *s = str;
   PangoLayout *layout = s->layout;
   int state_type = s->state_type;

   if (!color && s->color) color = s->color;
   if (color && !pango_layout_get_text(layout)) color = NULL;

   if (color) {
      PangoAttrList *attrlist;
      PangoAttribute *attr;

      layout = pango_layout_copy(layout);

      attrlist = pango_layout_get_attributes(layout);
      if (attrlist) {
         pango_attr_list_ref(attrlist);
      }
      else {
         attrlist = pango_attr_list_new();
      }

      if (color) {
         attr = pango_attr_foreground_new(color->r << 8, color->g << 8, color->b << 8);
         attr->start_index = 0;
         attr->end_index = strlen(pango_layout_get_text(layout));
         pango_attr_list_insert_before(attrlist, attr);
      }
      
      pango_layout_set_attributes(layout, attrlist);
      pango_attr_list_unref(attrlist);

      state_type = GTK_STATE_NORMAL;
   }

   s->parent_class->draw_layout(s->style, (GdkWindow *)win, state_type, s->use_text,
                                s->area, s->widget, s->detail, s->x + x_offset, s->y + y_offset, layout);

   if (color) {
      g_object_unref(layout);
   }
}
Beispiel #10
0
static gint
gtk_icon_view_item_accessible_get_offset_at_point (AtkText      *text,
                                                   gint          x,
                                                   gint          y,
                                                   AtkCoordType coord_type)
{
  GtkIconViewItemAccessible *item;
  gint offset = 0;
#if 0
  GtkIconView *icon_view;
  const gchar *item_text;
  gint index;
  gint l_x, l_y;
#endif

  item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);

  if (!GTK_IS_ICON_VIEW (item->widget))
    return -1;

  if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
    return -1;

#if 0
  icon_view = GTK_ICON_VIEW (item->widget);
      /* FIXME we probably have to use GailTextCell to salvage this */
  gtk_icon_view_update_item_text (icon_view, item->item);
  atk_component_get_position (ATK_COMPONENT (text), &l_x, &l_y, coord_type);
  x -= l_x + item->item->layout_x - item->item->x;
  x +=  ((item->item->width - item->item->layout_width) / 2) + (MAX (item->item->pixbuf_width, icon_view->priv->item_width) - item->item->width) / 2,
  y -= l_y + item->item->layout_y - item->item->y;
  item_text = pango_layout_get_text (icon_view->priv->layout);
  if (!pango_layout_xy_to_index (icon_view->priv->layout, 
                                x * PANGO_SCALE,
                                y * PANGO_SCALE,
                                &index, NULL))
    {
      if (x < 0 || y < 0)
        index = 0;
      else
        index = -1;
    } 
  if (index == -1)
    offset = g_utf8_strlen (item_text, -1);
  else
    offset = g_utf8_pointer_to_offset (item_text, item_text + index);
#endif
  return offset;
}
static const gchar *
gtk_scale_accessible_get_description (AtkObject *object)
{
  GtkWidget *widget;
  PangoLayout *layout;

  widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (object));
  if (widget == NULL)
    return NULL;

  layout = gtk_scale_get_layout (GTK_SCALE (widget));
  if (layout)
    return pango_layout_get_text (layout);

  return ATK_OBJECT_CLASS (_gtk_scale_accessible_parent_class)->get_description (object);
}
static PangoAttrList *
create_shape_attr_list_for_layout (PangoLayout   *layout,
                                   IconShapeData *data)
{
        PangoAttrList *attrs;
        PangoFontMetrics *metrics;
        gint ascent, descent;
        PangoRectangle ink_rect, logical_rect;
        const gchar *p;
        const gchar *text;
        gint placeholder_len;

        /* Get font metrics and prepare fancy shape size */
        metrics = pango_context_get_metrics (pango_layout_get_context (layout),
                                             pango_layout_get_font_description (layout),
                                             NULL);
        ascent = pango_font_metrics_get_ascent (metrics);
        descent = pango_font_metrics_get_descent (metrics);
        pango_font_metrics_unref (metrics);

        logical_rect.x = 0;
        logical_rect.y = - ascent;
        logical_rect.width = ascent + descent;
        logical_rect.height = ascent + descent;

        ink_rect = logical_rect;

        attrs = pango_attr_list_new ();
        text = pango_layout_get_text (layout);
        placeholder_len = strlen (data->placeholder_str);
        for (p = text; (p = strstr (p, data->placeholder_str)); p += placeholder_len) {
                PangoAttribute *attr;

                attr = pango_attr_shape_new_with_data (&ink_rect,
                                                       &logical_rect,
                                                       GUINT_TO_POINTER (g_utf8_get_char (p)),
                                                       NULL, NULL);

                attr->start_index = p - text;
                attr->end_index = attr->start_index + placeholder_len;

                pango_attr_list_insert (attrs, attr);
        }

        return attrs;
}
static void
make_layout(GtkWidget    *widget,
            PangoLayout **layout_p,
            const char   *value)
{
    if (value == NULL)
        value = "";

    if (*layout_p == NULL) {
        *layout_p = gtk_widget_create_pango_layout(widget, value);
    } else {
        const char *old = pango_layout_get_text(*layout_p);
        if (old && strcmp(old, value) == 0)
            /* nothing */;
        else
            pango_layout_set_text(*layout_p, value, -1);
    }
}
Beispiel #14
0
static AtkAttributeSet*
gail_scale_get_run_attributes (AtkText *text,
                               gint    offset,
                               gint    *start_offset,
	                       gint    *end_offset)
{
  GtkWidget *widget;
  GtkScale *scale;
  AtkAttributeSet *at_set = NULL;
  GtkTextDirection dir;
  PangoLayout *layout;
  const gchar *scale_text;

  widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
  if (widget == NULL)
    /* State is defunct */
    return NULL;

  scale = GTK_SCALE (widget);

  layout = gtk_scale_get_layout (scale);
  if (!layout)
    return at_set;
  scale_text = pango_layout_get_text (layout);
  if (!scale_text)
    return at_set;

  dir = gtk_widget_get_direction (widget);
  if (dir == GTK_TEXT_DIR_RTL)
    {
      at_set = gail_misc_add_attribute (at_set, 
                                        ATK_TEXT_ATTR_DIRECTION,
     g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_DIRECTION, dir)));
    }

  at_set = gail_misc_layout_get_run_attributes (at_set,
                                                layout,
                                                (gchar *)scale_text,
                                                offset,
                                                start_offset,
                                                end_offset);
  return at_set;
}
Beispiel #15
0
static void
dump_lines (PangoLayout *layout, GString *string)
{
  PangoLayoutIter *iter;
  const gchar *text;
  gint index, index2;
  gboolean has_more;
  gchar *char_str;
  gint i;
  PangoLayoutLine *line;

  text = pango_layout_get_text (layout);
  iter = pango_layout_get_iter (layout);

  has_more = TRUE;
  index = pango_layout_iter_get_index (iter);
  i = 0;
  while (has_more)
    {
      line = pango_layout_iter_get_line (iter);
      has_more = pango_layout_iter_next_line (iter);
      i++;

      if (has_more)
        {
          index2 = pango_layout_iter_get_index (iter);
          char_str = g_strndup (text + index, index2 - index);          
        }
      else
        {
          char_str = g_strdup (text + index);
        }

      g_string_append_printf (string, "i=%d, index=%d, paragraph-start=%d, dir=%s '%s'\n",
                              i, index, line->is_paragraph_start, direction_name (line->resolved_dir), 
                              char_str);
      g_free (char_str);

      index = index2;
    }
  pango_layout_iter_free (iter);
}
Beispiel #16
0
static void
gtk_icon_view_item_accessible_get_character_extents (AtkText      *text,
                                                     gint         offset,
                                                     gint         *x,
                                                     gint         *y,
                                                     gint         *width,
                                                     gint         *height,
                                                     AtkCoordType coord_type)
{
  GtkIconViewItemAccessible *item;
#if 0
  GtkIconView *icon_view;
  PangoRectangle char_rect;
  const gchar *item_text;
  gint index;
#endif

  item = GTK_ICON_VIEW_ITEM_ACCESSIBLE (text);

  if (!GTK_IS_ICON_VIEW (item->widget))
    return;

  if (atk_state_set_contains_state (item->state_set, ATK_STATE_DEFUNCT))
    return;

#if 0
  icon_view = GTK_ICON_VIEW (item->widget);
      /* FIXME we probably have to use GailTextCell to salvage this */
  gtk_icon_view_update_item_text (icon_view, item->item);
  item_text = pango_layout_get_text (icon_view->priv->layout);
  index = g_utf8_offset_to_pointer (item_text, offset) - item_text;
  pango_layout_index_to_pos (icon_view->priv->layout, index, &char_rect);

  atk_component_get_position (ATK_COMPONENT (text), x, y, coord_type);
  *x += item->item->layout_x - item->item->x + char_rect.x / PANGO_SCALE;
  /* Look at gtk_icon_view_paint_item() to see where the text is. */
  *x -=  ((item->item->width - item->item->layout_width) / 2) + (MAX (item->item->pixbuf_width, icon_view->priv->item_width) - item->item->width) / 2,
  *y += item->item->layout_y - item->item->y + char_rect.y / PANGO_SCALE;
  *width = char_rect.width / PANGO_SCALE;
  *height = char_rect.height / PANGO_SCALE;
#endif
}
Beispiel #17
0
static gint gtk_anim_label_button_press(GtkWidget * widget, GdkEventButton * event
)
{
	GtkAnimLabel *anim_label;

	g_return_val_if_fail(widget != NULL, FALSE);
	g_return_val_if_fail(GTK_IS_ANIM_LABEL(widget), FALSE);
	g_return_val_if_fail(event != NULL, FALSE);

	anim_label = GTK_ANIM_LABEL(widget);

	if (anim_label->txt)
	{

		char *plain = (char *) pango_layout_get_text(anim_label->layout);
		gtk_clipboard_set_text(gtk_widget_get_clipboard(GTK_WIDGET(anim_label), GDK_SELECTION_CLIPBOARD), plain, -1);
	}

	return FALSE;
}
Beispiel #18
0
static void
text_entry_set_anchor_position(struct text_entry *entry,
			       int32_t x, int32_t y)
{
	int index, trailing;
	const char *text;

	pango_layout_xy_to_index(entry->layout,
				 x * PANGO_SCALE, y * PANGO_SCALE,
				 &index, &trailing);

	text = pango_layout_get_text(entry->layout);
	entry->anchor = g_utf8_offset_to_pointer(text + index, trailing) - text;

	text_entry_update_layout(entry);

	widget_schedule_redraw(entry->widget);

	text_entry_update(entry);
}
static void
ellipsize_layout (PangoLayout *layout, gint width)
{
    PangoLayoutLine *line;
    PangoLayout *ell;
    gint h, w, ell_w, x;
    GString *text;
    
    if (width <= 0) {
        pango_layout_set_text (layout, "", -1);
        return;
    }
    
    pango_layout_get_pixel_size (layout, &w, &h);
    if (w <= width) return;
    
    /* calculate ellipsis width */
    ell = pango_layout_copy (layout);
    pango_layout_set_text (ell, ELLIPSIS, -1);
    pango_layout_get_pixel_size (ell, &ell_w, NULL);
    g_object_unref (ell);

    if (width < ell_w) {
        /* not even ellipsis fits, so hide the text */
        pango_layout_set_text (layout, "", -1);
        return;
    }

    /* shrink total available width by the width of the ellipsis */
    width -= ell_w;
    line = pango_layout_get_line (layout, 0);
    text = g_string_new (pango_layout_get_text (layout));
    if (pango_layout_line_x_to_index (line, width * PANGO_SCALE, &x, NULL)) {
        g_string_set_size (text, x);
        g_string_append (text, ELLIPSIS);
        pango_layout_set_text (layout, text->str, -1);
    }
    g_string_free (text, TRUE);
}
Beispiel #20
0
static gint 
gail_scale_get_offset_at_point (AtkText      *text,
                                gint         x,
                                gint         y,
	          		AtkCoordType coords)
{ 
  GtkWidget *widget;
  GtkScale *scale;
  PangoLayout *layout;
  gint index, x_layout, y_layout;
  const gchar *scale_text;

  widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
  if (widget == NULL)
    /* State is defunct */
    return -1;

  scale = GTK_SCALE (widget);
  layout = gtk_scale_get_layout (scale);
  if (!layout)
    return -1;
  scale_text = pango_layout_get_text (layout);
  if (!scale_text)
    return -1;
  
  gtk_scale_get_layout_offsets (scale, &x_layout, &y_layout);
  index = gail_misc_get_index_at_point_in_layout (widget, 
                                              layout, 
                                              x_layout, y_layout, x, y, coords);
  if (index == -1)
    {
      if (coords == ATK_XY_WINDOW || coords == ATK_XY_SCREEN)
        index = g_utf8_strlen (scale_text, -1);
    }
  else
    index = g_utf8_pointer_to_offset (scale_text, scale_text + index);  

  return index;
}
Beispiel #21
0
static void
gail_scale_real_initialize (AtkObject *obj,
                            gpointer  data)
{
  GailScale *gail_scale;
  const gchar *txt;
  PangoLayout *layout;

  ATK_OBJECT_CLASS (gail_scale_parent_class)->initialize (obj, data);

  gail_scale = GAIL_SCALE (obj);
  gail_scale->textutil = gail_text_util_new ();

  layout = gtk_scale_get_layout (GTK_SCALE (data));
  if (layout)
    {
      txt = pango_layout_get_text (layout);
      if (txt)
        {
          gail_text_util_text_setup (gail_scale->textutil, txt);
        }
    }
}
Beispiel #22
0
static void
text_entry_set_cursor_position(struct text_entry *entry,
			       int32_t x, int32_t y,
			       bool move_anchor)
{
	int index, trailing;
	const char *text;
	uint32_t cursor;

	pango_layout_xy_to_index(entry->layout,
				 x * PANGO_SCALE, y * PANGO_SCALE,
				 &index, &trailing);

	text = pango_layout_get_text(entry->layout);

	cursor = g_utf8_offset_to_pointer(text + index, trailing) - text;

	if (move_anchor)
		entry->anchor = cursor;

	if (text_entry_has_preedit(entry)) {
		text_entry_commit_and_reset(entry);

		assert(!text_entry_has_preedit(entry));
	}

	if (entry->cursor == cursor)
		return;

	entry->cursor = cursor;

	text_entry_update_layout(entry);

	widget_schedule_redraw(entry->widget);

	text_entry_update(entry);
}
Beispiel #23
0
static gboolean
on_entry_draw (GtkWidget *widget,
               cairo_t   *cr,
               gpointer   user_data)
{
  g_debug (G_STRLOC ": %s", G_STRFUNC);

  GtkStyleContext *style_context;
  PangoContext    *pango_context;
  PangoLayout     *layout;
  const char      *text;
  gint             cursor_index;
  gint             x, y;

  style_context = gtk_widget_get_style_context (widget);
  pango_context = gtk_widget_get_pango_context (widget);
  layout = gtk_entry_get_layout (GTK_ENTRY (widget));
  text = pango_layout_get_text (layout);
  gtk_entry_get_layout_offsets (GTK_ENTRY (widget), &x, &y);
  cursor_index = g_utf8_offset_to_pointer (text, gtk_editable_get_position (GTK_EDITABLE (widget))) - text;
  gtk_render_insertion_cursor (style_context, cr, x, y, layout, cursor_index,
                               pango_context_get_base_dir (pango_context));
  return FALSE;
}
Beispiel #24
0
bool wxFont::GTKSetPangoAttrs(PangoLayout* layout) const
{
    if (!IsOk() || !(GetUnderlined() || GetStrikethrough()))
        return false;

    PangoAttrList* attrs = pango_attr_list_new();
    PangoAttribute* a;

    if (wx_pango_version_check(1,16,0))
    {
        // a PangoLayout which has leading/trailing spaces with underlined font
        // is not correctly drawn by this pango version: Pango won't underline the spaces.
        // This can be a problem; e.g. wxHTML rendering of underlined text relies on
        // this behaviour. To workaround this problem, we use a special hack here
        // suggested by pango maintainer Behdad Esfahbod: we prepend and append two
        // empty space characters and give them a dummy colour attribute.
        // This will force Pango to underline the leading/trailing spaces, too.

        const char* text = pango_layout_get_text(layout);
        const size_t n = strlen(text);
        if ((n > 0 && text[0] == ' ') || (n > 1 && text[n - 1] == ' '))
        {
            wxCharBuffer buf(n + 6);
            // copy the leading U+200C ZERO WIDTH NON-JOINER encoded in UTF8 format
            memcpy(buf.data(), "\342\200\214", 3);
            // copy the user string
            memcpy(buf.data() + 3, text, n);
            // copy the trailing U+200C ZERO WIDTH NON-JOINER encoded in UTF8 format
            memcpy(buf.data() + 3 + n, "\342\200\214", 3);

            pango_layout_set_text(layout, buf, n + 6);

            // Add dummy attributes (use colour as it's invisible anyhow for 0
            // width spaces) to ensure that the spaces in the beginning/end of the
            // string are underlined too.
            a = pango_attr_foreground_new(0x0057, 0x52A9, 0xD614);
            a->start_index = 0;
            a->end_index = 3;
            pango_attr_list_insert(attrs, a);

            a = pango_attr_foreground_new(0x0057, 0x52A9, 0xD614);
            a->start_index = n + 3;
            a->end_index = n + 6;
            pango_attr_list_insert(attrs, a);
        }
    }
    if (GetUnderlined())
    {
        a = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
        pango_attr_list_insert(attrs, a);
    }
    if (GetStrikethrough())
    {
        a = pango_attr_strikethrough_new(true);
        pango_attr_list_insert(attrs, a);
    }

    pango_layout_set_attributes(layout, attrs);
    pango_attr_list_unref(attrs);

    return true;
}
Beispiel #25
0
static PyObject *
pango_GetLayoutClusterPos(PyObject *self, PyObject *args) {

	int i, len, w, h, index, prev_index;
	int ltr_flag, rtl_flag;
	double baseline, x, y, width, height, char_width, dx, dy;
	void *LayoutObj;
	PangoLayout *layout;
	PangoLayoutIter *iter;
	PangoLayoutIter *cluster_iter;
	PangoRectangle rect, cluster_rect;
	PangoDirection dir;
	PyObject *ret;
	PyObject *layout_data;
	PyObject *cluster_data;
	PyObject *cluster_range;
	PyObject *cluster_index_data;
	PyObject *cluster_index_range;
	PyObject *glyph_data;

	if (!PyArg_ParseTuple(args, "Oi", &LayoutObj, &len)) {
		return NULL;
	}

	layout = PyCObject_AsVoidPtr(LayoutObj);

	pango_layout_get_size(layout, &w, &h);
	dx = 0.0;
	if (pango_layout_get_alignment(layout) == PANGO_ALIGN_CENTER) {
		dx = -0.5 * ((double) w) / PANGO_SCALE;
	} else if (pango_layout_get_alignment(layout) == PANGO_ALIGN_RIGHT) {
		dx = -1.0 * ((double) w) / PANGO_SCALE;
	}


	ret = PyTuple_New(5);
	layout_data = PyList_New(0);
	cluster_data = PyList_New(0);
	cluster_index_data = PyList_New(0);

	PyTuple_SetItem(ret, 0, layout_data);
	PyTuple_SetItem(ret, 1, cluster_data);
	PyTuple_SetItem(ret, 2, cluster_index_data);

	iter = pango_layout_get_iter(layout);
	cluster_iter = pango_layout_get_iter(layout);

	prev_index = -1;
	rtl_flag = 0;
	ltr_flag = 0;

	dy = ((double) pango_layout_iter_get_baseline(iter)) / PANGO_SCALE;

	for (i = 0; i < len; i++) {
		glyph_data = PyTuple_New(6);

		//Processing EOL

		while (pango_layout_iter_get_baseline(cluster_iter) !=
				pango_layout_iter_get_baseline(iter)) {

			pango_layout_iter_get_char_extents(iter, &rect);

			x = ((double) rect.x) / PANGO_SCALE + dx;
			PyTuple_SetItem(glyph_data, 0, PyFloat_FromDouble(x));

			y = -1.0 * ((double) rect.y) / PANGO_SCALE + dy;
			PyTuple_SetItem(glyph_data, 1, PyFloat_FromDouble(y));

			width = ((double) rect.width) / PANGO_SCALE;
			PyTuple_SetItem(glyph_data, 2, PyFloat_FromDouble(width));

			height = ((double) rect.height) / PANGO_SCALE;
			PyTuple_SetItem(glyph_data, 3, PyFloat_FromDouble(height));

			baseline = -1.0 * ((double) pango_layout_iter_get_baseline(iter))
					/ PANGO_SCALE + dy;
			PyTuple_SetItem(glyph_data, 4, PyFloat_FromDouble(baseline));

			//index processing
			index=pango_layout_iter_get_index(iter);
			prev_index = index;
			PyTuple_SetItem(glyph_data, 5, PyInt_FromLong(index));

			PyList_Append(layout_data, glyph_data);

			pango_layout_iter_next_char(iter);
			i++;
			glyph_data = PyTuple_New(6);
		}

		pango_layout_iter_get_char_extents(iter, &rect);
		pango_layout_iter_get_cluster_extents(cluster_iter, NULL, &cluster_rect);

		//Processing cluster data
		//Layout_data: (x,y,width,height,base_line,byte_index)

		x = ((double) cluster_rect.x) / PANGO_SCALE + dx;
		PyTuple_SetItem(glyph_data, 0, PyFloat_FromDouble(x));

		y = -1.0 * ((double) cluster_rect.y) / PANGO_SCALE + dy;
		PyTuple_SetItem(glyph_data, 1, PyFloat_FromDouble(y));

		width = ((double) cluster_rect.width) / PANGO_SCALE;
		PyTuple_SetItem(glyph_data, 2, PyFloat_FromDouble(width));

		height = ((double) cluster_rect.height) / PANGO_SCALE;
		PyTuple_SetItem(glyph_data, 3, PyFloat_FromDouble(height));

		baseline = -1.0 * ((double) pango_layout_iter_get_baseline(cluster_iter))
				/ PANGO_SCALE + dy;
		PyTuple_SetItem(glyph_data, 4, PyFloat_FromDouble(baseline));

		//index processing
		index=pango_layout_iter_get_index(iter);
		if (prev_index != -1){
			if(index < prev_index){
				rtl_flag=1;
			}else if(index > prev_index){
				ltr_flag=1;
			}
		}
		prev_index = index;
		PyTuple_SetItem(glyph_data, 5, PyInt_FromLong(index));

		PyList_Append(layout_data, glyph_data);

		//Iterating over chars to next cluster

		if(cluster_rect.width > rect.width){
			char_width = rect.width;
			cluster_range = PyTuple_New(2);
			cluster_index_range = PyTuple_New(2);
			PyTuple_SetItem(cluster_range, 0, PyInt_FromLong(i));
			PyTuple_SetItem(cluster_index_range, 0,
					PyInt_FromLong(pango_layout_iter_get_index(iter)));
			while(cluster_rect.width > char_width){
				pango_layout_iter_next_char(iter);
				pango_layout_iter_get_char_extents(iter, &rect);
				char_width = char_width + rect.width;
				i++;
			}
			PyTuple_SetItem(cluster_range, 1, PyInt_FromLong(i + 1));
			PyTuple_SetItem(cluster_index_range, 1,
					PyInt_FromLong(pango_layout_iter_get_index(iter)));
			PyList_Append(cluster_data, cluster_range);
			PyList_Append(cluster_index_data, cluster_index_range);
		}

		pango_layout_iter_next_char(iter);
		pango_layout_iter_next_cluster(cluster_iter);
	}

	pango_layout_iter_free(iter);
	pango_layout_iter_free(cluster_iter);

	if(rtl_flag + ltr_flag == 2){
		PyTuple_SetItem(ret, 3, PyBool_FromLong(1));
	}else{
		PyTuple_SetItem(ret, 3, PyBool_FromLong(0));
	}

	dir = pango_find_base_dir(pango_layout_get_text(layout),-1);
	if(dir == PANGO_DIRECTION_RTL) {
		PyTuple_SetItem(ret, 4, PyBool_FromLong(1));
	} else {
		PyTuple_SetItem(ret, 4, PyBool_FromLong(0));
	}

	return ret;
}
Beispiel #26
0
static VALUE
rg_text(VALUE self)
{
    return CSTR2RVAL(pango_layout_get_text(_SELF(self)));
}
Beispiel #27
0
static gboolean
text_item_renderer (AboutRenderer *r, AboutState *state)
{
	PangoLayout *layout = r->layout;
	int age = state->now - r->start_time;
	double rage = CLAMP (age / (double)r->duration, 0.0, 1.0);
	GtkWidget *widget = state->anim_area;
	GtkStyleContext *ctxt;
	const int fade = 500;
	int x, y, width, height;
	cairo_t *cr;
	GtkAllocation wa;
	GdkRGBA color;
	double alpha = 1;

	if (age >= r->duration)
		return FALSE;

	if (r->fade_in && age < fade)
		alpha = age / (double)fade;
	else if (r->fade_out && r->duration - age < fade)
		alpha = (r->duration - age) / (double)fade;

	ctxt = gtk_widget_get_style_context (widget);

	gtk_widget_get_allocation (widget, &wa);
	x = (int)(PANGO_SCALE * wa.width *
		  (r->start.x + rage * (r->end.x - r->start.x)));
	y = (int)(PANGO_SCALE * wa.height *
		  (r->start.y + rage * (r->end.y - r->start.y)));

	if (r->expansion.count) {
		PangoAttrList *attrlist = pango_layout_get_attributes (layout);
		const char *p, *text = pango_layout_get_text (layout);
		PangoRectangle ink, logical;

		memset (&ink, 0, sizeof (ink));
		logical = ink;

		logical.width = (int)(rage * r->expansion.rate * r->natural_width / r->expansion.count);

		p = text;
		while (*p) {
			const char *next = g_utf8_next_char (p);
			gunichar uc = g_utf8_get_char (p);
			PangoAttribute *attr;

			if (uc == UNICODE_ZERO_WIDTH_SPACE_C) {
				attr = pango_attr_shape_new (&ink, &logical);
				attr->start_index = p - text;
				attr->end_index = next - text;
				pango_attr_list_change (attrlist, attr);
			}
			p = next;
		}
		pango_layout_set_attributes (layout, attrlist);
	}

	pango_layout_get_size (layout, &width, &height);
	x -= width / 2;
	y -= height / 2;

	cr = r->cr;
	gnm_style_context_get_color (ctxt, GTK_STATE_FLAG_NORMAL, &color);
	color.alpha = alpha;
	gdk_cairo_set_source_rgba (cr, &color);
	cairo_move_to (cr, x / (double)PANGO_SCALE, y / (double)PANGO_SCALE);
	pango_cairo_show_layout (cr, layout);

	return TRUE;
}
PangoLayout*
gdip_pango_setup_layout (GpGraphics *graphics, GDIPCONST WCHAR *stringUnicode, int length, GDIPCONST GpFont *font,
	GDIPCONST RectF *rc, RectF *box, GDIPCONST GpStringFormat *format, int **charsRemoved)
{
	GpStringFormat *fmt;
	PangoLayout *layout;
	PangoContext *context;
	PangoRectangle logical;   /* logical size of text (used for alignment) */
	PangoRectangle ink;       /* ink size of text (to pixel boundaries) */
	PangoAttrList *list = NULL;
	GString *ftext;
	PangoTabArray *tabs;
	PangoLayoutIter *iter;
	int i;
	int FrameWidth;     /* rc->Width (or rc->Height if vertical) */
	int FrameHeight;    /* rc->Height (or rc->Width if vertical) */
	int FrameX;         /* rc->X (or rc->Y if vertical) */
	int FrameY;         /* rc->Y (or rc->X if vertical) */
	int y0;             /* y0,y1,clipNN used for checking line positions vs. clip rectangle */
	int y1;
	double clipx1;
	double clipx2;
	double clipy1;
	double clipy2;
	int trimSpace;      /* whether or not to trim the space */

	gchar *text = ucs2_to_utf8 (stringUnicode, length);
	if (!text)
		return NULL;
	length = strlen(text);

	if (charsRemoved) {
		(*charsRemoved) = GdipAlloc (sizeof (int) * length);
		if (!*charsRemoved) {
			GdipFree (text);
		return NULL;
		}
		memset (*charsRemoved, 0, sizeof (int) * length);
	}

	/* TODO - Digit substitution */

// g_warning ("layout >%s< (%d) [x %g, y %g, w %g, h %g] [font %s, %g points]", text, length, rc->X, rc->Y, rc->Width, FrameHeight, font->face, font->emSize);

	/* a NULL format is valid, it means get the generic default values (and free them later) */
	if (!format) {
		GpStatus status = GdipStringFormatGetGenericDefault ((GpStringFormat **)&fmt);
		if (status != Ok) {
			GdipFree (text);
			return NULL;
		}
	} else {
		fmt = (GpStringFormat *)format;
	}

	layout = pango_cairo_create_layout (graphics->ct);

	/* context is owned by Pango (i.e. not referenced counted) do not free */
	context = pango_layout_get_context (layout);

	pango_layout_set_font_description (layout, gdip_get_pango_font_description ((GpFont*) font));

	if (fmt->formatFlags & StringFormatFlagsDirectionVertical) {
		FrameWidth = MAKE_SAFE_FOR_PANGO (SAFE_FLOAT_TO_UINT32 (rc->Height));
		FrameHeight = MAKE_SAFE_FOR_PANGO (SAFE_FLOAT_TO_UINT32 (rc->Width));
		FrameX = SAFE_FLOAT_TO_UINT32 (rc->Y);
		FrameY = SAFE_FLOAT_TO_UINT32 (rc->X);
	} else {
		FrameWidth = MAKE_SAFE_FOR_PANGO (SAFE_FLOAT_TO_UINT32 (rc->Width));
		FrameHeight = MAKE_SAFE_FOR_PANGO (SAFE_FLOAT_TO_UINT32 (rc->Height));
		FrameX = SAFE_FLOAT_TO_UINT32 (rc->X);
		FrameY = SAFE_FLOAT_TO_UINT32 (rc->Y);
	}
	//g_warning("FW: %d\tFH: %d", FrameWidth, FrameHeight);

	if ((FrameWidth <= 0) || (fmt->formatFlags & StringFormatFlagsNoWrap)) {
		pango_layout_set_width (layout, -1);
		//g_warning ("Setting width: %d", -1);
	} else {
		pango_layout_set_width (layout, FrameWidth * PANGO_SCALE);
		//g_warning ("Setting width: %d", FrameWidth * PANGO_SCALE);
	}

	if ((rc->Width != 0) && (rc->Height != 0) && ((fmt->formatFlags & StringFormatFlagsNoClip) == 0)) {
// g_warning ("\tclip [%g %g %g %g]", rc->X, rc->Y, rc->Width, rc->Height);
		/* We do not call cairo_reset_clip because we want to take previous clipping into account */
		/* Use rc instead of frame variables because this is pre-transform */
		gdip_cairo_rectangle (graphics, rc->X, rc->Y, rc->Width, rc->Height, TRUE);
		cairo_clip (graphics->ct);
	}

		/* with GDI+ the API not the renderer makes the direction decision */
		pango_layout_set_auto_dir (layout, FALSE);
	if (!(fmt->formatFlags & StringFormatFlagsDirectionRightToLeft) != !(fmt->formatFlags & StringFormatFlagsDirectionVertical)) {
		pango_context_set_base_dir (context, PANGO_DIRECTION_WEAK_RTL);
		pango_layout_context_changed (layout);

		/* horizontal alignment */
		switch (fmt->alignment) {
		case StringAlignmentNear:
			pango_layout_set_alignment (layout, PANGO_ALIGN_RIGHT);
			break;
		case StringAlignmentCenter:
			pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER);
			break;
		case StringAlignmentFar:
			pango_layout_set_alignment (layout, PANGO_ALIGN_LEFT);
			break;
		}
	} else {
		/* pango default base dir is WEAK_LTR, which is what we want */

		/* horizontal alignment */
		switch (fmt->alignment) {
		case StringAlignmentNear:
			pango_layout_set_alignment (layout, PANGO_ALIGN_LEFT);
			break;
		case StringAlignmentCenter:
			pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER);
			break;
		case StringAlignmentFar:
			pango_layout_set_alignment (layout, PANGO_ALIGN_RIGHT);
			break;
		}
	}

#ifdef PANGO_VERSION_CHECK
#if PANGO_VERSION_CHECK(1,16,0)
	if (fmt->formatFlags & StringFormatFlagsDirectionVertical) {
		if (fmt->formatFlags & StringFormatFlagsDirectionRightToLeft) {
			cairo_rotate (graphics->ct, M_PI/2.0);
			cairo_translate (graphics->ct, 0, -FrameHeight);
			pango_cairo_update_context (graphics->ct, context);
		} else {
			cairo_rotate (graphics->ct, 3.0*M_PI/2.0);
			cairo_translate (graphics->ct, -FrameWidth, 0);
			pango_cairo_update_context (graphics->ct, context);
		}
		/* only since Pango 1.16 */
		pango_context_set_base_gravity (context, PANGO_GRAVITY_AUTO);
		pango_context_set_gravity_hint (context, PANGO_GRAVITY_HINT_LINE);
		pango_layout_context_changed (layout);
	}
#endif
#endif

	/* TODO - StringFormatFlagsDisplayFormatControl
		scan and replace them ??? */

	/* Trimming options seem to apply only to the end of the string - gdi+ will still wrap
	 * with preference to word first, then character.  Unfortunately, pango doesn't have
	 * any way to differentiate wrapping behavior from trimming behavior that I could find */
	pango_layout_set_wrap (layout, PANGO_WRAP_WORD_CHAR);
	switch (fmt->trimming) {
	case StringTrimmingNone:
		pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_NONE);
		break;
	case StringTrimmingCharacter:
		pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_NONE);
		break;
	case StringTrimmingWord:
		pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_NONE);
		break;
	case StringTrimmingEllipsisCharacter:
		pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END);
		if (!(fmt->formatFlags & StringFormatFlagsNoWrap))
			pango_layout_set_height (layout, FrameHeight == 0 ? G_MAXINT32 : FrameHeight * PANGO_SCALE);
		break;
	case StringTrimmingEllipsisWord:
		pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END);
		if (!(fmt->formatFlags & StringFormatFlagsNoWrap))
			pango_layout_set_height (layout, FrameHeight == 0 ? G_MAXINT32 : FrameHeight * PANGO_SCALE);
		break;
	case StringTrimmingEllipsisPath:
		pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_MIDDLE);
		if (!(fmt->formatFlags & StringFormatFlagsNoWrap))
			pango_layout_set_height (layout, FrameHeight == 0 ? G_MAXINT32 : FrameHeight * PANGO_SCALE);
		break;
	}

	/* some stuff can only be done by manipulating the attributes (but we can avoid this most of the time) */
	if ((fmt->formatFlags & StringFormatFlagsNoFontFallback) || (font->style & (FontStyleUnderline | FontStyleStrikeout))) {

		list = gdip_get_layout_attributes (layout);

		/* StringFormatFlagsNoFontFallback */
		if (fmt->formatFlags & StringFormatFlagsNoFontFallback) {
			PangoAttribute *attr = pango_attr_fallback_new (FALSE);
			attr->start_index = 0;
			attr->end_index = length;
			pango_attr_list_insert (list, attr);
		}

		if (font->style & FontStyleUnderline) {
			PangoAttribute *attr = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE);
			attr->start_index = 0;
			attr->end_index = length;
			pango_attr_list_insert (list, attr);
		}

		if (font->style & FontStyleStrikeout) {
			PangoAttribute *attr = pango_attr_strikethrough_new (TRUE);
			attr->start_index = 0;
			attr->end_index = length;
			pango_attr_list_insert (list, attr);
		}
	}

	if (fmt->numtabStops > 0) {
		float tabPosition;
		tabs = pango_tab_array_new (fmt->numtabStops, FALSE);
		tabPosition = fmt->firstTabOffset;
		for (i = 0; i < fmt->numtabStops; i++) {
			tabPosition += fmt->tabStops[i];
			pango_tab_array_set_tab (tabs, i, PANGO_TAB_LEFT, (gint)min (tabPosition, PANGO_MAX) * PANGO_SCALE);
		}
		pango_layout_set_tabs (layout, tabs);
		pango_tab_array_free (tabs);
	}

	//g_warning ("length before ws removal: %d", length);
	trimSpace = (fmt->formatFlags & StringFormatFlagsMeasureTrailingSpaces) == 0;
	switch (fmt->hotkeyPrefix) {
	case HotkeyPrefixHide:
		/* we need to remove any accelerator from the string */
		ftext = gdip_process_string (text, length, 1, trimSpace, NULL, charsRemoved);
		break;
	case HotkeyPrefixShow:
		/* optimization: is seems that we never see the hotkey when using an underline font */
		if (font->style & FontStyleUnderline) {
			/* so don't bother drawing it (and simply add the '&' character) */
			ftext = gdip_process_string (text, length, 1, trimSpace, NULL, charsRemoved);
		} else {
			/* find accelerator and add attribute to the next character (unless it's the prefix too) */
			if (!list)
				list = gdip_get_layout_attributes (layout);
			ftext = gdip_process_string (text, length, 1, trimSpace, list, charsRemoved);
		}
		break;
	default:
		ftext = gdip_process_string (text, length, 0, trimSpace, NULL, charsRemoved);
		break;
	}
	length = ftext->len;
	//g_warning ("length after ws removal: %d", length);

	if (list) {
		pango_layout_set_attributes (layout, list);
		pango_attr_list_unref (list);
	}

// g_warning("\tftext>%s< (%d)", ftext->str, -1);
	pango_layout_set_text (layout, ftext->str, ftext->len);
	GdipFree (text);
	g_string_free(ftext, TRUE);

	/* Trim the text after the last line for ease of counting lines/characters */
	/* Also prevents drawing whole lines outside the boundaries if NoClip was specified */
	/* In case of pre-existing clipping, use smaller of clip rectangle or our specified height */
	if (FrameHeight > 0) {
		cairo_clip_extents (graphics->ct, &clipx1, &clipy1, &clipx2, &clipy2);
		if (clipy2 > 0 && !(fmt->formatFlags & StringFormatFlagsNoClip))
			clipy2 = min (clipy2, FrameHeight + FrameY);
		else
			clipy2 = FrameHeight + FrameY;
		iter = pango_layout_get_iter (layout);
		do {
			if (iter == NULL)
				break;
			pango_layout_iter_get_line_yrange (iter, &y0, &y1);
			//g_warning("yrange: %d  %d  clipy2: %f", y0 / PANGO_SCALE, y1 / PANGO_SCALE, clipy2);
			/* StringFormatFlagsLineLimit */
			if (((fmt->formatFlags & StringFormatFlagsLineLimit) && y1 / PANGO_SCALE > clipy2) || (y0 / PANGO_SCALE > clipy2)) {
				PangoLayoutLine *line = pango_layout_iter_get_line_readonly (iter);
				pango_layout_set_text (layout, pango_layout_get_text (layout), line->start_index);
				break;
			}
		} while (pango_layout_iter_next_line (iter));
		pango_layout_iter_free (iter);
	}

	pango_layout_get_pixel_extents (layout, &ink, &logical);
// g_warning ("\tlogical\t[x %d, y %d, w %d, h %d][x %d, y %d, w %d, h %d]", logical.x, logical.y, logical.width, logical.height, ink.x, ink.y, ink.width, ink.height);

	if ((fmt->formatFlags & StringFormatFlagsNoFitBlackBox) == 0) {
		/* By default don't allow overhang - ink space may be larger than logical space */
		if (fmt->formatFlags & StringFormatFlagsDirectionVertical) {
			box->X = min (ink.y, logical.y);
			box->Y = min (ink.x, logical.x);
			box->Height = max (ink.width, logical.width);
			box->Width = max (ink.height, logical.height);
		} else {
			box->X = min (ink.x, logical.x);
			box->Y = min (ink.y, logical.y);
			box->Height = max (ink.height, logical.height);
			box->Width = max (ink.width, logical.width);
		}
	} else {
		/* Allow overhang */
		if (fmt->formatFlags & StringFormatFlagsDirectionVertical) {
			box->X = logical.y;
			box->Y = logical.x;
			box->Height = logical.width;
			box->Width = logical.height;
		} else {
			box->X = logical.x;
			box->Y = logical.y;
	box->Height = logical.height;
			box->Width = logical.width;
		}
	}
// g_warning ("\tbox\t[x %g, y %g, w %g, h %g]", box->X, box->Y, box->Width, box->Height);

	/* vertical alignment*/
	if (fmt->formatFlags & StringFormatFlagsDirectionVertical) {
		switch (fmt->lineAlignment) {
		case StringAlignmentNear:
			break;
		case StringAlignmentCenter:
			box->X += (rc->Width - box->Width) / 2;
			break;
		case StringAlignmentFar:
			box->X += (rc->Width - box->Width);
			break;
		}
	} else {
	switch (fmt->lineAlignment) {
	case StringAlignmentNear:
		break;
	case StringAlignmentCenter:
			box->Y += (rc->Height - box->Height) / 2;
		break;
	case StringAlignmentFar:
			box->Y += (rc->Height - box->Height);
		break;
	}
	}
// g_warning ("va-box\t[x %g, y %g, w %g, h %g]", box->X, box->Y, box->Width, box->Height);

	pango_cairo_update_layout (graphics->ct, layout);

	return layout;
}
GpStatus
pango_MeasureString (GpGraphics *graphics, GDIPCONST WCHAR *stringUnicode, int length, GDIPCONST GpFont *font, GDIPCONST RectF *rc,
	GDIPCONST GpStringFormat *format, RectF *boundingBox, int *codepointsFitted, int *linesFilled)
{
	PangoLayout *layout;
	PangoLayoutLine *line;
	PangoRectangle logical;
	PangoLayoutIter *iter;
	int *charsRemoved = NULL;

	cairo_save (graphics->ct);

	layout = gdip_pango_setup_layout (graphics, stringUnicode, length, font, rc, boundingBox, format, &charsRemoved);
	if (!layout) {
		cairo_restore (graphics->ct);
		return OutOfMemory;
	}

	if (codepointsFitted) {
		int charsFitted;
		int lastIndex;
		int y0;
		int y1;
		double min_x;
		double max_x;
		double max_y;
		const char *layoutText;
		if (boundingBox && format && (format->formatFlags & StringFormatFlagsDirectionVertical)) {
			min_x = boundingBox->Y;
			max_x = boundingBox->Y + boundingBox->Height;
			max_y = boundingBox->X + boundingBox->Width;
		} else if (boundingBox) {
			min_x = boundingBox->X;
			max_x = boundingBox->X + boundingBox->Width;
			max_y = boundingBox->Y + boundingBox->Height;
		} else if (format && (format->formatFlags & StringFormatFlagsDirectionVertical)) {
			min_x = rc->Y;
			max_x = rc->Y + rc->Height;
			max_y = rc->X + rc->Width;
		} else {
			min_x = rc->X;
			max_x = rc->X + rc->Width;
			max_y = rc->Y + rc->Height;
		}
		lastIndex = 0;
		iter = pango_layout_get_iter (layout);
		do {
			if (iter == NULL)
				break;
			pango_layout_iter_get_line_yrange (iter, &y0, &y1);
			if (y0 / PANGO_SCALE >= max_y)
				break;
			if (pango_layout_iter_at_last_line (iter)) {
				do {
					pango_layout_iter_get_char_extents (iter, &logical);
					/* check both max and min to catch right-to-left text, also width may be negative */
					if ((logical.x / PANGO_SCALE > max_x || (logical.x + logical.width) / PANGO_SCALE > max_x) || (logical.x / PANGO_SCALE < min_x || (logical.x + logical.width) / PANGO_SCALE < min_x))
						break;
					lastIndex = pango_layout_iter_get_index (iter);
				} while (pango_layout_iter_next_char (iter));
				break;
			} else {
				line = pango_layout_iter_get_line_readonly (iter);
				lastIndex = line->start_index + line->length - 1;
			}
		} while (pango_layout_iter_next_line (iter));
		pango_layout_iter_free (iter);
		layoutText = pango_layout_get_text (layout);
		/* this can happen when the string ends in a newline */
		if (lastIndex >= strlen (layoutText))
			lastIndex = strlen (layoutText) - 1;
		/* Add back in any & characters removed and the final newline characters (if any) */
		charsFitted = g_utf8_strlen (layoutText, lastIndex + 1) + charsRemoved [lastIndex];
		//g_warning("lastIndex: %d\t\tcharsRemoved: %d", lastIndex, charsRemoved[lastIndex]);
		/* safe because of null termination */
		switch (layoutText [lastIndex + 1]) {
			case '\r':
				charsFitted++;
				if (layoutText [lastIndex + 2] == '\n')
					charsFitted++;
				break;
			case '\n':
				charsFitted++;
				break;
		}
		*codepointsFitted = charsFitted;
	}

	GdipFree (charsRemoved);

	if (linesFilled) {
		*linesFilled = pango_layout_get_line_count (layout);
// g_warning ("linesFilled %d", *linesFilled);
	}
// else g_warning ("linesFilled %d", pango_layout_get_line_count (layout));

	g_object_unref (layout);
	cairo_restore (graphics->ct);
	return Ok;
}
JNIEXPORT void JNICALL
Java_org_gnome_pango_PangoAttributeOverride_pango_1attribute_1set_1indexes
(
	JNIEnv* env,
	jclass cls,
	jlong _self,
	jlong _layout,
	jint _offset,
	jint _width
)
{
	PangoAttribute* self;
	PangoLayout* layout;
	gint offset;
	gint width;
	const char* text;
	char* alpha;
	char* omega;
	guint start;
	guint end;
	
	// convert paramter self
	self = (PangoAttribute*) _self;

	// convert paramter layout
	layout = (PangoLayout*) _layout;

	// convert parameter offset
	offset = (gint) _offset;

	// convert parameter width
	width = (gint) _width;

	// convert to bounds
	/*
	 * Get the text out of the layout, and then work out what
	 * the offset and offset+width work out to in byte terms.
	 */

	text = pango_layout_get_text(layout);

	alpha = g_utf8_offset_to_pointer(text, offset);
	omega = g_utf8_offset_to_pointer(text, offset + width);

	start = alpha - text;
	end = omega - text;

	// set fields
	self->start_index = start;
	self->end_index = end;
	
	// cleanup parameter self

	// cleanup parameter layout

	// cleanup parameter offset

	// cleanup parameter width

	// local text should not be modified or freed
}