diff options
Diffstat (limited to 'modules/basic/basic-x.c')
-rw-r--r-- | modules/basic/basic-x.c | 141 |
1 files changed, 125 insertions, 16 deletions
diff --git a/modules/basic/basic-x.c b/modules/basic/basic-x.c index 54417064..99316cc9 100644 --- a/modules/basic/basic-x.c +++ b/modules/basic/basic-x.c @@ -28,7 +28,9 @@ typedef struct _CharRange CharRange; typedef struct _Charset Charset; +typedef struct _CharsetOrdering CharsetOrdering; typedef struct _CharCache CharCache; +typedef struct _CharCachePointer CharCachePointer; typedef struct _MaskTable MaskTable; typedef PangoGlyph (*ConvFunc) (CharCache *cache, @@ -47,6 +49,12 @@ struct _Charset ConvFunc conv_func; }; +struct _CharsetOrdering +{ + const char *langs; + char charsets[MAX_CHARSETS]; +}; + struct _CharRange { guint16 start; @@ -64,10 +72,18 @@ struct _MaskTable struct _CharCache { + guint ref_count; + CharsetOrdering *ordering; MaskTable *mask_tables[256]; GIConv converters[MAX_CHARSETS]; }; +struct _CharCachePointer +{ + PangoLanguage *lang; + CharCache *cache; +}; + static PangoGlyph conv_8bit (CharCache *cache, Charset *charset, const char *input); @@ -112,17 +128,37 @@ static gint n_script_engines = G_N_ELEMENTS (script_engines); * X window system script engine portion */ +/* Structure of our cache: + * + * PangoFont => CharCachePointer ===\ + * | \ + * CharCachePointer ======> CharCache => CharsetOrdering + * | |======> MaskTable[0] => {subfonts,charset}[n_subfonts], + * | |======> MaskTable[1] => {subfonts,charset}[n_subfonts], + * | \======> MaskTable[...] => {subfonts,charset}[n_subfonts] + * | + * CharCachePointer ======> CharCache => CharsetOrdering + * |======> MaskTable[0] => {subfonts,charset}[n_subfonts], + * |======> MaskTable[1] => {subfonts,charset}[n_subfonts], + * \======> MaskTable[...] => {subfonts,charset}[n_subfonts] + * + * A CharCache structure caches the lookup of what subfonts can be used for what characters for a pair of a Font + * and CharsetOrdering. Multiple language tags can share the same CharsetOrdering - the list of CharCachePointer + * structures that is attached to the font as object data provides lookups from language tag to charcache. + */ static CharCache * -char_cache_new (void) +char_cache_new (CharsetOrdering *ordering) { CharCache *result; int i; result = g_new0 (CharCache, 1); + result->ref_count = 1; + result->ordering = ordering; for (i=0; i<MAX_CHARSETS; i++) result->converters[i] = (GIConv)-1; - + return result; } @@ -188,10 +224,12 @@ find_char (CharCache *cache, PangoFont *font, gunichar wc, const char *input) for (i=0; i<G_N_ELEMENTS(charsets); i++) { - if (mask & (1 << i)) + int charset_index = cache->ordering->charsets[i]; + + if (mask & (1 << charset_index)) { - charset_names[n_charsets] = charsets[i].x_charset; - charsets_map[n_charsets] = &charsets[i]; + charset_names[n_charsets] = charsets[charset_index].x_charset; + charsets_map[n_charsets] = &charsets[charset_index]; n_charsets++; } @@ -329,19 +367,90 @@ swap_range (PangoGlyphString *glyphs, int start, int end) } } +static void +char_caches_free (GSList *caches) +{ + GSList *tmp_list = caches; + while (tmp_list) + { + CharCachePointer *pointer = tmp_list->data; + + pointer->cache->ref_count--; + if (pointer->cache->ref_count == 0) + char_cache_free (pointer->cache); + g_free (pointer); + + tmp_list = tmp_list->next; + } + g_slist_free (caches); +} + +static CharsetOrdering * +ordering_for_lang (PangoLanguage *lang) +{ + int i; + + for (i = 0; i < G_N_ELEMENTS (charset_orderings) - 1; i++) + { + if (pango_language_matches (lang, charset_orderings[i].langs)) + return &charset_orderings[i]; + } + + return &charset_orderings[i]; +} + static CharCache * -get_char_cache (PangoFont *font) +get_char_cache (PangoFont *font, + PangoLanguage *lang) { GQuark cache_id = g_quark_from_string ("basic-char-cache"); - - CharCache *cache = g_object_get_qdata (G_OBJECT (font), cache_id); - if (!cache) + CharCache *cache = NULL; + CharCachePointer *pointer; + CharsetOrdering *ordering; + GSList *caches; + GSList *tmp_list; + + caches = g_object_get_qdata (G_OBJECT (font), cache_id); + tmp_list = caches; + while (tmp_list) + { + pointer = tmp_list->data; + if (pointer->lang == lang) + return pointer->cache; + + tmp_list = tmp_list->next; + } + + ordering = ordering_for_lang (lang); + + tmp_list = caches; + while (tmp_list) { - cache = char_cache_new (); - g_object_set_qdata_full (G_OBJECT (font), cache_id, - cache, (GDestroyNotify)char_cache_free); + pointer = tmp_list->data; + if (pointer->cache->ordering == ordering) + { + cache = pointer->cache; + break; + } + + tmp_list = tmp_list->next; } + if (!cache) + cache = char_cache_new (ordering); + else + cache->ref_count++; + + pointer = g_new (CharCachePointer, 1); + pointer->lang = lang; + pointer->cache = cache; + + caches = g_slist_prepend (caches, pointer); + + g_object_steal_qdata (G_OBJECT (font), cache_id); + g_object_set_qdata_full (G_OBJECT (font), cache_id, + caches, (GDestroyNotify)char_caches_free); + return cache; } @@ -363,7 +472,7 @@ basic_engine_shape (PangoFont *font, g_return_if_fail (length >= 0); g_return_if_fail (analysis != NULL); - cache = get_char_cache (font); + cache = get_char_cache (font, analysis->language); n_chars = g_utf8_strlen (text, length); pango_glyph_string_set_size (glyphs, n_chars); @@ -451,10 +560,10 @@ basic_engine_shape (PangoFont *font, } static PangoCoverage * -basic_engine_get_coverage (PangoFont *font, - const char *lang) +basic_engine_get_coverage (PangoFont *font, + PangoLanguage *lang) { - CharCache *cache = get_char_cache (font); + CharCache *cache = get_char_cache (font, lang); PangoCoverage *result = pango_coverage_new (); gunichar wc; |