static void set_glyphs (PangoFont *font, const gunichar *wcs, gulong *tags, glong n_glyphs, PangoOTBuffer *buffer, gboolean process_zwj) { gint i; PangoFcFont *fc_font; g_assert (font); fc_font = PANGO_FC_FONT (font); for (i = 0; i < n_glyphs; i++) { guint glyph; if (pango_is_zero_width (wcs[i]) && (!process_zwj || wcs[i] != 0x200D)) glyph = PANGO_GLYPH_EMPTY; else { glyph = pango_fc_font_get_glyph (fc_font, wcs[i]); if (!glyph) glyph = PANGO_GET_UNKNOWN_GLYPH ( wcs[i]); } pango_ot_buffer_add_glyph (buffer, glyph, tags[i], i); } }
static PangoGlyph get_index (PangoFcFont *fc_font, gunichar wc) { PangoGlyph index = pango_fc_font_get_glyph (fc_font, wc); if (!index) index = pango_fc_font_get_unknown_glyph (fc_font, wc); return index; }
static PangoGlyph get_index (PangoFcFont *fc_font, gunichar wc) { PangoGlyph index = pango_fc_font_get_glyph (fc_font, wc); if (!index) index = PANGO_GET_UNKNOWN_GLYPH ( wc); return index; }
PangoGlyph thai_make_glyph_uni (ThaiFontInfo *font_info, gunichar uc) { PangoGlyph result; PangoFcFont *fc_font = (PangoFcFont *)font_info->font; result = pango_fc_font_get_glyph (fc_font, uc); if (result) return result; else return PANGO_GET_UNKNOWN_GLYPH ( uc); }
bool PangoFontInfo::GetSpacingProperties(const string& utf8_char, int* x_bearing, int* x_advance) const { // Convert to equivalent PangoFont structure PangoFont* font = ToPangoFont(); // Find the glyph index in the font for the supplied utf8 character. int total_advance = 0; int min_bearing = 0; // Handle multi-unicode strings by reporting the left-most position of the // x-bearing, and right-most position of the x-advance if the string were to // be rendered. const UNICHAR::const_iterator it_begin = UNICHAR::begin(utf8_char.c_str(), utf8_char.length()); const UNICHAR::const_iterator it_end = UNICHAR::end(utf8_char.c_str(), utf8_char.length()); for (UNICHAR::const_iterator it = it_begin; it != it_end; ++it) { PangoGlyph glyph_index = pango_fc_font_get_glyph( reinterpret_cast<PangoFcFont*>(font), *it); if (!glyph_index) { // Glyph for given unicode character doesn't exist in font. return false; } // Find the ink glyph extents for the glyph PangoRectangle ink_rect, logical_rect; pango_font_get_glyph_extents(font, glyph_index, &ink_rect, &logical_rect); pango_extents_to_pixels(&ink_rect, NULL); pango_extents_to_pixels(&logical_rect, NULL); int bearing = total_advance + PANGO_LBEARING(ink_rect); if (it == it_begin || bearing < min_bearing) { min_bearing = bearing; } total_advance += PANGO_RBEARING(logical_rect); } *x_bearing = min_bearing; *x_advance = total_advance; return true; }
JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_FreetypeGlyphVector_getGlyphs (JNIEnv *env, jobject obj, jintArray codepoints, jintArray glyphs, jlongArray fonts) { PangoFcFont *default_font, *current_font; PangoFontset *pfs; jint *cpvals; jint length; int i; /* Set up default font and fontset */ default_font = getFont(env, obj); current_font = default_font; pfs = getFontSet(env, obj); /* Retrieve string information */ length = (*env)->GetArrayLength (env, codepoints); cpvals = (*env)->GetIntArrayElements (env, codepoints, NULL); jint *glyphArray = (*env)->GetIntArrayElements (env, glyphs, NULL); jlong *fontArray = (*env)->GetLongArrayElements (env, fonts, NULL); /* A design goal of Pango is to be threadsafe, but it's admitted that it is * not actually threadsafe at the moment. Using gdk locking here to be safe, * but I don't know if if actually helps at all... */ gdk_threads_enter(); for( i = 0; i < length; i++ ) { /* Ensure the current font has the requested character; if it doesn't, * try the default font before pulling a new font out of the fontset. * Once chosen, a font will be used until a character not in the font is * encountered. */ if (!pango_fc_font_has_char(current_font, cpvals[i])) { if (pango_fc_font_has_char(default_font, cpvals[i])) { current_font = default_font; g_object_ref(current_font); } else { current_font = (PangoFcFont*)pango_fontset_get_font(pfs, cpvals[i]); } } else { g_object_ref(current_font); } /* Get glyph, and store both glyph and pointer to font */ glyphArray[i] = (int)pango_fc_font_get_glyph(current_font, (gunichar)cpvals[i]); fontArray[i] = PTR_TO_JLONG(current_font); } gdk_threads_leave(); (*env)->ReleaseIntArrayElements (env, glyphs, glyphArray, 0); (*env)->ReleaseIntArrayElements (env, codepoints, cpvals, 0); (*env)->ReleaseLongArrayElements (env, fonts, fontArray, 0); }
static void syriac_engine_shape (PangoEngineShape *engine, PangoFont *font, const char *text, gint length, const PangoAnalysis *analysis, PangoGlyphString *glyphs) { PangoFcFont *fc_font; FT_Face face; PangoOTRulesetDescription desc; const PangoOTRuleset *ruleset; PangoOTBuffer *buffer; gulong *properties = NULL; glong n_chars; gunichar *wcs; const char *p; int cluster = 0; int i; g_return_if_fail (font != NULL); g_return_if_fail (text != NULL); g_return_if_fail (length >= 0); g_return_if_fail (analysis != NULL); fc_font = PANGO_FC_FONT (font); face = pango_fc_font_lock_face (fc_font); if (!face) return; buffer = pango_ot_buffer_new (fc_font); pango_ot_buffer_set_rtl (buffer, analysis->level % 2 != 0); pango_ot_buffer_set_zero_width_marks (buffer, TRUE); wcs = g_utf8_to_ucs4_fast (text, length, &n_chars); properties = g_new0 (gulong, n_chars); syriac_assign_properties (wcs, properties, n_chars); g_free (wcs); p = text; for (i=0; i < n_chars; i++) { gunichar wc; PangoGlyph glyph; wc = g_utf8_get_char (p); if (g_unichar_type (wc) != G_UNICODE_NON_SPACING_MARK) cluster = p - text; if (pango_is_zero_width (wc)) glyph = PANGO_GLYPH_EMPTY; else { gunichar c = wc; if (analysis->level % 2) g_unichar_get_mirror_char (c, &c); glyph = pango_fc_font_get_glyph (fc_font, c); } if (!glyph) glyph = PANGO_GET_UNKNOWN_GLYPH (wc); pango_ot_buffer_add_glyph (buffer, glyph, properties[i], cluster); p = g_utf8_next_char (p); } g_free (properties); desc.script = analysis->script; desc.language = analysis->language; desc.n_static_gsub_features = G_N_ELEMENTS (gsub_features); desc.static_gsub_features = gsub_features; desc.n_static_gpos_features = G_N_ELEMENTS (gpos_features); desc.static_gpos_features = gpos_features; /* TODO populate other_features from analysis->extra_attrs */ desc.n_other_features = 0; desc.other_features = NULL; ruleset = pango_ot_ruleset_get_for_description (pango_ot_info_get (face), &desc); pango_ot_ruleset_substitute (ruleset, buffer); pango_ot_ruleset_position (ruleset, buffer); pango_ot_buffer_output (buffer, glyphs); pango_ot_buffer_destroy (buffer); pango_fc_font_unlock_face (fc_font); }
TGlyphInfo *glyph_cache_get_info(TGlyphCache *cache, gunichar glyph) { TGlyphInfo *gfi; XftFont *xftfont; PangoFont *font; PangoGlyph pglyph; PangoRectangle ink, logical; gint ascent, descent; gint x_offset; gint nominal_width; double scale_y, scale_x; if (!cache->hash) return NULL; gfi = g_hash_table_lookup(cache->hash, GINT_TO_POINTER(glyph)); if (gfi) return gfi; font = pango_fontset_get_font(cache->font_set, glyph); pglyph = pango_fc_font_get_glyph(PANGO_FC_FONT(font), glyph); if (!pglyph) { fprintf (stderr, "Error: Unable to find glyph %d.\n", glyph); if (!pglyph) pglyph = pango_fc_font_get_glyph(PANGO_FC_FONT(font), glyph); if (!pglyph) pglyph = PANGO_GET_UNKNOWN_GLYPH (glyph); if (!pglyph) return NULL; } pango_font_get_glyph_extents(font, pglyph, &ink, &logical); ascent = PANGO_ASCENT(logical); descent = PANGO_DESCENT(logical); xftfont = pango_xft_font_get_font(font); x_offset = 0; nominal_width = cache->width; if (g_unichar_iswide(glyph)) nominal_width *= 2; scale_x = scale_y = 1.0; if (logical.width > nominal_width) { if (logical.width) scale_x = (double)nominal_width / (double)logical.width; else scale_x = 1.0; } if (logical.height != cache->height) { double scale; if (ascent) { scale_y = (double)cache->ascent / (double)ascent; } else { scale_y = 1.0; } if (descent) { scale = (double)cache->descent / (double)descent; if (scale < scale_y) scale_y = scale; } } if (scale_x >= 1.0) { scale_x = 1.0; x_offset += (nominal_width - logical.width) / 2; } if (scale_x < 1.0 || scale_y != 1.0) { FcBool scalable; FcPatternGetBool(xftfont->pattern, FC_SCALABLE, 0, &scalable); if (!scalable) { /* Bah. Need better handling of non-scalable fonts */ if (scale_x < 1.0) scale_x = 1.0; scale_y = 1.0; } else if (scale_x < 1.0 || scale_y != 1.0) { FcPattern *pattern; FcMatrix mat; pattern = FcPatternDuplicate(xftfont->pattern); FcMatrixInit (&mat); FcMatrixScale(&mat, scale_x, scale_y); FcPatternDel (pattern, FC_MATRIX); FcPatternAddMatrix(pattern, FC_MATRIX, &mat); xftfont = XftFontOpenPattern( GDK_DISPLAY_XDISPLAY(cache->display), pattern ); } ascent = ascent * scale_y; } g_object_unref(font); // gfi = calloc(sizeof(TGlyphInfo), 1); gfi = g_slice_new(TGlyphInfo); gfi->font = xftfont; gfi->x_offset = PANGO_PIXELS(x_offset); gfi->y_offset = cache->ascent + (cache->ascent - ascent); gfi->y_offset = PANGO_PIXELS(gfi->y_offset); g_hash_table_insert(cache->hash, GINT_TO_POINTER(glyph), gfi); return gfi; }
PangoGlyph thai_get_glyph_uni (ThaiFontInfo *font_info, gunichar uc) { return pango_fc_font_get_glyph ((PangoFcFont *)font_info->font, uc); }
bool PangoFontInfo::CanRenderString(const char* utf8_word, int len, vector<string>* graphemes) const { if (graphemes) graphemes->clear(); // We check for font coverage of the text first, as otherwise Pango could // (undesirably) fall back to another font that does have the required // coverage. if (!CoversUTF8Text(utf8_word, len)) { return false; } // U+25CC dotted circle character that often (but not always) gets rendered // when there is an illegal grapheme sequence. const char32 kDottedCircleGlyph = 9676; bool bad_glyph = false; PangoFontMap* font_map = pango_cairo_font_map_get_default(); PangoContext* context = pango_context_new(); pango_context_set_font_map(context, font_map); PangoLayout* layout; { // Pango is not relasing the cached layout. DISABLE_HEAP_LEAK_CHECK; layout = pango_layout_new(context); } if (desc_) { pango_layout_set_font_description(layout, desc_); } else { PangoFontDescription *desc = pango_font_description_from_string( DescriptionName().c_str()); pango_layout_set_font_description(layout, desc); pango_font_description_free(desc); } pango_layout_set_text(layout, utf8_word, len); PangoLayoutIter* run_iter = NULL; { // Fontconfig caches some information here that is not freed before exit. DISABLE_HEAP_LEAK_CHECK; run_iter = pango_layout_get_iter(layout); } do { PangoLayoutRun* run = pango_layout_iter_get_run_readonly(run_iter); if (!run) { tlog(2, "Found end of line NULL run marker\n"); continue; } PangoGlyph dotted_circle_glyph; PangoFont* font = run->item->analysis.font; dotted_circle_glyph = pango_fc_font_get_glyph( reinterpret_cast<PangoFcFont*>(font), kDottedCircleGlyph); if (TLOG_IS_ON(2)) { PangoFontDescription* desc = pango_font_describe(font); char* desc_str = pango_font_description_to_string(desc); tlog(2, "Desc of font in run: %s\n", desc_str); g_free(desc_str); pango_font_description_free(desc); } PangoGlyphItemIter cluster_iter; gboolean have_cluster; for (have_cluster = pango_glyph_item_iter_init_start(&cluster_iter, run, utf8_word); have_cluster && !bad_glyph; have_cluster = pango_glyph_item_iter_next_cluster(&cluster_iter)) { const int start_byte_index = cluster_iter.start_index; const int end_byte_index = cluster_iter.end_index; int start_glyph_index = cluster_iter.start_glyph; int end_glyph_index = cluster_iter.end_glyph; string cluster_text = string(utf8_word + start_byte_index, end_byte_index - start_byte_index); if (graphemes) graphemes->push_back(cluster_text); if (IsUTF8Whitespace(cluster_text.c_str())) { tlog(2, "Skipping whitespace\n"); continue; } if (TLOG_IS_ON(2)) { printf("start_byte=%d end_byte=%d start_glyph=%d end_glyph=%d ", start_byte_index, end_byte_index, start_glyph_index, end_glyph_index); } for (int i = start_glyph_index, step = (end_glyph_index > start_glyph_index) ? 1 : -1; !bad_glyph && i != end_glyph_index; i+= step) { const bool unknown_glyph = (cluster_iter.glyph_item->glyphs->glyphs[i].glyph & PANGO_GLYPH_UNKNOWN_FLAG); const bool illegal_glyph = (cluster_iter.glyph_item->glyphs->glyphs[i].glyph == dotted_circle_glyph); bad_glyph = unknown_glyph || illegal_glyph; if (TLOG_IS_ON(2)) { printf("(%d=%d)", cluster_iter.glyph_item->glyphs->glyphs[i].glyph, bad_glyph ? 1 : 0); } } if (TLOG_IS_ON(2)) { printf(" '%s'\n", cluster_text.c_str()); } if (bad_glyph) tlog(1, "Found illegal glyph!\n"); } } while (!bad_glyph && pango_layout_iter_next_run(run_iter)); pango_layout_iter_free(run_iter); g_object_unref(context); g_object_unref(layout); if (bad_glyph && graphemes) graphemes->clear(); return !bad_glyph; }