static void render_tone (PangoFont *font, gunichar tone, PangoGlyphString *glyphs, int *n_glyphs, int cluster_offset) { int index; index = find_char (font, tone); pango_glyph_string_set_size (glyphs, *n_glyphs + 1); if (index) { set_glyph_tone (font, glyphs, *n_glyphs, cluster_offset, index); } else { /* fall back : HTONE1(0x302e) => middle-dot, HTONE2(0x302f) => colon */ index = find_char (font, tone == HTONE1 ? 0x00b7 : 0x003a); if (index) { set_glyph_tone (font, glyphs, *n_glyphs, cluster_offset, index); } else set_glyph (font, glyphs, *n_glyphs, cluster_offset, get_unknown_glyph (font, tone)); } (*n_glyphs)++; }
/* This is a fallback for when we get a tone mark not preceded * by a syllable. */ static void render_isolated_tone (PangoFont *font, gunichar tone, PangoGlyphString *glyphs, int *n_glyphs, int cluster_offset) { #if 0 /* FIXME: what kind of hack is it? it draws dummy glyphs. */ /* Find a base character to render the mark on */ int index = find_char (font, 0x25cc); /* DOTTED CIRCLE */ if (!index) index = find_char (font, 0x25cb); /* WHITE CIRCLE, in KSC-5601 */ if (!index) index = find_char (font, ' '); /* Space */ if (!index) /* Unknown glyph box with 0000 in it */ index = find_char (font, PANGO_GET_UNKNOWN_GLYPH (0)); /* Add the base character */ pango_glyph_string_set_size (glyphs, *n_glyphs + 1); set_glyph (font, glyphs, *n_glyphs, cluster_offset, index); (*n_glyphs)++; #endif /* And the tone mark */ render_tone(font, tone, glyphs, n_glyphs, cluster_offset); }
static void render_basic (PangoFont *font, gunichar wc, PangoGlyphString *glyphs, int *n_glyphs, int cluster_offset) { int index; if (wc == 0xa0) /* non-break-space */ wc = 0x20; pango_glyph_string_set_size (glyphs, *n_glyphs + 1); if (pango_is_zero_width (wc)) set_glyph (font, glyphs, *n_glyphs, cluster_offset, PANGO_GLYPH_EMPTY); else { index = find_char (font, wc); if (index) set_glyph (font, glyphs, *n_glyphs, cluster_offset, index); else set_glyph (font, glyphs, *n_glyphs, cluster_offset, get_unknown_glyph (font, wc)); } (*n_glyphs)++; }
/* This is a fallback for when we get a tone mark not preceded * by a syllable. */ static void render_isolated_tone (PangoFont *font, gunichar tone, PangoGlyphString *glyphs, int *n_glyphs, int cluster_offset) { /* Find a base character to render the mark on */ int index = find_char (font, 0x25cc); /* DOTTED CIRCLE */ if (!index) index = find_char (font, 0x25cb); /* WHITE CIRCLE, in KSC-5601 */ if (!index) index = find_char (font, ' '); /* Space */ if (!index) /* Unknown glyph box with 0000 in it */ index = find_char (font, get_unknown_glyph (font, 0)); /* Add the base character */ pango_glyph_string_set_size (glyphs, *n_glyphs + 1); set_glyph (font, glyphs, *n_glyphs, cluster_offset, index); (*n_glyphs)++; /* And the tone mrak */ render_tone(font, tone, glyphs, n_glyphs, cluster_offset); }
static VALUE rglyph_set_size(VALUE self, VALUE len) { pango_glyph_string_set_size(_SELF(self), NUM2INT(len)); return self; }
/* analysis->shape_engine has the PangoEngine... */ static void indic_engine_shape (PangoEngineShape *engine, PangoFont *font, const char *text, gint length, const PangoAnalysis *analysis, PangoGlyphString *glyphs) { PangoFcFont *fc_font; FT_Face face; PangoOTRuleset *gsub_ruleset, *gpos_ruleset; PangoOTBuffer *buffer; glong i, n_chars, n_glyphs; gulong *tags = NULL; gunichar *wc_in = NULL, *wc_out = NULL; glong *utf8_offsets = NULL; glong *indices = NULL; IndicEngineFc *indic_shape_engine = NULL; const PangoIndicInfo *indic_info = NULL; MPreFixups *mprefixups; 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; indic_shape_engine = (IndicEngineFc *) engine; indic_info = indic_shape_engine->indicInfo; wc_in = expand_text (text, length, &utf8_offsets, &n_chars); n_glyphs = indic_ot_reorder (wc_in, utf8_offsets, n_chars, indic_info->classTable, NULL, NULL, NULL, NULL); wc_out = g_new (gunichar, n_glyphs); indices = g_new (glong, n_glyphs); tags = g_new (gulong, n_glyphs); n_glyphs = indic_ot_reorder (wc_in, utf8_offsets, n_chars, indic_info->classTable, wc_out, indices, tags, &mprefixups); pango_glyph_string_set_size (glyphs, n_glyphs); buffer = pango_ot_buffer_new (fc_font); set_glyphs(font, wc_out, tags, n_glyphs, buffer, (indic_info->classTable->scriptFlags & SF_PROCESS_ZWJ) != 0); /* do gsub processing */ gsub_ruleset = get_gsub_ruleset (face, indic_info); if (gsub_ruleset != NULL) pango_ot_ruleset_substitute (gsub_ruleset, buffer); /* Fix pre-modifiers for some scripts before base consonant */ if (mprefixups) { indic_mprefixups_apply (mprefixups, buffer); indic_mprefixups_free (mprefixups); } /* do gpos processing */ gpos_ruleset = get_gpos_ruleset (face, indic_info); if (gpos_ruleset != NULL) pango_ot_ruleset_position (gpos_ruleset, buffer); pango_ot_buffer_output (buffer, glyphs); /* Get the right log_clusters values */ for (i = 0; i < glyphs->num_glyphs; i += 1) glyphs->log_clusters[i] = indices[glyphs->log_clusters[i]]; pango_fc_font_unlock_face (fc_font); pango_ot_buffer_destroy (buffer); g_free (tags); g_free (indices); g_free (wc_out); g_free (wc_in); g_free (utf8_offsets); }
static void render_syllable (PangoFont *font, gunichar *text, int length, PangoGlyphString *glyphs, int *n_glyphs, int cluster_offset) { int n_prev_glyphs = *n_glyphs; int index; gunichar wc, tone; int i, j, composed; if (IS_M (text[length - 1])) { tone = text[length - 1]; length--; } else tone = 0; if (length >= 3 && IS_L_S(text[0]) && IS_V_S(text[1]) && IS_T_S(text[2])) composed = 3; else if (length >= 2 && IS_L_S(text[0]) && IS_V_S(text[1])) composed = 2; else composed = 0; if (composed) { if (composed == 3) wc = S_FROM_LVT(text[0], text[1], text[2]); else wc = S_FROM_LV(text[0], text[1]); index = find_char (font, wc); pango_glyph_string_set_size (glyphs, *n_glyphs + 1); if (!index) set_glyph (font, glyphs, *n_glyphs, cluster_offset, get_unknown_glyph (font, wc)); else set_glyph (font, glyphs, *n_glyphs, cluster_offset, index); (*n_glyphs)++; text += composed; length -= composed; } /* Render the remaining text as uncomposed forms as a fallback. */ for (i = 0; i < length; i++) { int jindex; int oldlen; if (text[i] == LFILL || text[i] == VFILL) continue; index = find_char (font, text[i]); if (index) { pango_glyph_string_set_size (glyphs, *n_glyphs + 1); set_glyph (font, glyphs, *n_glyphs, cluster_offset, index); (*n_glyphs)++; continue; } /* This font has no glyphs on the Hangul Jamo area! Find a fallback from the Hangul Compatibility Jamo area. */ jindex = text[i] - LBASE; oldlen = *n_glyphs; for (j = 0; j < 3 && (__jamo_to_ksc5601[jindex][j] != 0); j++) { wc = __jamo_to_ksc5601[jindex][j] - KSC_JAMOBASE + UNI_JAMOBASE; index = (wc >= 0x3131) ? find_char (font, wc) : 0; pango_glyph_string_set_size (glyphs, *n_glyphs + 1); if (!index) { *n_glyphs = oldlen; pango_glyph_string_set_size (glyphs, *n_glyphs + 1); set_glyph (font, glyphs, *n_glyphs, cluster_offset, get_unknown_glyph (font, text[i])); (*n_glyphs)++; break; } else set_glyph (font, glyphs, *n_glyphs, cluster_offset, index); (*n_glyphs)++; } } if (n_prev_glyphs == *n_glyphs) { index = find_char (font, 0x3164); pango_glyph_string_set_size (glyphs, *n_glyphs + 1); if (!index) set_glyph (font, glyphs, *n_glyphs, cluster_offset, get_unknown_glyph (font, index)); else set_glyph (font, glyphs, *n_glyphs, cluster_offset, index); glyphs->log_clusters[*n_glyphs] = cluster_offset; (*n_glyphs)++; } if (tone) render_tone(font, tone, glyphs, n_glyphs, cluster_offset); }
static gboolean itemize_shape_and_place (PangoFont *font, HDC hdc, wchar_t *wtext, int wlen, const PangoAnalysis *analysis, PangoGlyphString *glyphs) { int i; int item, nitems, item_step; int itemlen, glyphix, nglyphs; SCRIPT_CONTROL control; SCRIPT_STATE state; SCRIPT_ITEM items[100]; double scale = pango_win32_font_get_metrics_factor (font); HFONT hfont = _pango_win32_font_get_hfont (font); static GHashTable *script_cache_hash = NULL; if (!script_cache_hash) script_cache_hash = g_hash_table_new (g_int64_hash, g_int64_equal); memset (&control, 0, sizeof (control)); memset (&state, 0, sizeof (state)); control.uDefaultLanguage = make_langid (analysis->language); state.uBidiLevel = analysis->level; #ifdef BASIC_WIN32_DEBUGGING if (pango_win32_debug) g_print (G_STRLOC ": ScriptItemize: uDefaultLanguage:%04x uBidiLevel:%d\n", control.uDefaultLanguage, state.uBidiLevel); #endif if (ScriptItemize (wtext, wlen, G_N_ELEMENTS (items), &control, NULL, items, &nitems)) { #ifdef BASIC_WIN32_DEBUGGING if (pango_win32_debug) g_print ("ScriptItemize failed\n"); #endif return FALSE; } #ifdef BASIC_WIN32_DEBUGGING if (pango_win32_debug) g_print ("%d items:\n", nitems); #endif if (analysis->level % 2) { item = nitems - 1; item_step = -1; } else { item = 0; item_step = 1; } for (i = 0; i < nitems; i++, item += item_step) { WORD iglyphs[1000]; WORD log_clusters[1000]; SCRIPT_VISATTR visattrs[1000]; int advances[1000]; GOFFSET offsets[1000]; ABC abc; gint32 script = items[item].a.eScript; int ng; int char_offset; SCRIPT_CACHE *script_cache; gint64 font_and_script_key; memset (advances, 0, sizeof (advances)); memset (offsets, 0, sizeof (offsets)); memset (&abc, 0, sizeof (abc)); /* Note that itemlen is number of wchar_t's i.e. surrogate pairs * count as two! */ itemlen = items[item+1].iCharPos - items[item].iCharPos; char_offset = items[item].iCharPos; #ifdef BASIC_WIN32_DEBUGGING if (pango_win32_debug) g_print (" Item %d: iCharPos=%d eScript=%d (%s) %s%s%s%s%s%s%s wchar_t %d--%d (%d)\n", item, items[item].iCharPos, script, lang_name (scripts[script]->langid), scripts[script]->fComplex ? "complex" : "simple", items[item].a.fRTL ? " fRTL" : "", items[item].a.fLayoutRTL ? " fLayoutRTL" : "", items[item].a.fLinkBefore ? " fLinkBefore" : "", items[item].a.fLinkAfter ? " fLinkAfter" : "", items[item].a.fLogicalOrder ? " fLogicalOrder" : "", items[item].a.fNoGlyphIndex ? " fNoGlyphIndex" : "", items[item].iCharPos, items[item+1].iCharPos-1, itemlen); #endif /* Create a hash key based on hfont and script engine */ font_and_script_key = (((gint64) ((gint32) hfont)) << 32) | script; /* Get the script cache for this hfont and script */ script_cache = g_hash_table_lookup (script_cache_hash, &font_and_script_key); if (!script_cache) { gint64 *key_n; SCRIPT_CACHE *new_script_cache; key_n = g_new (gint64, 1); *key_n = font_and_script_key; new_script_cache = g_new0 (SCRIPT_CACHE, 1); script_cache = new_script_cache; /* Insert the new value */ g_hash_table_insert (script_cache_hash, key_n, new_script_cache); #ifdef BASIC_WIN32_DEBUGGING if (pango_win32_debug) g_print (" New SCRIPT_CACHE for font %p and script %d\n", hfont, script); #endif } items[item].a.fRTL = analysis->level % 2; if (ScriptShape (hdc, script_cache, wtext + items[item].iCharPos, itemlen, G_N_ELEMENTS (iglyphs), &items[item].a, iglyphs, log_clusters, visattrs, &nglyphs)) { #ifdef BASIC_WIN32_DEBUGGING if (pango_win32_debug) g_print ("pango-basic-win32: ScriptShape failed\n"); #endif return FALSE; } #ifdef BASIC_WIN32_DEBUGGING dump_glyphs_and_log_clusters (items[item].a.fRTL, itemlen, items[item].iCharPos, log_clusters, iglyphs, nglyphs); #endif ng = glyphs->num_glyphs; pango_glyph_string_set_size (glyphs, ng + nglyphs); set_up_pango_log_clusters (wtext + items[item].iCharPos, items[item].a.fRTL, itemlen, log_clusters, nglyphs, glyphs->log_clusters + ng, char_offset); if (ScriptPlace (hdc, script_cache, iglyphs, nglyphs, visattrs, &items[item].a, advances, offsets, &abc)) { #ifdef BASIC_WIN32_DEBUGGING if (pango_win32_debug) g_print ("pango-basic-win32: ScriptPlace failed\n"); #endif return FALSE; } for (glyphix = 0; glyphix < nglyphs; glyphix++) { if (iglyphs[glyphix] != 0) { glyphs->glyphs[ng+glyphix].glyph = iglyphs[glyphix]; glyphs->glyphs[ng+glyphix].geometry.width = floor (0.5 + scale * advances[glyphix]); glyphs->glyphs[ng+glyphix].geometry.x_offset = floor (0.5 + scale * offsets[glyphix].du); glyphs->glyphs[ng+glyphix].geometry.y_offset = floor (0.5 + scale * offsets[glyphix].dv); } else { PangoRectangle logical_rect; /* Should pass actual char that was not found to * PANGO_GET_UNKNOWN_GLYPH(), but a bit hard to * find out that at this point, so cheat and use 0. */ PangoGlyph unk = PANGO_GET_UNKNOWN_GLYPH (0); glyphs->glyphs[ng+glyphix].glyph = unk; pango_font_get_glyph_extents (font, unk, NULL, &logical_rect); glyphs->glyphs[ng+glyphix].geometry.width = logical_rect.width; glyphs->glyphs[ng+glyphix].geometry.x_offset = 0; glyphs->glyphs[ng+glyphix].geometry.y_offset = 0; } } } #ifdef BASIC_WIN32_DEBUGGING if (pango_win32_debug) { g_print (" Pango log_clusters (level:%d), char index:", analysis->level); for (glyphix = 0; glyphix < glyphs->num_glyphs; glyphix++) g_print ("%d ", glyphs->log_clusters[glyphix]); g_print ("\n"); } #endif return TRUE; }
static void render_syllable (PangoFont *font, const char *str, int length, PangoGlyphString *glyphs, int *n_glyphs, int cluster_offset) { int n_prev_glyphs = *n_glyphs; int index; gunichar wc = 0, tone = 0, text[4]; int i, j, composed = 0; const char *p; /* Normalize it only when the entire sequence is equivalent to a * precomposed syllable. It's usually better than prefix * normalization both for poor-featured fonts and for smart fonts. * I have seen no smart font which can render S+T as a syllable * form. */ if (length == 3 || length == 4) { p = str; text[0] = g_utf8_get_char(p); p = g_utf8_next_char(p); text[1] = g_utf8_get_char(p); p = g_utf8_next_char(p); text[2] = g_utf8_get_char(p); if (length == 4 && !IS_M(g_utf8_get_char(g_utf8_next_char(p)))) goto lvt_out; /* draw the tone mark later */ if (IS_L_S(text[0]) && IS_V_S(text[1]) && IS_T_S(text[2])) { composed = 3; wc = S_FROM_LVT(text[0], text[1], text[2]); str = g_utf8_next_char(p); goto normalize_out; } } lvt_out: if (length == 2 || length == 3) { p = str; text[0] = g_utf8_get_char(p); p = g_utf8_next_char(p); text[1] = g_utf8_get_char(p); if (length == 3 && !IS_M(g_utf8_get_char(g_utf8_next_char(p)))) goto lv_out; /* draw the tone mark later */ if (IS_L_S(text[0]) && IS_V_S(text[1])) { composed = 2; wc = S_FROM_LV(text[0], text[1]); str = g_utf8_next_char(p); } else if (IS_S(text[0] && !S_HAS_T(text[0]) && IS_T_S(text[1]))) { composed = 2; wc = text[0] + (text[1] - TBASE); str = g_utf8_next_char(p); goto normalize_out; } } lv_out: normalize_out: if (composed) { index = find_char (font, wc); pango_glyph_string_set_size (glyphs, *n_glyphs + 1); if (!index) set_glyph (font, glyphs, *n_glyphs, cluster_offset, PANGO_GET_UNKNOWN_GLYPH (wc)); else set_glyph (font, glyphs, *n_glyphs, cluster_offset, index); (*n_glyphs)++; length -= composed; } /* Render the remaining text as uncomposed forms as a fallback. */ for (i = 0; i < length; i++, str = g_utf8_next_char(str)) { int jindex; int oldlen; wc = g_utf8_get_char(str); if (wc == LFILL || wc == VFILL) continue; if (IS_M(wc)) { tone = wc; break; } if (IS_S(wc)) { oldlen = *n_glyphs; text[0] = L_FROM_S(wc); text[1] = V_FROM_S(wc); if (S_HAS_T(wc)) { text[2] = T_FROM_S(wc); composed = 3; } else composed = 2; for (j = 0; j < composed; j++) { index = find_char (font, text[j]); if (index) { pango_glyph_string_set_size (glyphs, *n_glyphs + 1); set_glyph (font, glyphs, *n_glyphs, cluster_offset, index); (*n_glyphs)++; } else goto decompose_cancel; } continue; decompose_cancel: /* The font doesn't have jamos. Cancel it. */ *n_glyphs = oldlen; pango_glyph_string_set_size (glyphs, *n_glyphs); } index = find_char (font, wc); if (index) { pango_glyph_string_set_size (glyphs, *n_glyphs + 1); set_glyph (font, glyphs, *n_glyphs, cluster_offset, index); (*n_glyphs)++; continue; } else if (IS_S(wc)) { pango_glyph_string_set_size (glyphs, *n_glyphs + 1); set_glyph (font, glyphs, *n_glyphs, cluster_offset, PANGO_GET_UNKNOWN_GLYPH (wc)); (*n_glyphs)++; continue; } /* This font has no glyphs on the Hangul Jamo area! Find a fallback from the Hangul Compatibility Jamo area. */ jindex = wc - LBASE; oldlen = *n_glyphs; for (j = 0; j < 3 && (__jamo_to_ksc5601[jindex][j] != 0); j++) { wc = __jamo_to_ksc5601[jindex][j] - KSC_JAMOBASE + UNI_JAMOBASE; index = (wc >= 0x3131) ? find_char (font, wc) : 0; pango_glyph_string_set_size (glyphs, *n_glyphs + 1); if (!index) { *n_glyphs = oldlen; pango_glyph_string_set_size (glyphs, *n_glyphs + 1); set_glyph (font, glyphs, *n_glyphs, cluster_offset, PANGO_GET_UNKNOWN_GLYPH (text[i])); (*n_glyphs)++; break; } else set_glyph (font, glyphs, *n_glyphs, cluster_offset, index); (*n_glyphs)++; } } if (n_prev_glyphs == *n_glyphs) { index = find_char (font, 0x3164); /* U+3164 HANGUL FILLER */ pango_glyph_string_set_size (glyphs, *n_glyphs + 1); if (!index) set_glyph (font, glyphs, *n_glyphs, cluster_offset, PANGO_GET_UNKNOWN_GLYPH (index)); else set_glyph (font, glyphs, *n_glyphs, cluster_offset, index); glyphs->log_clusters[*n_glyphs] = cluster_offset; (*n_glyphs)++; } if (tone) render_tone(font, tone, glyphs, n_glyphs, cluster_offset); }
/** * pango_ot_ruleset_shape: * @ruleset: a #PangoOTRuleset. * @glyphs: a pointer to a #PangoGlyphString. * @properties: an array containing one #gulong bitfield for each glyph, * which gives the glyph's properties: If a certain bit is set for a glyph, * the feature which has the same bit set in its property value is applied. * * Shapes a string of glyphs with the given properties according to @ruleset. **/ void pango_ot_ruleset_shape (PangoOTRuleset *ruleset, PangoGlyphString *glyphs, gulong *properties) { int i; int last_cluster; int result; TTO_GSUB gsub = NULL; TTO_GPOS gpos = NULL; TTO_GSUB_String *in_string = NULL; TTO_GSUB_String *out_string = NULL; TTO_GSUB_String *result_string = NULL; gboolean need_gsub = FALSE; gboolean need_gpos = FALSE; g_return_if_fail (PANGO_OT_IS_RULESET (ruleset)); for (i = 0; i < ruleset->rules->len; i++) { PangoOTRule *rule = &g_array_index (ruleset->rules, PangoOTRule, i); if (rule->table_type == PANGO_OT_TABLE_GSUB) need_gsub = TRUE; else need_gpos = TRUE; } if (need_gsub) { gsub = pango_ot_info_get_gsub (ruleset->info); if (gsub) TT_GSUB_Clear_Features (gsub); } if (need_gpos) { gpos = pango_ot_info_get_gpos (ruleset->info); if (gpos) TT_GPOS_Clear_Features (gpos); } for (i = 0; i < ruleset->rules->len; i++) { PangoOTRule *rule = &g_array_index (ruleset->rules, PangoOTRule, i); if (rule->table_type == PANGO_OT_TABLE_GSUB) { if (gsub) TT_GSUB_Add_Feature (gsub, rule->feature_index, rule->property_bit); } else { if (gpos) TT_GPOS_Add_Feature (gpos, rule->feature_index, rule->property_bit); } } if (!gsub && !gpos) return; result = TT_GSUB_String_New (ruleset->info->face->memory, &in_string); g_assert (result == FT_Err_Ok); result = TT_GSUB_String_Set_Length (in_string, glyphs->num_glyphs); g_assert (result == FT_Err_Ok); for (i = 0; i < glyphs->num_glyphs; i++) { in_string->string[i] = glyphs->glyphs[i].glyph; in_string->properties[i] = properties[i]; in_string->logClusters[i] = glyphs->log_clusters[i]; } in_string->max_ligID = i; if (gsub) { result = TT_GSUB_String_New (ruleset->info->face->memory, &out_string); g_assert (result == FT_Err_Ok); result_string = out_string; TT_GSUB_Apply_String (gsub, in_string, out_string); } else result_string = in_string; if (gpos) { TTO_GPOS_Data *outgpos = NULL; if (!TT_GPOS_Apply_String (ruleset->info->face, gpos, 0, result_string, &outgpos, FALSE /* enable device-dependant values */, FALSE /* Even though this might be r2l text, RTL is handled elsewhere */)) { for (i = 0; i < result_string->length; i++) { FT_Pos x_pos = outgpos[i].x_pos; FT_Pos y_pos = outgpos[i].y_pos; int back = i; int j; while (outgpos[back].back != 0) { back -= outgpos[back].back; x_pos += outgpos[back].x_pos; y_pos += outgpos[back].y_pos; } for (j = back; j < i; j++) glyphs->glyphs[i].geometry.x_offset -= glyphs->glyphs[j].geometry.width; glyphs->glyphs[i].geometry.x_offset += PANGO_UNITS_26_6(x_pos); glyphs->glyphs[i].geometry.y_offset += PANGO_UNITS_26_6(y_pos); if (outgpos[i].new_advance) glyphs->glyphs[i].geometry.width = PANGO_UNITS_26_6(outgpos[i].x_advance); else glyphs->glyphs[i].geometry.width += PANGO_UNITS_26_6(outgpos[i].x_advance); } FT_Free(gpos->memory, (void *)outgpos); } } pango_glyph_string_set_size (glyphs, result_string->length); last_cluster = -1; for (i = 0; i < result_string->length; i++) { glyphs->glyphs[i].glyph = result_string->string[i]; glyphs->log_clusters[i] = result_string->logClusters[i]; if (glyphs->log_clusters[i] != last_cluster) glyphs->glyphs[i].attr.is_cluster_start = 1; else glyphs->glyphs[i].attr.is_cluster_start = 0; last_cluster = glyphs->log_clusters[i]; } if (in_string) TT_GSUB_String_Done (in_string); if (out_string) TT_GSUB_String_Done (out_string); }
/** * pango_ot_buffer_output * @buffer: a #PangoOTBuffer * @glyphs: a #PangoGlyphString * * Exports the glyphs in a #PangoOTBuffer into a #PangoGlyphString. This is * typically used after the OpenType layout processing is over, to convert the * resulting glyphs into a generic Pango glyph string. * * Since: 1.4 **/ void pango_ot_buffer_output (PangoOTBuffer *buffer, PangoGlyphString *glyphs) { FT_Face face; PangoOTInfo *info; HB_GDEF gdef = NULL; unsigned int i; int last_cluster; face = pango_fc_font_lock_face (buffer->font); g_assert (face); /* Copy glyphs into output glyph string */ pango_glyph_string_set_size (glyphs, buffer->buffer->in_length); last_cluster = -1; for (i = 0; i < buffer->buffer->in_length; i++) { HB_GlyphItem item = &buffer->buffer->in_string[i]; glyphs->glyphs[i].glyph = item->gindex; glyphs->log_clusters[i] = item->cluster; if (glyphs->log_clusters[i] != last_cluster) glyphs->glyphs[i].attr.is_cluster_start = 1; else glyphs->glyphs[i].attr.is_cluster_start = 0; last_cluster = glyphs->log_clusters[i]; } info = pango_ot_info_get (face); gdef = pango_ot_info_get_gdef (info); /* Apply default positioning */ for (i = 0; i < (unsigned int)glyphs->num_glyphs; i++) { if (glyphs->glyphs[i].glyph) { PangoRectangle logical_rect; FT_UShort property; if (buffer->zero_width_marks && gdef && HB_GDEF_Get_Glyph_Property (gdef, glyphs->glyphs[i].glyph, &property) == FT_Err_Ok && (property == HB_GDEF_MARK || (property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS) != 0)) { glyphs->glyphs[i].geometry.width = 0; } else { pango_font_get_glyph_extents ((PangoFont *)buffer->font, glyphs->glyphs[i].glyph, NULL, &logical_rect); glyphs->glyphs[i].geometry.width = logical_rect.width; } } else glyphs->glyphs[i].geometry.width = 0; glyphs->glyphs[i].geometry.x_offset = 0; glyphs->glyphs[i].geometry.y_offset = 0; } if (buffer->rtl) { /* Swap all glyphs */ swap_range (glyphs, 0, glyphs->num_glyphs); } if (buffer->applied_gpos) { if (buffer->rtl) apply_gpos_rtl (glyphs, buffer->buffer->positions); else apply_gpos_ltr (glyphs, buffer->buffer->positions); } else pango_fc_font_kern_glyphs (buffer->font, glyphs); pango_fc_font_unlock_face (buffer->font); }
static void basic_engine_shape (PangoEngineShape *engine, PangoFont *font, const char *text, gint length, PangoAnalysis *analysis, PangoGlyphString *glyphs) { int n_chars; int i; const char *p; g_return_if_fail (font != NULL); g_return_if_fail (text != NULL); g_return_if_fail (length >= 0); g_return_if_fail (analysis != NULL); #ifdef HAVE_USP10_H if (have_uniscribe && !text_is_simple (text, length) && uniscribe_shape (font, text, length, analysis, glyphs)) return; #endif n_chars = g_utf8_strlen (text, length); pango_glyph_string_set_size (glyphs, n_chars); p = text; for (i = 0; i < n_chars; i++) { gunichar wc; gunichar mirrored_ch; PangoGlyph index; wc = g_utf8_get_char (p); if (analysis->level % 2) if (pango_get_mirror_char (wc, &mirrored_ch)) wc = mirrored_ch; if (wc == 0xa0) /* non-break-space */ wc = 0x20; if (pango_is_zero_width (wc)) { set_glyph (font, glyphs, i, p - text, PANGO_GLYPH_EMPTY); } else { index = find_char (font, wc); if (index) { set_glyph (font, glyphs, i, p - text, index); if (g_unichar_type (wc) == G_UNICODE_NON_SPACING_MARK) { if (i > 0) { PangoRectangle logical_rect, ink_rect; glyphs->glyphs[i].geometry.width = MAX (glyphs->glyphs[i-1].geometry.width, glyphs->glyphs[i].geometry.width); glyphs->glyphs[i-1].geometry.width = 0; glyphs->log_clusters[i] = glyphs->log_clusters[i-1]; /* Some heuristics to try to guess how overstrike glyphs are * done and compensate */ /* FIXME: (alex) Is this double call to get_glyph_extents really necessary? */ pango_font_get_glyph_extents (font, glyphs->glyphs[i].glyph, &ink_rect, &logical_rect); if (logical_rect.width == 0 && ink_rect.x == 0) glyphs->glyphs[i].geometry.x_offset = (glyphs->glyphs[i].geometry.width - ink_rect.width) / 2; } } } else set_glyph (font, glyphs, i, p - text, PANGO_GET_UNKNOWN_GLYPH (wc)); } p = g_utf8_next_char (p); } /* Simple bidi support... may have separate modules later */ if (analysis->level % 2) { int start, end; /* Swap all glyphs */ swap_range (glyphs, 0, n_chars); /* Now reorder glyphs within each cluster back to LTR */ for (start = 0; start < n_chars;) { end = start; while (end < n_chars && glyphs->log_clusters[end] == glyphs->log_clusters[start]) end++; swap_range (glyphs, start, end); start = end; } } }
static void basic_engine_shape (PangoEngineShape *engine, PangoFont *font, const char *text, gint length, const PangoAnalysis *analysis, PangoGlyphString *glyphs) { const char *p; char *copy; CTLineRef line; CFStringRef cstr; CFDictionaryRef attributes; CFAttributedStringRef attstr; PangoCoreTextFont *cfont = PANGO_CORE_TEXT_FONT (font); PangoCoverage *coverage; CFArrayRef runs; CTRunRef run; CTRunStatus run_status; CFIndex i, glyph_count; const CGGlyph *cgglyphs; CFTypeRef keys[] = { (CFTypeRef) kCTFontAttributeName }; CFTypeRef values[] = { pango_core_text_font_get_ctfont (cfont) }; attributes = CFDictionaryCreate (kCFAllocatorDefault, (const void **)keys, (const void **)values, 1, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); copy = g_strndup (text, length + 1); copy[length] = 0; cstr = CFStringCreateWithCString (kCFAllocatorDefault, copy, kCFStringEncodingUTF8); g_free (copy); attstr = CFAttributedStringCreate (kCFAllocatorDefault, cstr, attributes); line = CTLineCreateWithAttributedString (attstr); runs = CTLineGetGlyphRuns (line); /* Since Pango divides things into runs already, we assume there is * only a single run in this line. */ run = CFArrayGetValueAtIndex (runs, 0); run_status = CTRunGetStatus (run); glyph_count = CTRunGetGlyphCount (run); cgglyphs = CTRunGetGlyphsPtr (run); p = text; pango_glyph_string_set_size (glyphs, glyph_count); coverage = pango_font_get_coverage (PANGO_FONT (cfont), analysis->language); for (i = 0; i < glyph_count; i++) { CFIndex real_i, prev_i; gunichar wc; gunichar mirrored_ch; wc = g_utf8_get_char (p); if (analysis->level % 2) if (pango_get_mirror_char (wc, &mirrored_ch)) wc = mirrored_ch; if (run_status & kCTRunStatusRightToLeft) { real_i = glyph_count - i - 1; prev_i = real_i + 1; } else { real_i = i; prev_i = real_i - 1; } if (wc == 0xa0) /* non-break-space */ wc = 0x20; if (pango_is_zero_width (wc)) { set_glyph (font, glyphs, real_i, p - text, PANGO_GLYPH_EMPTY); } else { PangoCoverageLevel result; result = pango_coverage_get (coverage, wc); if (result != PANGO_COVERAGE_NONE) { set_glyph (font, glyphs, real_i, p - text, cgglyphs[real_i]); if (g_unichar_type (wc) == G_UNICODE_NON_SPACING_MARK) { if (i > 0) { PangoRectangle logical_rect, ink_rect; glyphs->glyphs[real_i].geometry.width = MAX (glyphs->glyphs[prev_i].geometry.width, glyphs->glyphs[prev_i].geometry.width); glyphs->glyphs[prev_i].geometry.width = 0; glyphs->log_clusters[real_i] = glyphs->log_clusters[prev_i]; /* Some heuristics to try to guess how overstrike glyphs are * done and compensate */ pango_font_get_glyph_extents (font, glyphs->glyphs[real_i].glyph, &ink_rect, &logical_rect); if (logical_rect.width == 0 && ink_rect.x == 0) glyphs->glyphs[real_i].geometry.x_offset = (glyphs->glyphs[real_i].geometry.width - ink_rect.width) / 2; } } } else { set_glyph (font, glyphs, real_i, p - text, PANGO_GET_UNKNOWN_GLYPH (wc)); } } p = g_utf8_next_char (p); } CFRelease (line); CFRelease (attstr); CFRelease (cstr); CFRelease (attributes); pango_coverage_unref (coverage); }