new API: UBidiGetParagraphEmbeddingLevelsAlt, an optimized call

This commit is contained in:
Vincent Wei
2019-03-18 19:07:53 +08:00
parent aab8d6e2c6
commit ceaec7e3d3
6 changed files with 179 additions and 98 deletions

View File

@@ -8277,6 +8277,10 @@ MG_EXPORT BidiLevel GUIAPI UBidiGetParagraphEmbeddingLevels(
const BidiBracketType* bracket_types, int len,
ParagraphDir *paragraph_dir, BidiLevel *embedding_levels);
MG_EXPORT BidiLevel GUIAPI UBidiGetParagraphEmbeddingLevelsAlt(
const Uchar32* ucs, int nr_ucs,
ParagraphDir *paragraph_dir, BidiLevel *embedding_levels);
/*
* \var typedef void (*CB_REVERSE_ARRAY) (void* extra, int len, int pos)
* \brief The prototype of the user defined function to reverse an array.
@@ -12429,7 +12433,6 @@ MG_EXPORT GLYPHRUNINFO* GUIAPI CreateGlyphRunInfo(Uchar32* ucs, int nr_ucs,
LanguageCode lang_code, ScriptType script_type,
ParagraphDir base_dir, GlyphRunDir run_dir,
GlyphOrient glyph_orient, GlyphOrientPolicy orient_policy,
Uint8 ctr, Uint8 wbr, Uint8 lbp,
LOGFONT* logfont, RGBCOLOR color);
/**
@@ -12700,7 +12703,8 @@ MG_EXPORT GLYPHEXTINFO* GUIAPI GetShapedGlyphsExtentInfo(
* GetGlyphsExtentInfo, DrawShapedGlyphString, GLYPHEXTINFO, glyph_render_flags
*/
MG_EXPORT int GUIAPI GetShapedGlyphsFittingLine(const GLYPHRUNINFO* run_info,
int uc_start_index, int x, int y,
const BreakOppo* break_oppos,
int uc_start_index, int x, int y, Uint32 render_flags,
int letter_spacing, int word_spacing, int tab_size, int max_extent,
SIZE* line_size, GLYPHPOS** glyph_pos, int* nr_glyphs);

View File

@@ -1711,4 +1711,130 @@ out:
return status ? max_level + 1 : 0;
}
/* Local array size, used for stack-based local arrays */
#if SIZEOF_PTR == 8
# define LOCAL_ARRAY_SIZE 256
#else
# define LOCAL_ARRAY_SIZE 128
#endif
BidiLevel GUIAPI UBidiGetParagraphEmbeddingLevelsAlt(
const Uchar32* ucs, int nr_ucs,
ParagraphDir *paragraph_dir, BidiLevel *els)
{
int i;
ParagraphDir base_dir = *paragraph_dir;
BidiLevel max_level = 0;
BidiType local_bidi_ts[LOCAL_ARRAY_SIZE];
BidiType *bidi_ts = NULL;
BidiType ored_types = 0;
BidiType anded_strongs = BIDI_TYPE_RLE;
BidiBracketType local_brk_ts[LOCAL_ARRAY_SIZE];
BidiBracketType *brk_ts = NULL;
if (!els) {
_DBG_PRINTF("%s: Embedding levels is NULL.\n",
__FUNCTION__);
goto out;
}
if (nr_ucs < LOCAL_ARRAY_SIZE)
bidi_ts = local_bidi_ts;
else
bidi_ts = malloc(nr_ucs * sizeof(BidiType));
if (!bidi_ts) {
_DBG_PRINTF("%s: failed to allocate space for bidi types.\n",
__FUNCTION__);
goto out;
}
if (nr_ucs < LOCAL_ARRAY_SIZE)
brk_ts = local_brk_ts;
else
brk_ts = (BidiBracketType*)malloc (nr_ucs * sizeof(BidiBracketType));
if (!brk_ts) {
_DBG_PRINTF("%s: failed to allocate space for bracket types.\n",
__FUNCTION__);
goto out;
}
for (i = 0; i < nr_ucs; i++) {
BidiType bidi_type;
bidi_ts[i] = bidi_type = UCharGetBidiType(ucs[i]);
ored_types |= bidi_type;
if (BIDI_IS_STRONG (bidi_type))
anded_strongs &= bidi_type;
if (bidi_ts[i] == BIDI_TYPE_ON)
brk_ts[i] = UCharGetBracketType(ucs[i]);
else
brk_ts[i] = BIDI_BRACKET_NONE;
}
/* Short-circuit (malloc-expensive) Bidi call for unidirectional text. */
/* The case that all resolved levels will be ltr.
* No isolates, all strongs be LTR, there should be no Arabic numbers
* (or letters for that matter), and one of the following:
*
* o base_dir doesn't have an RTL taste.
* o there are letters, and base_dir is weak.
*/
if (!BIDI_IS_ISOLATE (ored_types) &&
!BIDI_IS_RTL (ored_types) &&
!BIDI_IS_ARABIC (ored_types) &&
(!BIDI_IS_RTL (base_dir) ||
(BIDI_IS_WEAK (base_dir) &&
BIDI_IS_LETTER (ored_types))
))
{
/* all LTR */
base_dir = BIDI_PGDIR_LTR;
memset (els, 0, nr_ucs);
}
/* The case that all resolved levels will be RTL is much more complex.
* No isolates, no numbers, all strongs are RTL, and one of
* the following:
*
* o base_dir has an RTL taste (may be weak).
* o there are letters, and base_dir is weak.
*/
else if (!BIDI_IS_ISOLATE (ored_types) &&
!BIDI_IS_NUMBER (ored_types) &&
BIDI_IS_RTL (anded_strongs) &&
(BIDI_IS_RTL (base_dir) ||
(BIDI_IS_WEAK (base_dir) &&
BIDI_IS_LETTER (ored_types))
))
{
/* all RTL */
base_dir = BIDI_PGDIR_RTL;
memset (els, 1, nr_ucs);
}
else {
max_level = UBidiGetParagraphEmbeddingLevels(bidi_ts, brk_ts, nr_ucs,
&base_dir, els);
if (max_level == 0) {
_DBG_PRINTF("%s: failed to get paragraph embedding levels.\n");
memset (els, 0, nr_ucs);
}
}
*paragraph_dir = (base_dir == BIDI_PGDIR_LTR) ? BIDI_PGDIR_LTR : BIDI_PGDIR_RTL;
out:
if (bidi_ts && bidi_ts != local_bidi_ts)
free (bidi_ts);
if (brk_ts && brk_ts != local_brk_ts)
free (brk_ts);
return max_level;
}
#endif /* _MGCHARSET_UNICODE */

