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); }
gui2::tpoint ttext::get_cursor_position( const unsigned column, const unsigned line) const { recalculate(); // First we need to determine the byte offset, if more routines need it it // would be a good idea to make it a separate function. titor itor(layout_); // Go the wanted line. if(line != 0) { if(pango_layout_get_line_count(layout_) >= static_cast<int>(line)) { return gui2::tpoint(0, 0); } for(size_t i = 0; i < line; ++i) { pango_layout_iter_next_line(itor); } } // Go the wanted column. for(size_t i = 0; i < column; ++i) { if(!pango_layout_iter_next_char(itor)) { // It seems that the documentation is wrong and causes and off by // one error... the result should be false if already at the end of // the data when started. if(i + 1 == column) { break; } // We are beyond data. return gui2::tpoint(0, 0); } } // Get the byte offset const int offset = pango_layout_iter_get_index(itor); // Convert the byte offset in a position. PangoRectangle rect; pango_layout_get_cursor_pos(layout_, offset, &rect, nullptr); return gui2::tpoint(PANGO_PIXELS(rect.x), PANGO_PIXELS(rect.y)); }
static gboolean gw_spellcheck_get_line_coordinates (GwSpellcheck *spellcheck, int startindex, int endindex, int *x, int *y, int *x2, int *y2) { //Declarations GwSpellcheckPrivate *priv; int index; PangoLayout *layout; PangoRectangle rect; PangoLayoutIter *iter; int xoffset, yoffset; //Initializations priv = spellcheck->priv; layout = gtk_entry_get_layout (priv->entry); iter = pango_layout_get_iter (layout); xoffset = gw_spellcheck_get_layout_x_offset (spellcheck); yoffset = gw_spellcheck_get_layout_y_offset (spellcheck); *x = *y = *x2 = *y2 = 0; do { index = pango_layout_iter_get_index (iter); pango_layout_iter_get_char_extents (iter, &rect); if (index == startindex) { *x = PANGO_PIXELS (rect.x) + xoffset; *y = PANGO_PIXELS (rect.y + rect.height) + yoffset; } if (index == endindex - 1) { *x2 = PANGO_PIXELS (rect.width + rect.x) + xoffset + 1; *y2 = *y; } } while (pango_layout_iter_next_char (iter)); //Cleanup pango_layout_iter_free (iter); return (*x > 0 && *y > 0 && *x2 > 0 && *y2 > 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; }
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; }
static gboolean layout_is_ellipsized(PangoLayout *layout) { /* pango_layout_is_ellipsized() is a new function in Pango-1.16; we * emulate it here by trying to look for the ellipsis run */ PangoLogAttr *log_attrs; int n_attrs; PangoLayoutIter *iter; gboolean result = FALSE; /* Short circuit when we aren't ellipsizing at all */ if (pango_layout_get_ellipsize(layout) == PANGO_ELLIPSIZE_NONE) return FALSE; pango_layout_get_log_attrs(layout, &log_attrs, &n_attrs); iter = pango_layout_get_iter(layout); do { PangoGlyphItem *run; int n_glyphs; int start_index; int n_graphemes; int i; run = pango_layout_iter_get_run(iter); if (!run) continue; n_glyphs = run->glyphs->num_glyphs; start_index = pango_layout_iter_get_index(iter); /* Check the number of clusters in the run ... if it is greater * than 1, then it isn't an ellipsis */ if (run->glyphs->log_clusters[0] != run->glyphs->log_clusters[n_glyphs - 1]) continue; /* Now check the number of graphemes in the run ... if it is less * than 3, it's probably an isolated 'fi' ligature or something * like that rather than an ellipsis. */ n_graphemes = 0; for (i = 0; i < run->item->num_chars && i + start_index < n_attrs; i++) if (log_attrs[i + start_index].is_cursor_position) n_graphemes++; if (n_graphemes < 3) continue; /* OK, at this point it is probably an ellipsis; it's possible that * the text consists of just the letters 'ffi' and the font has a ligature * for that or something, but it's not too likely. */ result = TRUE; break; } while (pango_layout_iter_next_run(iter)); pango_layout_iter_free(iter); g_free(log_attrs); return result; }
static void create_pages (Pqueue * queue) { gchar * msg; gdouble line_height; guint i, id; glong index; PangoLayoutLine * line; PangoRectangle ink_rect, logical_rect; g_return_if_fail (queue); g_return_if_fail (queue->pos < strlen(queue->text)); while (queue->pos < strlen (queue->text)) { while (gtk_events_pending ()) gtk_main_iteration (); for (i = 0; i < queue->lines_per_page; i++) { line = pango_layout_iter_get_line (queue->iter); pango_layout_iter_next_line (queue->iter); pango_layout_iter_get_line_extents (queue->iter, &ink_rect, &logical_rect); index = pango_layout_iter_get_index (queue->iter); if (index == 0) { i = queue->lines_per_page; queue->pos = strlen (queue->text); g_message ("%s", _("Error: Pango iter index is zero.")); continue; } line_height = logical_rect.height / PANGO_SCALE; if ((queue->page_height + line_height) > (queue->height - (EDGE_MARGIN/2))) { queue->pos += index; queue->page_height = EDGE_MARGIN; gtk_progress_bar_pulse (queue->progressbar); pango_cairo_update_layout (queue->cr, queue->layout); queue->layout = make_new_page (queue->context, queue->desc, queue->height, queue->width); i = queue->lines_per_page; queue->page_count++; pango_layout_set_text (queue->layout, (queue->text+queue->pos), -1); queue->iter = pango_layout_get_iter (queue->layout); pango_cairo_show_layout_line (queue->cr, line); pango_cairo_update_layout (queue->cr, queue->layout); cairo_show_page (queue->cr); } else pango_cairo_show_layout_line (queue->cr, line); queue->page_height += line_height; cairo_move_to (queue->cr, SIDE_MARGIN / 2, queue->page_height); } } pango_layout_iter_free (queue->iter); gtk_progress_bar_set_fraction (queue->progressbar, 0.0); cairo_surface_destroy(queue->surface); pango_font_description_free (queue->desc); g_object_unref (queue->context); g_object_unref (queue->layout); cairo_destroy (queue->cr); id = gtk_statusbar_get_context_id (queue->statusbar, PACKAGE); msg = g_strdup_printf (ngettext("Saved PDF file. (%ld page)", "Saved PDF file (%ld pages).", queue->page_count), queue->page_count); gtk_statusbar_push (queue->statusbar, id, msg); g_free (msg); }
static void dump_runs (PangoLayout *layout, GString *string) { PangoLayoutIter *iter; PangoLayoutRun *run; PangoItem *item; const gchar *text; gint index, index2; gboolean has_more; gchar *char_str; gint i; gchar *font; 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) { run = pango_layout_iter_get_run (iter); has_more = pango_layout_iter_next_run (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); } if (run) { item = ((PangoGlyphItem*)run)->item; font = font_name (item->analysis.font); g_string_append_printf (string, "i=%d, index=%d, chars=%d, level=%d, gravity=%s, flags=%d, font=%s, script=%s, language=%s, '%s'\n", i, index, item->num_chars, item->analysis.level, gravity_name (item->analysis.gravity), item->analysis.flags, "OMITTED", /* for some reason, this fails on build.gnome.org, so leave it out */ script_name (item->analysis.script), pango_language_to_string (item->analysis.language), char_str); dump_extra_attrs (item->analysis.extra_attrs, string); g_free (font); } else { g_string_append_printf (string, "i=%d, index=%d, no run, line end\n", i, index); } g_free (char_str); index = index2; } pango_layout_iter_free (iter); }
static VALUE layout_iter_get_index(VALUE self) { return INT2NUM(pango_layout_iter_get_index(_SELF(self))); }