pango PangoAnalysis
void pango_shape (const gchar *text, gint length, const PangoAnalysis *analysis, PangoGlyphString *glyphs) { pango_shape_full (text, length, text, length, analysis, glyphs); }
void pango_shape_full (const gchar *item_text, gint item_length, const gchar *paragraph_text, gint paragraph_length, const PangoAnalysis *analysis, PangoGlyphString *glyphs) { int i; int last_cluster; glyphs->num_glyphs = 0; if (item_length == -1) item_length = strlen (item_text); if (!paragraph_text) { paragraph_text = item_text; paragraph_length = item_length; } if (paragraph_length == -1) paragraph_length = strlen (paragraph_text); g_return_if_fail (paragraph_text <= item_text); g_return_if_fail (paragraph_text + paragraph_length >= item_text + item_length); if (G_LIKELY (analysis->shape_engine && analysis->font)) { _pango_engine_shape_shape (analysis->shape_engine, analysis->font, item_text, item_length, paragraph_text, paragraph_length, analysis, glyphs); if (G_UNLIKELY (glyphs->num_glyphs == 0)) { /* If a font has been correctly chosen, but no glyphs are output, * there's probably something wrong with the shaper, or the font. * * Trying to be informative, we print out the font description, * shaper name, and the text, but to not flood the terminal with * zillions of the message, we set a flag to only err once per * font/engine pair. * * To do the flag fast, we use the engine qname to qflag the font, * but also the font description to flag the engine. This is * supposed to be fast to check, but also avoid writing out * duplicate warnings when a new PangoFont is created. */ GType engine_type = G_OBJECT_TYPE (analysis->shape_engine); GQuark warned_quark = g_type_qname (engine_type); if (!g_object_get_qdata (G_OBJECT (analysis->font), warned_quark)) { PangoFontDescription *desc; char *font_name; const char *engine_name; desc = pango_font_describe (analysis->font); font_name = pango_font_description_to_string (desc); pango_font_description_free (desc); if (!g_object_get_data (G_OBJECT (analysis->shape_engine), font_name)) { engine_name = g_type_name (engine_type); if (!engine_name) engine_name = "(unknown)"; g_warning ("shaping failure, expect ugly output. shape-engine='%s', font='%s', text='%.*s'", engine_name, font_name, item_length, item_text); g_object_set_data_full (G_OBJECT (analysis->shape_engine), font_name, GINT_TO_POINTER (1), NULL); } g_free (font_name); g_object_set_qdata_full (G_OBJECT (analysis->font), warned_quark, GINT_TO_POINTER (1), NULL); } } } else glyphs->num_glyphs = 0; if (G_UNLIKELY (!glyphs->num_glyphs)) { PangoEngineShape *fallback_engine = _pango_get_fallback_shaper (); _pango_engine_shape_shape (fallback_engine, analysis->font, item_text, item_length, paragraph_text, paragraph_length, analysis, glyphs); if (G_UNLIKELY (!glyphs->num_glyphs)) return; } /* make sure last_cluster is invalid */ last_cluster = glyphs->log_clusters[0] - 1; for (i = 0; i < glyphs->num_glyphs; i++) { /* Set glyphs[i].attr.is_cluster_start based on log_clusters[] */ if (glyphs->log_clusters[i] != last_cluster) { glyphs->glyphs[i].attr.is_cluster_start = TRUE; last_cluster = glyphs->log_clusters[i]; } else glyphs->glyphs[i].attr.is_cluster_start = FALSE; /* Shift glyph if width is negative, and negate width. * This is useful for rotated font matrices and shouldn't * harm in normal cases. */ if (glyphs->glyphs[i].geometry.width < 0) { glyphs->glyphs[i].geometry.width = -glyphs->glyphs[i].geometry.width; glyphs->glyphs[i].geometry.x_offset += glyphs->glyphs[i].geometry.width; } } /* Make sure glyphstring direction conforms to analysis->level */ if (G_UNLIKELY ((analysis->level & 1) && glyphs->log_clusters[0] < glyphs->log_clusters[glyphs->num_glyphs - 1])) { /* Warn once per shaper */ static GQuark warned_quark = 0; /* MT-safe */ if (!warned_quark) warned_quark = g_quark_from_static_string ("pango-shape-warned"); if (analysis->shape_engine && !g_object_get_qdata (G_OBJECT (analysis->shape_engine), warned_quark)) { GType engine_type = G_OBJECT_TYPE (analysis->shape_engine); const char *engine_name = g_type_name (engine_type); if (!engine_name) engine_name = "(unknown)"; g_warning ("Expected RTL run but shape-engine='%s' returned LTR. Fixing.", engine_name); g_object_set_qdata_full (G_OBJECT (analysis->shape_engine), warned_quark, GINT_TO_POINTER (1), NULL); } /* *Fix* it so we don't crash later */ pango_glyph_string_reverse_range (glyphs, 0, glyphs->num_glyphs); } }
Example
int main (int argc, char **argv) { PangoFontMap * fontmap = pango_win32_font_map_for_display(); PangoContext * context; PangoCoverage * coverage = NULL; PangoFont * font = NULL; PangoFontFamily ** families = NULL; PangoFontFace ** faces = NULL; int nb, i; gchar* family_name = NULL; PangoLanguage *lang = pango_language_from_string (g_win32_getlocale ()); HDC hdc = NULL; int line = 0; GTimeVal tv0, tv1; int my_font_size = 12; printf ("# Pango Font Test\n" "# Language: %s\n" "#\n", pango_language_to_string (lang));
/* this wasn't necessary with previous version * * force initialization of built-in engines, otherwise * the rendering get's really fast - too fast to work :-( */ context = pango_win32_get_context (); if (argc == 1) /* No arguments given */ { char *std_fonts[] = {"Sans 12", "Serif 12", "Monospace 12"}; /* try to load some fonts often hardcoded */ for (i = 0; i < G_N_ELEMENTS (std_fonts); i++) { PangoFontDescription *desc = pango_font_description_from_string(std_fonts[i]); /* spits warnings if font cannot be loaded */ font = pango_font_map_load_font (fontmap, context, desc); g_object_unref (font); } } else { PangoFontDescription *desc = NULL; GString *s; s = g_string_new (argv[1]); for (i = 2; i < argc; i++) { s = g_string_append_c (s, ' '); s = g_string_append (s, argv[i]); if (0 != atoi (argv[i])) my_font_size = atoi (argv[i]); } desc = pango_font_description_from_string(s->str); family_name = g_strdup (pango_font_description_get_family (desc)); font = pango_font_map_load_font (fontmap, context, desc); coverage = pango_font_get_coverage (font, lang); /* ... */ pango_coverage_unref (coverage); pango_font_description_free (desc); g_object_unref (font); }
pango_font_map_list_families (fontmap, &families, &nb); if (!family_name) { qsort (families, nb, sizeof (PangoFontFamily*), compare_font_family); } else { /* Get on the family faces. No simple way ? */ for (i = 0; i < nb; i++) { if (0 == g_ascii_strcasecmp (pango_font_family_get_name (families[i]), family_name)) { pango_font_family_list_faces (families[i], &faces, &nb); /* now nb is the number of faces */ break; } } g_free (families); families = NULL; g_free (family_name); family_name = NULL; } hdc = pre_render(my_font_size * 64, 3 * my_font_size * nb / 2); for (i = 0; i < nb; i++) {
PangoFontDescription *desc; const char *f_name; PangoWeight weight; PangoStyle style; if (families) { desc = pango_font_description_new (); f_name = pango_font_family_get_name (families[i]); pango_font_description_set_family (desc, f_name); } else { desc = pango_font_face_describe (faces[i]); /* this is _not_ the family name from above */ f_name = pango_font_description_get_family (desc); } weight = pango_font_description_get_weight (desc); style = pango_font_description_get_style (desc); g_print ("%s; Style: %d; Weight: %d\n", f_name, style, weight); /* give it an arbitray size to load it */ pango_font_description_set_size (desc, my_font_size * PANGO_SCALE); g_get_current_time (&tv0); font = pango_font_map_load_font (fontmap, context, desc); g_get_current_time (&tv1); g_print ("\tpango_font_map_load_font took %.3f sec\n", calc_duration (&tv1, &tv0)); if (font) { PangoItem *item; PangoGlyphString * glyphs; char s[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "1234567890 -+*/!\xc2\xa7$%&()[]{}<>|#=?@"; g_get_current_time (&tv0); coverage = pango_font_get_coverage (font, lang); g_get_current_time (&tv1); g_print ("\tpango_font_get_coverage took %.3f sec\n", calc_duration (&tv1, &tv0)); /* ... */ pango_context_set_language (context, lang); pango_context_set_base_dir (context, PANGO_DIRECTION_LTR); pango_context_set_font_description (context, desc); glyphs = pango_glyph_string_new (); item = pango_item_new (); item->analysis.shape_engine = pango_font_find_shaper (font, lang, s[0]); item->analysis.font = g_object_ref (font); pango_shape ( s, sizeof(s), &(item->analysis), glyphs); <====================== if (hdc) { /* the positioning isn't correct */ char* name = g_strdup_printf ("%s (%s%s)", f_name, weight == PANGO_WEIGHT_NORMAL ? "n" : (weight == PANGO_WEIGHT_HEAVY ? "h" : (weight > PANGO_WEIGHT_NORMAL ? "b" : "l")), style == PANGO_STYLE_OBLIQUE ? "o" : (style == PANGO_STYLE_ITALIC ? "i" : "n")); TextOut (hdc, 0, line, name, strlen(name)); g_get_current_time (&tv0); pango_win32_render (hdc, font, glyphs, 200, line); g_get_current_time (&tv1); g_print ("\tpango_win32_render took %.3f sec\n", calc_duration (&tv1, &tv0)); line += (3 * my_font_size / 2); g_free(name); } /* free glyphs, ... */ pango_glyph_string_free (glyphs); pango_item_free (item); pango_coverage_unref (coverage); g_object_unref (font); } pango_font_description_free (desc); } if (hdc) post_render (hdc, "pango-fonts.bmp"); g_free (families); g_free (faces); return 0; }