initial implementation of complex shaping engine

This commit is contained in:
Vincent Wei
2019-04-08 15:17:05 +08:00
parent 0b92cd51be
commit 872ea630fd
4 changed files with 182 additions and 15 deletions

View File

@@ -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;

View File

@@ -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
}

View File

@@ -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;
}

View File

@@ -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 <hb.h>
#include <hb-ft.h>
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) */