diff --git a/src/font/freetype2.c b/src/font/freetype2.c index c9deb60a..343cac9f 100644 --- a/src/font/freetype2.c +++ b/src/font/freetype2.c @@ -771,6 +771,12 @@ static void get_kerning (LOGFONT* logfont, DEVFONT* devfont, *delta_y = delta.y >> 6; } +static void* get_ft_face (LOGFONT* logfont, DEVFONT* devfont) +{ + FTFACEINFO* ft_face_info = FT_FACE_INFO_P (devfont); + return ft_face_info->face; +} + #ifdef _MGFONT_TTF_CACHE static int make_hash_key(Glyph32 data) { @@ -1270,11 +1276,40 @@ FONTOPS __mg_ttf_ops = { load_font_data, unload_font_data, get_glyph_value, - get_kerning + get_kerning, + get_ft_face }; -BOOL -ft2SetLcdFilter (LOGFONT* logfont, FT2LCDFilter filter) +/* Get the FreeType2 face object for HarfBuzz shaping engine */ +void* __mg_ft2_get_face(LOGFONT* lf, Uchar32 uc, int* dfi) +{ + void* face = NULL; + DEVFONT* df; + int i; + + /* find the FreeType2 devfont which contains the glyph for + * the Uchar32 character */ + for (i = 1; i < MAXNR_DEVFONTS; i++) { + if ((df = lf->devfonts[i]) && df->font_ops->get_ft_face) { + face = df->font_ops->get_ft_face(lf, df); + if (df->font_ops->get_glyph_value(lf, df, uc)) { + *dfi = i; + return face; + } + } + } + + /* return the default face object */ + if ((df = lf->devfonts[1]) && df->font_ops->get_ft_face) { + *dfi = 1; + face = df->font_ops->get_ft_face(lf, df); + return face; + } + + return NULL; +} + +BOOL ft2SetLcdFilter (LOGFONT* logfont, FT2LCDFilter filter) { int i; BOOL rv = FALSE; @@ -1304,15 +1339,13 @@ ft2SetLcdFilter (LOGFONT* logfont, FT2LCDFilter filter) return rv; } -int -ft2GetLcdFilter (DEVFONT* devfont) +int ft2GetLcdFilter (DEVFONT* devfont) { FTINSTANCEINFO* ft_inst_info = FT_INST_INFO_P (devfont); return ft_inst_info->ft_lcdfilter; } -int -ft2IsFreeTypeDevfont (DEVFONT* devfont) +int ft2IsFreeTypeDevfont (DEVFONT* devfont) { if (devfont && devfont->font_ops == &__mg_ttf_ops) return TRUE; diff --git a/src/include/devfont.h b/src/include/devfont.h index 04d720c0..59142761 100644 --- a/src/include/devfont.h +++ b/src/include/devfont.h @@ -333,6 +333,13 @@ struct _FONTOPS */ void (*get_kerning) (LOGFONT* logfont, DEVFONT* devfont, Glyph32 prev, Glyph32 curr, int* delta_x, int* delta_y); + + /** + * The method to get the FreeType2 FT_Face objece; only valid for FreeType2 font engine + * + * Since 4.0.0. + */ + void* (*get_ft_face) (LOGFONT* logfont, DEVFONT* devfont); }; typedef struct { @@ -341,6 +348,7 @@ typedef struct { } FONTOPS_INFO; extern FONTOPS_INFO __mg_fontops_infos[]; +void* __mg_ft2_get_face(LOGFONT* lf, Uchar32 uc, int* dfi); #ifdef __cplusplus } diff --git a/src/newgdi/shape-glyphs-basic.c b/src/newgdi/shape-glyphs-basic.c index 4a58a975..90362c60 100644 --- a/src/newgdi/shape-glyphs-basic.c +++ b/src/newgdi/shape-glyphs-basic.c @@ -287,19 +287,17 @@ static BOOL destroy_instance(SEInstance* instance) return TRUE; } - _ERR_PRINTF("%s: you are destroying a non-basic shaping engine instance.\n", - __FUNCTION__); - + _WRN_PRINTF("You are destroying a non-basic shaping engine instance"); return FALSE; } -BOOL GUIAPI InitBasicShapingEngine(TEXTRUNS* info) +BOOL GUIAPI InitBasicShapingEngine(TEXTRUNS* truns) { shaping_engine_basic.ref_count++; - info->sei.inst = &shaping_engine_basic; - info->sei.shape = shape_layout_run; - info->sei.free = destroy_instance; + truns->sei.inst = &shaping_engine_basic; + truns->sei.shape = shape_layout_run; + truns->sei.free = destroy_instance; return TRUE; } diff --git a/src/newgdi/shape-glyphs-complex.c b/src/newgdi/shape-glyphs-complex.c index 90310636..70c9fa32 100644 --- a/src/newgdi/shape-glyphs-complex.c +++ b/src/newgdi/shape-glyphs-complex.c @@ -56,11 +56,139 @@ #include "devfont.h" #include "unicode-ops.h" #include "textruns.h" +#include "layout.h" +#include "glyph.h" -BOOL GUIAPI InitComplexShapingEngine(TEXTRUNS* run_info) +#include +#include + +static BOOL shape_layout_run(SEInstance* inst, + const TEXTRUNS* info, const LayoutRun* run, + GlyphString* gs) { + 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) { + _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; + + for (i = 0; i < run->len; i++) { + hb_buffer_add(hb_buf, run->ucs[i], i); + } + + hb_buffer_set_direction(hb_buf, run->dir + HB_DIRECTION_LTR); + hb_buffer_set_script(hb_buf, ScriptTypeToISO15924(run->st)); + hb_buffer_set_language(hb_buf, + hb_language_from_string(LanguageCodeToISO639s1(run->lc), -1)); + + hb_font = hb_ft_font_create(*face, NULL); + if (hb_font == NULL) + goto error; + + hb_shape(hb_font, hb_buf, NULL, 0); + + glyph_info = hb_buffer_get_glyph_infos(hb_buf, &nr_glyphs); + glyph_pos = hb_buffer_get_glyph_positions(hb_buf, &nr_glyphs); + if (glyph_info == NULL || glyph_pos == NULL || nr_glyphs == 0) { + _ERR_PRINTF("%s: bad shaping result: glyph_info(%p), glyph_pos(%p), nr_glyphs(%d)\n", + __FUNCTION__, glyph_info, glyph_pos, nr_glyphs); + goto error; + } + + // generate result + gs->glyphs = malloc(sizeof(ShapedGlyph) * nr_glyphs); + if (gs->glyphs == NULL) { + goto error; + } + gs->log_clusters = malloc(sizeof(int) * nr_glyphs); + if (gs->log_clusters == NULL) { + free(gs->glyphs); + goto error; + } + + last_cluster = -1; + gs->nr_glyphs = nr_glyphs; + for (i = 0 ; i < nr_glyphs; i++) { + + Glyph32 gv; + + gv = SET_GLYPH_DFI(glyph_info[i].codepoint, dfi); + gs->glyphs[i].gv = gv; + gs->log_clusters[i] = glyph_info[i].cluster; + + if (run->flags & LAYOUTRUN_FLAG_CENTERED_BASELINE) { + gs->glyphs[i].width = run->lf->size; + gs->glyphs[i].height + = _font_get_glyph_log_width(run->lf, gv); + } + else { + gs->glyphs[i].width + = _font_get_glyph_log_width(run->lf, gv); + gs->glyphs[i].height = run->lf->size; + } + + gs->glyphs[i].x_off = glyph_pos[i].x_offset >> 6; + gs->glyphs[i].y_off = glyph_pos[i].y_offset >> 6; + + gs->glyphs[i].is_cluster_start = gs->log_clusters[i] != last_cluster; + last_cluster = gs->log_clusters[i]; + } + + ok = TRUE; + +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.shape = shape_layout_run; + truns->sei.free = destroy_instance; + return TRUE; +} + #endif /* defined(_MGCHARSET_UNICODE) && defined(_MGCOMPLEX_SCRIPTS) */