From ceaec7e3d311ecb45c230d67ebe3992124e28203 Mon Sep 17 00:00:00 2001 From: Vincent Wei Date: Mon, 18 Mar 2019 19:07:53 +0800 Subject: [PATCH] new API: UBidiGetParagraphEmbeddingLevelsAlt, an optimized call --- include/gdi.h | 8 ++- src/font/unicode-bidi.c | 126 ++++++++++++++++++++++++++++++++++++++ src/font/unicode-emoji.c | 13 +--- src/include/unicode-ops.h | 2 +- src/newgdi/glyphruninfo.c | 120 +++++++++++++----------------------- src/newgdi/glyphruninfo.h | 8 +-- 6 files changed, 179 insertions(+), 98 deletions(-) diff --git a/include/gdi.h b/include/gdi.h index 7e107eab..964f4a5a 100644 --- a/include/gdi.h +++ b/include/gdi.h @@ -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); diff --git a/src/font/unicode-bidi.c b/src/font/unicode-bidi.c index 068e6e9e..f57e7bd5 100644 --- a/src/font/unicode-bidi.c +++ b/src/font/unicode-bidi.c @@ -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 */ diff --git a/src/font/unicode-emoji.c b/src/font/unicode-emoji.c index 6fa40add..b8779e4c 100644 --- a/src/font/unicode-emoji.c +++ b/src/font/unicode-emoji.c @@ -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 */ diff --git a/src/include/unicode-ops.h b/src/include/unicode-ops.h index 19bd6fc3..a5c6683d 100644 --- a/src/include/unicode-ops.h +++ b/src/include/unicode-ops.h @@ -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); diff --git a/src/newgdi/glyphruninfo.c b/src/newgdi/glyphruninfo.c index 10e575b3..bb4e11ba 100644 --- a/src/newgdi/glyphruninfo.c +++ b/src/newgdi/glyphruninfo.c @@ -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; diff --git a/src/newgdi/glyphruninfo.h b/src/newgdi/glyphruninfo.h index 58471f7a..34fd7894 100644 --- a/src/newgdi/glyphruninfo.h +++ b/src/newgdi/glyphruninfo.h @@ -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