mirror of
https://github.com/VincentWei/MiniGUI.git
synced 2026-02-07 11:01:57 +08:00
initial implementation of complex shaping engine
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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) */
|
||||
|
||||
|
||||
Reference in New Issue
Block a user