View File

@@ -210,18 +210,14 @@ typedef unsigned char *emoji_text_iter_t;
#include "emoji_presentation_scanner.inc"
EmojiIterator * __mg_emoji_iter_init (EmojiIterator *iter,
const Uchar32* ucs, int nr_ucs)
const Uchar32* ucs, int nr_ucs, Uint8* types_buff)
{
int i;
unsigned char *types;
Uint8 *types = types_buff;
const Uchar32 *p;
assert (nr_ucs > 0);
types = malloc (sizeof (unsigned char) * nr_ucs);
if (types == NULL)
return NULL;
p = ucs;
for (i = 0; i < nr_ucs; i++) {
types[i] = emojiSegmentationCategory (*p);
@@ -272,9 +268,4 @@ BOOL __mg_emoji_iter_next (EmojiIterator *iter)
return TRUE;
}
void __mg_emoji_iter_fini (EmojiIterator *iter)
{
free (iter->types);
}
#endif /* _MGCHARSET_UNICODE */

View File

@@ -128,7 +128,7 @@ WidthIterator* __mg_width_iter_init (WidthIterator* iter,
void __mg_width_iter_next(WidthIterator* iter);
EmojiIterator* __mg_emoji_iter_init (EmojiIterator *iter,
const Uchar32* ucs, int nr_ucs);
const Uchar32* ucs, int nr_ucs, Uint8* types_buff);
BOOL __mg_emoji_iter_next (EmojiIterator *iter);
void __mg_emoji_iter_fini (EmojiIterator *iter);

View File

@@ -53,16 +53,24 @@
#include "unicode-ops.h"
#include "glyphruninfo.h"
typedef enum {
EMBEDDING_CHANGED = 1 << 0,
SCRIPT_CHANGED = 1 << 1,
LANG_CHANGED = 1 << 2,
DERIVED_LANG_CHANGED = 1 << 3,
WIDTH_CHANGED = 1 << 3,
EMOJI_CHANGED = 1 << 5,
} ChangedFlags;
/* Local array size, used for stack-based local arrays */
#if SIZEOF_PTR == 8
# define LOCAL_ARRAY_SIZE 256
#else
# define LOCAL_ARRAY_SIZE 128
#endif
typedef struct _GlyphRunState {
enum {
EMBEDDING_CHANGED = 1 << 0,
SCRIPT_CHANGED = 1 << 1,
LANG_CHANGED = 1 << 2,
DERIVED_LANG_CHANGED = 1 << 3,
FONT_CHANGED = 1 << 4,
WIDTH_CHANGED = 1 << 5,
EMOJI_CHANGED = 1 << 6,
};
typedef struct _GLYPHRUNSTATE {
GLYPHRUNINFO* context;
const Uchar32* text;
const Uchar32* end;
@@ -90,11 +98,13 @@ typedef struct _GlyphRunState {
EmojiIterator emoji_iter;
LanguageCode derived_lang;
} GlyphRunState;
} GLYPHRUNSTATE;
static BOOL init_glyph_runs(GLYPHRUNINFO* runinfo)
static BOOL init_glyph_runs(GLYPHRUNINFO* runinfo, BidiLevel* els)
{
#if 0
GLYPHRUNSTATE state;
BidiLevel el = runinfo->els[0];
ScriptType st = UCharGetScriptType(runinfo->ucs[0]);
#endif
@@ -102,36 +112,17 @@ static BOOL init_glyph_runs(GLYPHRUNINFO* runinfo)
return FALSE;
}
/* Local array size, used for stack-based local arrays */
#if SIZEOF_PTR == 8
# define LOCAL_ARRAY_SIZE 256
#else
# define LOCAL_ARRAY_SIZE 128
#endif
GLYPHRUNINFO* GUIAPI CreateGlyphRunInfo(Uchar32* ucs, int nr_ucs,
LanguageCode lang_code, ScriptType script_type,
ParagraphDir base_dir, GlyphRunDir run_dir,
GlyphOrient glyph_orient, GlyphOrientPolicy orient_policy,
Uint8 ctr, Uint8 wbr, Uint8 lbp,
LOGFONT* logfont, RGBCOLOR color)
{
BOOL ok = FALSE;
GLYPHRUNINFO* runinfo;
BidiLevel local_els[LOCAL_ARRAY_SIZE];
BidiLevel* els = NULL;
BreakOppo* bos = NULL;
BidiLevel max_level = 0;
BidiType local_bidi_ts[LOCAL_ARRAY_SIZE];
BidiType *bidi_ts = NULL;
BidiBracketType local_brk_ts[LOCAL_ARRAY_SIZE];
BidiBracketType *brk_ts = NULL;
BidiLevel level_or, level_and;
int i, j;
runinfo = (GLYPHRUNINFO*)calloc(1, sizeof(GLYPHRUNINFO));
if (ucs == NULL || nr_ucs <= 0 || runinfo == NULL) {
@@ -139,53 +130,28 @@ GLYPHRUNINFO* GUIAPI CreateGlyphRunInfo(Uchar32* ucs, int nr_ucs,
}
if (nr_ucs < LOCAL_ARRAY_SIZE)
bidi_ts = local_bidi_ts;
els = local_els;
else
bidi_ts = malloc(nr_ucs * sizeof(BidiType));
els = (BidiLevel*)malloc (nr_ucs * sizeof(BidiLevel));
if (!bidi_ts) {
_DBG_PRINTF("%s: failed to allocate space for bidi types.\n");
goto out;
}
UStrGetBidiTypes(ucs, nr_ucs, bidi_ts);
if (nr_ucs < LOCAL_ARRAY_SIZE)
brk_ts = local_brk_ts;
else
brk_ts = (BidiBracketType*)malloc (nr_ucs * sizeof(BidiBracketType));
if (!brk_ts) {
_DBG_PRINTF("%s: failed to allocate space for bracket types.\n");
goto out;
}
UStrGetBracketTypes (ucs, bidi_ts, nr_ucs, brk_ts);
els = (BidiLevel*)malloc (nr_ucs * sizeof(BidiLevel));
if (!els) {
_DBG_PRINTF("%s: failed to allocate space for embedding levels.\n");
goto out;
}
max_level = UBidiGetParagraphEmbeddingLevels(bidi_ts, brk_ts, nr_ucs,
&base_dir, els) - 1;
if (max_level < 0) {
_DBG_PRINTF("%s: failed to get paragraph embedding levels.\n");
goto out;
}
UBidiGetParagraphEmbeddingLevelsAlt(ucs, nr_ucs, &base_dir, els);
/* the breaking opportunities should be passed to the layout function.
// Calculate the breaking opportunities
if (UStrGetBreaks(script_type, ctr, wbr, lbp,
ucs, nr_ucs, &bos) == 0) {
_DBG_PRINTF("%s: failed to get breaking opportunities.\n");
goto out;
}
*/
// Initialize other fields
runinfo->ucs = ucs;
runinfo->els = els;
runinfo->bos = bos;
INIT_LIST_HEAD(&runinfo->cm_head.list);
runinfo->cm_head.si = 0;
@@ -206,6 +172,11 @@ GLYPHRUNINFO* GUIAPI CreateGlyphRunInfo(Uchar32* ucs, int nr_ucs,
runinfo->run_head.dir = run_dir;
runinfo->run_head.ort = glyph_orient;
#if 0
int i, j;
BidiLevel max_level = 0;
BidiLevel level_or, level_and;
// make the embedding levels of the bidi marks to be -1.
level_or = 0, level_and = 1;
j = 0;
@@ -222,11 +193,12 @@ GLYPHRUNINFO* GUIAPI CreateGlyphRunInfo(Uchar32* ucs, int nr_ucs,
// check for all even or odd
/* If none of the levels had the LSB set, all chars were even. */
runinfo->run_head.all_even = (level_or & 0x1) == 0;
runinfo->all_even = (level_or & 0x1) == 0;
/* If all of the levels had the LSB set, all chars were odd. */
runinfo->run_head.all_odd = (level_and & 0x1) == 1;
runinfo->all_odd = (level_and & 0x1) == 1;
#endif
if (!init_glyph_runs(runinfo)) {
if (!init_glyph_runs(runinfo, els)) {
_DBG_PRINTF("%s: failed to call init_glyph_runs.\n");
goto out;
}
@@ -234,18 +206,13 @@ GLYPHRUNINFO* GUIAPI CreateGlyphRunInfo(Uchar32* ucs, int nr_ucs,
ok = TRUE;
out:
if (bidi_ts && bidi_ts != local_bidi_ts)
free (bidi_ts);
if (brk_ts && brk_ts != local_brk_ts)
free (brk_ts);
if (els && els != local_els)
free(els);
if (ok)
return runinfo;
if (runinfo->l2g) free(runinfo->l2g);
if (els) free(els);
if (bos) free(bos);
free(runinfo);
return NULL;
@@ -340,7 +307,7 @@ BOOL GUIAPI ResetFontInGlyphRuns(GLYPHRUNINFO* runinfo, LOGFONT* logfont)
runinfo->run_head.lf = logfont;
return init_glyph_runs(runinfo);
return init_glyph_runs(runinfo, NULL);
}
static void set_run_dir(GLYPHRUNINFO* runinfo, GLYPHRUN* run,
@@ -401,17 +368,13 @@ BOOL GUIAPI ResetColorInGlyphRuns(GLYPHRUNINFO* runinfo, RGBCOLOR color)
return TRUE;
}
#if 0
BOOL GUIAPI ResetBreaksInGlyphRuns(GLYPHRUNINFO* runinfo,
Uint8 ctr, Uint8 wbr, Uint8 lbp)
{
if (runinfo == NULL)
return FALSE;
if (runinfo->bos) {
free (runinfo->bos);
runinfo->bos = NULL;
}
// Re-calculate the breaking opportunities
if (UStrGetBreaks(runinfo->run_head.st, ctr, wbr, lbp,
runinfo->ucs, runinfo->run_head.nr_ucs, &runinfo->bos) == 0) {
@@ -421,6 +384,7 @@ BOOL GUIAPI ResetBreaksInGlyphRuns(GLYPHRUNINFO* runinfo,
return TRUE;
}
#endif
BOOL GUIAPI DestroyGlyphRunInfo(GLYPHRUNINFO* runinfo)
{
@@ -446,8 +410,6 @@ BOOL GUIAPI DestroyGlyphRunInfo(GLYPHRUNINFO* runinfo)
if (runinfo->l2g) free(runinfo->l2g);
if (runinfo->ges) free(runinfo->ges);
if (runinfo->els) free(runinfo->els);
if (runinfo->bos) free(runinfo->bos);
free(runinfo);
return TRUE;

View File

@@ -82,8 +82,6 @@ typedef struct _GLYPHRUN {
Uint32 level:8; // the bidi level
Uint32 dir:4; // the run direction
Uint32 ort:2; // the glyph orientation
Uint32 all_even:1; // flag indicating all level is even
Uint8 all_odd:1; // flag indicating all level is odd
} GLYPHRUN;
// NOTE: we arrange the fields carefully to avoid wasting space when
@@ -102,9 +100,7 @@ typedef struct _UCHARCOLORMAP {
struct _GLYPHRUNINFO {
/* The following fields will be initialized by CreateGlyphRunInfo. */
Uchar32* ucs;
BidiLevel* els;
BreakOppo* bos;
const Uchar32* ucs;
UCHARCOLORMAP cm_head; // the head of color map list of the characters.
// change by calling SetPartColorInGlyphRunInfo.
@@ -117,6 +113,8 @@ struct _GLYPHRUNINFO {
GLYPHEXTINFO* ges; // the glyph extent information.
Uint32 rf; // the rendering flags.
Uint8 all_even:1; // flag indicating all level is even
Uint8 all_odd:1; // flag indicating all level is odd
};
#ifdef __cplusplus