static VALUE rpango_find_base_dir(VALUE self, VALUE text) { StringValue(text); return GENUM2RVAL(pango_find_base_dir(RSTRING_PTR(text), RSTRING_LEN(text)), PANGO_TYPE_DIRECTION); }
const gchar * common_get_direction_mark (gchar *text) { PangoDirection pango_direction = PANGO_DIRECTION_NEUTRAL; GtkTextDirection gtk_direction; if (text) pango_direction = pango_find_base_dir (text, -1); switch (pango_direction) { case PANGO_DIRECTION_LTR: gtk_direction = GTK_TEXT_DIR_LTR; break; case PANGO_DIRECTION_RTL: gtk_direction = GTK_TEXT_DIR_RTL; break; default: gtk_direction = gtk_widget_get_default_direction (); break; } switch (gtk_direction) { case GTK_TEXT_DIR_RTL: return "\342\200\217"; /* U+200F RIGHT-TO-LEFT MARK */ case GTK_TEXT_DIR_LTR: return "\342\200\216"; /* U+200E LEFT-TO-RIGHT MARK */ default: return ""; } }
static void get_artist_album_templates (const char *artist, const char *album, const char **artist_template, const char **album_template) { PangoDirection tag_dir; PangoDirection template_dir; /* Translators: by Artist */ *artist_template = _("by <i>%s</i>"); /* Translators: from Album */ *album_template = _("from <i>%s</i>"); /* find the direction (left-to-right or right-to-left) of the * track's tags and the localized templates */ if (artist != NULL && artist[0] != '\0') { tag_dir = pango_find_base_dir (artist, -1); template_dir = pango_find_base_dir (*artist_template, -1); } else if (album != NULL && album[0] != '\0') { tag_dir = pango_find_base_dir (album, -1); template_dir = pango_find_base_dir (*album_template, -1); } else { return; } /* if the track's tags and the localized templates have a different * direction, switch to direction-neutral templates in order to improve * display. * text can have a neutral direction, this condition only applies when * both directions are defined and they are conflicting. * https://bugzilla.gnome.org/show_bug.cgi?id=609767 */ if (((tag_dir == PANGO_DIRECTION_LTR) && (template_dir == PANGO_DIRECTION_RTL)) || ((tag_dir == PANGO_DIRECTION_RTL) && (template_dir == PANGO_DIRECTION_LTR))) { /* these strings should not be localized, they must be * locale-neutral and direction-neutral */ *artist_template = "<i>%s</i>"; *album_template = "/ <i>%s</i>"; } }
/* * Returns a string that can be used for the HTML "dir" attribute. * Direction is taken from a string, regardless of any language tags. */ const gchar * common_get_text_direction (const gchar *text) { PangoDirection pango_direction = PANGO_DIRECTION_NEUTRAL; if (text) pango_direction = pango_find_base_dir (text, -1); if (pango_direction == PANGO_DIRECTION_RTL) return ("rtl"); else return ("ltr"); }
static gfloat item_list_title_alignment (gchar *title) { if (!title || strlen(title) == 0) return 0.; /* debug5 (DEBUG_HTML, "title ***%s*** first bytes %02hhx%02hhx%02hhx pango %d", title, title[0], title[1], title[2], pango_find_base_dir (title, -1)); */ int txt_direction = pango_find_base_dir (title, -1); int app_direction = gtk_widget_get_default_direction (); if ((txt_direction == PANGO_DIRECTION_LTR && app_direction == GTK_TEXT_DIR_LTR) || (txt_direction == PANGO_DIRECTION_RTL && app_direction == GTK_TEXT_DIR_RTL)) return 0.; /* same direction, regular ("left") alignment */ else return 1.; }
static VALUE rg_s_find_base_dir(G_GNUC_UNUSED VALUE self, VALUE text) { StringValue(text); return PANGODIRECTION2RVAL(pango_find_base_dir(RSTRING_PTR(text), RSTRING_LEN(text))); }
static void text_to_glyphs (cairo_t *cr, const gchar *text, cairo_glyph_t **glyphs, int *num_glyphs) { PangoAttribute *fallback_attr; PangoAttrList *attr_list; PangoContext *context; PangoDirection base_dir; GList *items; GList *visual_items; FT_Face ft_face; hb_font_t *hb_font; gdouble x = 0, y = 0; gint i; gdouble x_scale, y_scale; *num_glyphs = 0; *glyphs = NULL; base_dir = pango_find_base_dir (text, -1); cairo_scaled_font_t *cr_font = cairo_get_scaled_font (cr); ft_face = cairo_ft_scaled_font_lock_face (cr_font); hb_font = hb_ft_font_create (ft_face, NULL); cairo_surface_t *target = cairo_get_target (cr); cairo_surface_get_device_scale (target, &x_scale, &y_scale); /* We abuse pango itemazation to split text into script and direction * runs, since we use our fonts directly no through pango, we don't * bother changing the default font, but we disable font fallback as * pango will split runs at font change */ context = pango_cairo_create_context (cr); attr_list = pango_attr_list_new (); fallback_attr = pango_attr_fallback_new (FALSE); pango_attr_list_insert (attr_list, fallback_attr); items = pango_itemize_with_base_dir (context, base_dir, text, 0, strlen (text), attr_list, NULL); g_object_unref (context); pango_attr_list_unref (attr_list); /* reorder the items in the visual order */ visual_items = pango_reorder_items (items); while (visual_items) { PangoItem *item; PangoAnalysis analysis; hb_buffer_t *hb_buffer; hb_glyph_info_t *hb_glyphs; hb_glyph_position_t *hb_positions; gint n; item = visual_items->data; analysis = item->analysis; hb_buffer = hb_buffer_create (); hb_buffer_add_utf8 (hb_buffer, text, -1, item->offset, item->length); hb_buffer_set_script (hb_buffer, hb_glib_script_to_script (analysis.script)); hb_buffer_set_language (hb_buffer, hb_language_from_string (pango_language_to_string (analysis.language), -1)); hb_buffer_set_direction (hb_buffer, analysis.level % 2 ? HB_DIRECTION_RTL : HB_DIRECTION_LTR); hb_shape (hb_font, hb_buffer, NULL, 0); n = hb_buffer_get_length (hb_buffer); hb_glyphs = hb_buffer_get_glyph_infos (hb_buffer, NULL); hb_positions = hb_buffer_get_glyph_positions (hb_buffer, NULL); *glyphs = g_renew (cairo_glyph_t, *glyphs, *num_glyphs + n); for (i = 0; i < n; i++) { (*glyphs)[*num_glyphs + i].index = hb_glyphs[i].codepoint; (*glyphs)[*num_glyphs + i].x = x + (hb_positions[i].x_offset / (64. * x_scale)); (*glyphs)[*num_glyphs + i].y = y - (hb_positions[i].y_offset / (64. * y_scale)); x += (hb_positions[i].x_advance / (64. * x_scale)); y -= (hb_positions[i].y_advance / (64. * y_scale)); } *num_glyphs += n; hb_buffer_destroy (hb_buffer); visual_items = visual_items->next; } g_list_free_full (visual_items, (GDestroyNotify) pango_item_free); g_list_free_full (items, (GDestroyNotify) pango_item_free); hb_font_destroy (hb_font); cairo_ft_scaled_font_unlock_face (cr_font); }
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; }