diff --git a/src/newgdi/shape-glyphs-complex.c b/src/newgdi/shape-glyphs-complex.c index 0f2c0250..39a858c4 100644 --- a/src/newgdi/shape-glyphs-complex.c +++ b/src/newgdi/shape-glyphs-complex.c @@ -58,10 +58,121 @@ #include "textruns.h" #include "layout.h" #include "glyph.h" +#include "list.h" #include #include +typedef struct _FtFontInfo { + struct list_head list; + LOGFONT* lf; + ScriptType st; + FT_Face face; + hb_font_t* hb_font; + int dfi; +} FtFontInfo; + +struct _SEInstance { + int signature; + int nr_fonts; + struct list_head cached_fonts; +}; + +static hb_font_t* get_hb_font_for_script(SEInstance* inst, + LOGFONT* lf, ScriptType st, Uchar32 uc, int* dfi) +{ + struct list_head* f; + FT_Face face; + hb_font_t* hb_font; + FtFontInfo *new_fi; + FONT_RES* font_res; + + list_for_each(f, &inst->cached_fonts) { + FtFontInfo *fi = (FtFontInfo*)f; + + if (fi->lf == lf && fi->st == st) { + *dfi = fi->dfi; + return fi->hb_font; + } + } + + face = (FT_Face)__mg_ft2_get_face(lf, uc, dfi); + if (face == NULL) { + _WRN_PRINTF("Cannot get FT2 face for logfont (%p) and uc (0x%x)\n", + lf, uc); + return NULL; + } + + hb_font = hb_ft_font_create_referenced(face); + //hb_font = hb_ft_font_create(face, NULL); + if (hb_font == NULL) + return NULL; + + new_fi = mg_slice_new(FtFontInfo); + new_fi->lf = lf; + new_fi->st = st; + new_fi->face = face; + new_fi->hb_font = hb_font; + new_fi->dfi = *dfi; + + font_res = (FONT_RES*)lf; + AddResRef(font_res->key); + + list_add_tail(&new_fi->list, &inst->cached_fonts); + inst->nr_fonts++; + return hb_font; +} + +static SEInstance* create_instance(void) +{ + SEInstance* inst; + + inst = mg_slice_new(SEInstance); + + inst->signature = 0x77520388; + inst->nr_fonts = 0; + INIT_LIST_HEAD(&inst->cached_fonts); + + _DBG_PRINTF("%s: new complex shaping engine instance: %p\n", + __FUNCTION__, inst); + return inst; +} + +static BOOL destroy_instance(SEInstance* inst) +{ + _DBG_PRINTF("%s: destroy complex shaping engine instance: %p\n", + __FUNCTION__, inst); + + if (inst->signature != 0x77520388) { + _WRN_PRINTF("you passed a non-complex shaping engine instance."); + return FALSE; + } + + while (!list_empty(&inst->cached_fonts)) { + FONT_RES* font_res; + + FtFontInfo *fi = (FtFontInfo*)inst->cached_fonts.prev; + list_del(inst->cached_fonts.prev); + + hb_font_destroy(fi->hb_font); + + font_res = (FONT_RES*)fi->lf; + if (font_res->key) { + int rc = ReleaseRes(font_res->key); + _DBG_PRINTF("%s: ref count of logfont (%p): %d\n", + __FUNCTION__, fi->lf, rc); + } + + mg_slice_delete(FtFontInfo, fi); + inst->nr_fonts--; + } + + assert(inst->nr_fonts == 0); + + mg_slice_delete(SEInstance, inst); + return TRUE; +} + static BOOL shape_layout_run(SEInstance* inst, const TEXTRUNS* info, const LayoutRun* run, GlyphString* gs) @@ -69,19 +180,12 @@ static BOOL shape_layout_run(SEInstance* inst, BOOL ok = FALSE; int dfi; unsigned int i, nr_glyphs; - FT_Face face = NULL; hb_buffer_t *hb_buf = NULL; hb_font_t *hb_font = NULL; hb_glyph_info_t *glyph_info; hb_glyph_position_t *glyph_pos; int last_cluster; - face = (FT_Face)__mg_ft2_get_face(run->lf, run->ucs[0], &dfi); - if (face == NULL) { - _WRN_PRINTF("Can not get FT2 face object for layout run: %p\n", run); - return FALSE; - } - hb_buf = hb_buffer_create(); if (hb_buf == NULL) goto error; @@ -96,7 +200,7 @@ static BOOL shape_layout_run(SEInstance* inst, hb_buffer_set_language(hb_buf, hb_language_from_string(LanguageCodeToISO639s1(run->lc), -1)); - hb_font = hb_ft_font_create(face, NULL); + hb_font = get_hb_font_for_script(inst, run->lf, run->st, run->ucs[0], &dfi); if (hb_font == NULL) goto error; @@ -153,39 +257,15 @@ static BOOL shape_layout_run(SEInstance* inst, error: - if (hb_font) - hb_font_destroy(hb_font); if (hb_buf) hb_buffer_destroy(hb_buf); return ok; } -struct _SEInstance { - const char* name; - int ref_count; -}; - -static struct _SEInstance shaping_engine_complex = { - "Complex Shapping Engine", 0 -}; - -static BOOL destroy_instance(SEInstance* instance) -{ - if (instance == &shaping_engine_complex) { - shaping_engine_complex.ref_count--; - return TRUE; - } - - _WRN_PRINTF("you are destroying a non-complex shaping engine instance."); - return FALSE; -} - BOOL GUIAPI InitComplexShapingEngine(TEXTRUNS* truns) { - shaping_engine_complex.ref_count++; - - truns->sei.inst = &shaping_engine_complex; + truns->sei.inst = create_instance(); truns->sei.shape = shape_layout_run; truns->sei.free = destroy_instance; return TRUE;