This commit is contained in:
Vincent Wei
2019-03-21 15:03:04 +08:00
parent 96b06544b3
commit 65972861a0
6 changed files with 200 additions and 83 deletions
-2
View File
@@ -41,8 +41,6 @@
#include <stdlib.h>
#include <string.h>
#define DEBUG
#include "common.h"
#include "minigui.h"
#include "gdi.h"
+18
View File
@@ -108,6 +108,24 @@ static inline BOOL is_uchar_letter(Uchar32 uc,
return FALSE;
}
static inline BOOL is_uchar_no_shaping(Uchar32 uc)
{
UCharGeneralCategory gc;
gc = UCharGetCategory (uc);
if ((gc == UCHAR_CATEGORY_CONTROL ||
gc == UCHAR_CATEGORY_FORMAT ||
gc == UCHAR_CATEGORY_SURROGATE ||
(gc == UCHAR_CATEGORY_SPACE_SEPARATOR &&
uc != 0x1680u /* OGHAM SPACE MARK */) ||
(uc >= 0xfe00u && uc <= 0xfe0fu) ||
(uc >= 0xe0100u && uc <= 0xe01efu))) {
return TRUE;
}
return FALSE;
}
BOOL _unicode_is_emoji(Uchar32 ch);
BOOL _unicode_is_emoji_presentation(Uchar32 ch);
BOOL _unicode_is_emoji_modifier(Uchar32 ch);
+18 -15
View File
@@ -2207,6 +2207,9 @@ int _font_get_glyph_log_width(LOGFONT* logfont, Glyph32 gv)
int glyph_bmptype;
DEVFONT* devfont = SELECT_DEVFONT_BY_GLYPH(logfont, gv);
if (gv == INV_GLYPH_VALUE)
return 0;
gv = REAL_GLYPH(gv);
width = devfont->font_ops->get_glyph_advance(logfont, devfont, gv,
NULL, NULL);
@@ -2241,22 +2244,21 @@ int _font_get_glyph_advance (LOGFONT* logfont, DEVFONT* devfont,
int bold = 0;
int tmp_x = x;
int tmp_y = y;
int adv_len;
int bbox_x = 0, bbox_y = 0;
int adv_len = 0;
int bbox_x = x, bbox_y = y;
int bbox_w = 0, bbox_h = 0;
int advance = 0;
int glyph_bmptype;
// skip empty glyph
if (glyph_value == INV_GLYPH_VALUE) {
goto done;
}
glyph_bmptype = devfont->font_ops->get_glyph_bmptype (logfont, devfont)
& DEVFONTGLYPHTYPE_MASK_BMPTYPE;
bbox_x = x;
bbox_y = y;
/* in freetype get_glyph_bbox loads glyph, so we must call get_glyph_bbox
* before get_glyph_advance, get_glyph_monobitmap....
*/
devfont->font_ops->get_glyph_bbox (logfont, devfont,
REAL_GLYPH(glyph_value), &bbox_x, &bbox_y, &bbox_w, &bbox_h);
@@ -2269,13 +2271,6 @@ int _font_get_glyph_advance (LOGFONT* logfont, DEVFONT* devfont,
bbox_w += bold;
}
if (bbox) {
bbox->x = bbox_x;
bbox->y = bbox_y;
bbox->w = bbox_w;
bbox->h = bbox_h;
}
adv_len = devfont->font_ops->get_glyph_advance (logfont, devfont,
REAL_GLYPH(glyph_value), &tmp_x, &tmp_y);
@@ -2302,6 +2297,14 @@ int _font_get_glyph_advance (LOGFONT* logfont, DEVFONT* devfont,
}
}
done:
if (bbox) {
bbox->x = bbox_x;
bbox->y = bbox_y;
bbox->w = bbox_w;
bbox->h = bbox_h;
}
return adv_len + bold + ch_extra + advance;
}
+14
View File
@@ -209,7 +209,21 @@ static BOOL shape_text_run(SEINSTANCE* inst,
j++;
}
}
else {
gv = GetGlyphValue(run->lf, UCHAR2ACHAR(shaped_ucs[i]));
gs->glyphs[j].gv = gv;
gs->glyphs[j].is_cluster_start = 0;
gs->glyphs[j].x_off = 0;
gs->glyphs[j].y_off = 0;
gs->glyphs[j].width
= _font_get_glyph_log_width(run->lf, gv);
gs->log_clusters[j] = i;
j++;
}
}
gs->nr_glyphs = j;
if (ar_props && ar_props != local_ar_props) {
+147 -66
View File
@@ -75,6 +75,7 @@ typedef struct _TEXTRUNSTATE {
TEXTRUNSINFO* runinfo;
const Uchar32* text;
const Uchar32* end;
TEXTRUN* run;
const Uchar32* run_start;
const Uchar32* run_end;
@@ -94,6 +95,7 @@ typedef struct _TEXTRUNSTATE {
EmojiIterator emoji_iter;
LanguageCode derived_lang;
} TEXTRUNSTATE;
static void update_embedding_end(TEXTRUNSTATE *state)
@@ -160,16 +162,11 @@ static void state_update_for_new_run (TEXTRUNSTATE *state)
if (old_derived_lang != state->derived_lang)
state->changed |= DERIVED_LANG_CHANGED;
}
#if 0
if ((state->changed & DERIVED_LANG_CHANGED) || !state->lang_engine) {
state->lang_engine = _pango_get_language_engine ();
}
#endif
}
static LOGFONT* create_logfont_for_run(const TEXTRUNSINFO* runinfo,
const TEXTRUN* run)
/* Use MiniGUI resource manager to avoid duplicated logfonts */
static LOGFONT* create_logfont_for_ort(const TEXTRUNSINFO* runinfo,
GlyphOrient ort)
{
char fontname[LEN_LOGFONT_NAME_FULL + 1];
int orient_pos = fontGetOrientPosFromName(runinfo->fontname);
@@ -181,7 +178,7 @@ static LOGFONT* create_logfont_for_run(const TEXTRUNSINFO* runinfo,
memset (fontname, 0, LEN_LOGFONT_NAME_FULL + 1);
strncpy (fontname, runinfo->fontname, LEN_LOGFONT_NAME_FULL);
switch (run->ort) {
switch (ort) {
case GLYPH_ORIENT_UPRIGHT:
fontname[orient_pos] = FONT_ORIENT_UPRIGHT;
break;
@@ -195,7 +192,7 @@ static LOGFONT* create_logfont_for_run(const TEXTRUNSINFO* runinfo,
fontname[orient_pos] = FONT_ORIENT_SIDEWAYS_LEFT;
break;
default:
_WRN_PRINTF("bad orientation param: %d\n", run->ort);
_WRN_PRINTF("bad orientation param: %d\n", ort);
return NULL;
}
@@ -242,66 +239,95 @@ static void release_logfont_for_run(const TEXTRUNSINFO* runinfo,
ReleaseRes(Str2Key(fontname));
}
static void state_add_character(TEXTRUNSTATE *state,
BOOL no_shaping, BOOL force_break, const Uchar32* pos)
{
if (state->run) {
BOOL without_shaping = (state->run->lf == NULL);
if (!force_break &&
state->run->lc == state->derived_lang &&
without_shaping == no_shaping) {
state->run->len++;
return;
}
}
state->run = malloc(sizeof(TEXTRUN));
if (no_shaping)
state->run->lf = NULL;
else
state->run->lf = create_logfont_for_ort(state->runinfo, state->ort_rsv);
state->run->idx = pos - state->text;
state->run->len = 1;
state->run->lc = state->derived_lang;
state->run->st = state->script_iter.script;
state->run->el = state->emb_level;
state->run->dir = state->runinfo->run_dir;
state->run->ort = state->ort_rsv;
/* The level vs. gravity dance:
* If gravity is SOUTH, leave level untouched.
* If gravity is NORTH, step level one up, to
* not get mirrored upside-down text.
* If gravity is EAST, step up to an even level, as
* it's a clockwise-rotated layout, so the rotated
* top is unrotated left.
* If gravity is WEST, step up to an odd level, as
* it's a counter-clockwise-rotated layout, so the rotated
* top is unrotated right.
*/
switch (state->run->ort) {
case GLYPH_GRAVITY_SOUTH:
default:
break;
case GLYPH_GRAVITY_NORTH:
state->run->el++;
break;
case GLYPH_GRAVITY_EAST:
state->run->el += 1;
state->run->el &= ~1;
break;
case GLYPH_GRAVITY_WEST:
state->run->el |= 1;
break;
}
state->run->flags = state->centered_baseline ?
GLYPH_FLAG_CENTERED_BASELINE : 0;
list_add_tail(&state->run->list, &state->runinfo->run_head);
state->runinfo->nr_runs++;
}
static BOOL state_process_run (TEXTRUNSTATE *state)
{
TEXTRUN* run;
const Uchar32* p;
BOOL last_was_forced_break = FALSE;
state_update_for_new_run (state);
run = malloc(sizeof(TEXTRUN));
if (run == NULL) {
_ERR_PRINTF("%s: failed to allocate space for new glyph runs\n",
__FUNCTION__);
return FALSE;
}
for (p = state->run_start; p < state->run_end; p++) {
Uchar32 uc = *p;
run->lc = state->derived_lang;
run->st = state->script_iter.script;
run->el = state->emb_level;
run->dir = state->runinfo->run_dir;
run->ort = state->ort_rsv;
run->lf = create_logfont_for_run(state->runinfo, run);
run->idx = state->run_start - state->text;
run->len = state->run_end - state->run_start;
list_add_tail(&run->list, &state->runinfo->run_head);
state->runinfo->nr_runs++;
return TRUE;
#if 0
const Uchar32 *p;
BOOL last_was_forced_break = FALSE;
/* Only one character has the category LINE_SEPARATOR in Unicode 12.0;
* update this if that changes. */
/* Only one character has the category LINE_SEPARATOR in Unicode 12.0;
* update this if that changes. */
#define LINE_SEPARATOR 0x2028
for (p = state->run_start; p < state->run_end; p++) {
Uchar32 wc = *p;
BOOL is_forced_break = (wc == '\t' || wc == LINE_SEPARATOR);
UCharGeneralCategory type;
BOOL is_forced_break = (uc == '\t' || uc == LINE_SEPARATOR);
BOOL no_shaping;
/* We don't want space characters to affect font selection; in general,
* it's always wrong to select a font just to render a space.
* We assume that all fonts have the ASCII space, and for other space
* characters if they don't, HarfBuzz will compatibility-decompose them
* to ASCII space...
*/
type = UCharGetCategory (wc);
if ((type == UCHAR_CATEGORY_CONTROL ||
type == UCHAR_CATEGORY_FORMAT ||
type == UCHAR_CATEGORY_SURROGATE ||
(type == UCHAR_CATEGORY_SPACE_SEPARATOR &&
wc != 0x1680u /* OGHAM SPACE MARK */) ||
(wc >= 0xfe00u && wc <= 0xfe0fu) ||
(wc >= 0xe0100u && wc <= 0xe01efu))) {
}
else {
}
no_shaping = is_uchar_no_shaping(uc);
state_add_character(state, no_shaping,
is_forced_break || last_was_forced_break, p);
last_was_forced_break = is_forced_break;
}
#endif
/* Finish the final item from the current segment */
state->run = NULL;
return TRUE;
}
static BOOL state_next (TEXTRUNSTATE *state)
@@ -356,7 +382,12 @@ static BOOL create_glyph_runs(TEXTRUNSINFO* runinfo, BidiLevel* els)
state.runinfo = runinfo;
state.text = runinfo->ucs;
state.end = runinfo->ucs + runinfo->nr_ucs;
state.run = NULL;
state.els = els;
state.ort_rsv = runinfo->ort_rsv;
/* check font gravity here */
state.centered_baseline = GLYPH_ORIENT_IS_VERTICAL(runinfo->ort_rsv);
state.run_start = state.text;
state.changed = 0;
@@ -370,7 +401,14 @@ static BOOL create_glyph_runs(TEXTRUNSINFO* runinfo, BidiLevel* els)
__mg_emoji_iterator_init (&state.emoji_iter, state.text, runinfo->nr_ucs,
types_buff);
if (types_buff && types_buff != local_types_buff) {
free (types_buff);
types_buff = NULL;
}
update_end (&state);
state.changed = EMBEDDING_CHANGED | SCRIPT_CHANGED | LANG_CHANGED |
FONT_CHANGED | WIDTH_CHANGED | EMOJI_CHANGED;
do {
@@ -442,6 +480,40 @@ void* GetNextTextRunInfo(TEXTRUNSINFO* runinfo,
}
#endif /* _MGDEVEL_MODE */
static BOOL is_fontname_conformed(const char* fontname,
GlyphOrient glyph_orient, GlyphOrientPolicy orient_policy)
{
LOGFONT* lf;
DEVFONT *sbc_devfont, *mbc_devfont;
BOOL ok = FALSE;
if ((lf = CreateLogFontByName(fontname)) == NULL)
return FALSE;
sbc_devfont = lf->devfonts[0];
mbc_devfont = lf->devfonts[1];
if (mbc_devfont == NULL)
goto out;
if (mbc_devfont->charset_ops->conv_to_uc32)
goto out;
/* TODO: check more */
if (glyph_orient != GLYPH_ORIENT_UPRIGHT) {
if (sbc_devfont->font_ops->is_rotatable(lf, sbc_devfont, 100) != 100
|| mbc_devfont->font_ops->is_rotatable(lf, mbc_devfont, 100)
!= 100)
goto out;
}
ok = TRUE;
out:
DestroyLogFont(lf);
return ok;
}
TEXTRUNSINFO* GUIAPI CreateTextRunsInfo(Uchar32* ucs, int nr_ucs,
LanguageCode lang_code, ParagraphDir base_dir, GlyphRunDir run_dir,
GlyphOrient glyph_orient, GlyphOrientPolicy orient_policy,
@@ -453,9 +525,16 @@ TEXTRUNSINFO* GUIAPI CreateTextRunsInfo(Uchar32* ucs, int nr_ucs,
BidiLevel local_els[LOCAL_ARRAY_SIZE];
BidiLevel* els = NULL;
if (ucs == NULL || nr_ucs <= 0 || logfont_name == NULL) {
return NULL;
}
if (!is_fontname_conformed(logfont_name, glyph_orient, orient_policy)) {
return NULL;
}
runinfo = (TEXTRUNSINFO*)calloc(1, sizeof(TEXTRUNSINFO));
if (ucs == NULL || nr_ucs <= 0 || logfont_name == NULL ||
runinfo == NULL) {
if (runinfo == NULL) {
return NULL;
}
@@ -486,11 +565,18 @@ TEXTRUNSINFO* GUIAPI CreateTextRunsInfo(Uchar32* ucs, int nr_ucs,
runinfo->ucs = ucs;
runinfo->fontname = strdup(logfont_name);
runinfo->nr_ucs = nr_ucs;
runinfo->lc = lang_code;
if (lang_code == LANGCODE_unknown)
runinfo->lc = LANGCODE_en; // fallback to English
else
runinfo->lc = lang_code;
runinfo->base_level = (base_dir == BIDI_PGDIR_LTR) ? 0 : 1;
runinfo->run_dir = run_dir;
runinfo->ort_base = glyph_orient;
runinfo->ort_plc = orient_policy;
if (runinfo->ort_base == GLYPH_ORIENT_AUTO)
runinfo->ort_rsv = get_glyph_orient_from_fontname (runinfo->fontname);
else
runinfo->ort_rsv = runinfo->ort_base;
INIT_LIST_HEAD(&runinfo->cm_head.list);
runinfo->cm_head.si = 0;
@@ -500,11 +586,6 @@ TEXTRUNSINFO* GUIAPI CreateTextRunsInfo(Uchar32* ucs, int nr_ucs,
INIT_LIST_HEAD(&runinfo->run_head);
runinfo->nr_runs = 0;
if (runinfo->ort_base == GLYPH_ORIENT_AUTO)
runinfo->ort_rsv = get_glyph_orient_from_fontname (runinfo->fontname);
else
runinfo->ort_rsv = runinfo->ort_base;
#if 0
int i, j;
BidiLevel max_level = 0;
+3
View File
@@ -67,6 +67,8 @@ struct _SHAPINGENGINEINFO {
CB_DESTROY_INSTANCE free;
};
#define GLYPH_FLAG_CENTERED_BASELINE 1
struct _TEXTRUN {
struct list_head list;
LOGFONT* lf; // the logfont for this run
@@ -79,6 +81,7 @@ struct _TEXTRUN {
Uint32 el:8; // the bidi embedding level
Uint32 dir:4; // the run direction
Uint32 ort:2; // the glyph orientation
Uint32 flags:2;// other flags
};
struct _TEXTCOLORMAP {