diff --git a/src/kernel/timer.c b/src/kernel/timer.c index 389e236d..20a9209a 100644 --- a/src/kernel/timer.c +++ b/src/kernel/timer.c @@ -78,7 +78,7 @@ static pthread_mutex_t timerLock; #define TIMER_UNLOCK() #endif -#ifdef __LINUX__ +#if defined(__LINUX__) && defined(_MGRM_THREADS) # define _MG_USE_BETTER_TIMER #endif /* __LINUX__ */ diff --git a/src/newgdi/glyph-css.c b/src/newgdi/glyph-css.c index 14da2f8e..1c950834 100644 --- a/src/newgdi/glyph-css.c +++ b/src/newgdi/glyph-css.c @@ -48,6 +48,8 @@ #include #include +#define DEBUG + #include "common.h" #include "minigui.h" #include "gdi.h" @@ -73,134 +75,204 @@ #define UCHAR_SPACE 0x0020 #define UCHAR_TAB 0x0009 -struct glyph_break_info { +enum _LBOrder { + LB1, LB2, LB3, LB4, LB5, LB6, LB7, LB8, LB8a, LB9, LB10, + LB11, LB12, LB12a, LB13, LB14, LB15, LB16, LB17, LB18, LB19, + LB20, LB21, LB21a, LB21b, LB22, LB23, LB23a, LB24, LB25, LB26, + LB27, LB28, LB29, LB30, LB30a, LB30b, LB31, +}; + +struct glyph_break_ctxt { DEVFONT* mbc_devfont; DEVFONT* sbc_devfont; Glyph32* gs; Uint8* bs; + Uint8* od; // internal use int len_buff; int n; int base_bt; + Uint8 curr_od; + + LanguageCode cl; + UCharScriptType ws; }; -static int gbinfo_init(struct glyph_break_info* gbinfo, int size) +static int gbctxt_init(struct glyph_break_ctxt* gbctxt, int size) { // pre-allocate buffers - gbinfo->len_buff = size; - if (gbinfo->len_buff < MIN_LEN_GLYPHS) - gbinfo->len_buff = MIN_LEN_GLYPHS; + gbctxt->len_buff = size; + if (gbctxt->len_buff < MIN_LEN_GLYPHS) + gbctxt->len_buff = MIN_LEN_GLYPHS; - gbinfo->gs = (Glyph32*)malloc(sizeof(Glyph32) * gbinfo->len_buff); - gbinfo->bs = (Uint8*)malloc(sizeof(Uint8) * gbinfo->len_buff); - if (gbinfo->gs == NULL || gbinfo->bs == NULL) + gbctxt->gs = (Glyph32*)malloc(sizeof(Glyph32) * gbctxt->len_buff); + gbctxt->bs = (Uint8*)malloc(sizeof(Uint8) * gbctxt->len_buff); + gbctxt->od = (Uint8*)malloc(sizeof(Uint8) * gbctxt->len_buff); + if (gbctxt->gs == NULL || gbctxt->bs == NULL || gbctxt->od == NULL) return 0; - return gbinfo->len_buff; + return gbctxt->len_buff; } -static int gbinfo_push_back(struct glyph_break_info* gbinfo, +static int gbctxt_push_back(struct glyph_break_ctxt* gbctxt, Glyph32 gv, Uint8 bt) { /* realloc buffers if it needs */ - if ((gbinfo->n + 2) >= gbinfo->len_buff) { - gbinfo->len_buff += INC_LEN_GLYPHS; - gbinfo->gs = (Glyph32*)realloc(gbinfo->gs, - sizeof(Glyph32) * gbinfo->len_buff); - gbinfo->bs = (Uint8*)realloc(gbinfo->bs, - sizeof(Uint8) * gbinfo->len_buff); - if (gbinfo->gs == NULL || gbinfo->bs == NULL) + if ((gbctxt->n + 2) >= gbctxt->len_buff) { + gbctxt->len_buff += INC_LEN_GLYPHS; + gbctxt->gs = (Glyph32*)realloc(gbctxt->gs, + sizeof(Glyph32) * gbctxt->len_buff); + gbctxt->bs = (Uint8*)realloc(gbctxt->bs, + sizeof(Uint8) * gbctxt->len_buff); + gbctxt->od = (Uint8*)realloc(gbctxt->od, + sizeof(Uint8) * gbctxt->len_buff); + + if (gbctxt->gs == NULL || gbctxt->bs == NULL || gbctxt->od == NULL) return 0; } - if (gbinfo->n == 0) { + if (gbctxt->n == 0) { // set the before break opportunity - gbinfo->bs[gbinfo->n] = bt; + gbctxt->bs[0] = bt; + gbctxt->od[0] = 0xFF; } else { // set the after break opportunity - gbinfo->gs[gbinfo->n - 1] = gv; - gbinfo->bs[gbinfo->n] = bt; + gbctxt->gs[gbctxt->n - 1] = gv; + gbctxt->bs[gbctxt->n] = bt; + if (bt == BOV_UNKNOWN) + gbctxt->od[gbctxt->n] = 0xFF; + else + gbctxt->od[gbctxt->n] = gbctxt->curr_od; } - gbinfo->n++; - return gbinfo->n; + + gbctxt->n++; + return gbctxt->n; } -static BOOL gbinfo_change_bt_last(struct glyph_break_info* gbinfo, Uint8 bt) +static BOOL gbctxt_change_bt_last(struct glyph_break_ctxt* gbctxt, + Uint8 bt) { - Uint8 org_bt; + if (gbctxt->n < 1) + return FALSE; - org_bt = gbinfo->bs[gbinfo->n]; - if (org_bt == BOV_UNKNOWN) { - gbinfo->bs[gbinfo->n] = bt; + if (gbctxt->bs[gbctxt->n - 1] & BOV_MANDATORY_FLAG) { + _DBG_PRINTF("%s: ignore the change: old one is mandatory\n", + __FUNCTION__); } - else if ((org_bt & BOV_BREAK_FLAG) == (bt & BOV_BREAK_FLAG)) { - gbinfo->bs[gbinfo->n] = bt; + else if (gbctxt->curr_od < gbctxt->od[gbctxt->n - 1]) { + _DBG_PRINTF("%s: changed: curr_od(%d), org_od(%d)\n", + __FUNCTION__, gbctxt->curr_od, gbctxt->od[gbctxt->n - 1]); + gbctxt->bs[gbctxt->n - 1] = bt; + gbctxt->od[gbctxt->n - 1] = gbctxt->curr_od; } else { - gbinfo->bs[gbinfo->n] = bt; - _DBG_PRINTF ("%s: break opportunity conflict\n", __FUNCTIOIN__); + _DBG_PRINTF("%s: ignore the change: curr_od(%d), org_od(%d)\n", + __FUNCTION__, gbctxt->curr_od, gbctxt->od[gbctxt->n - 1]); } return TRUE; } -static BOOL gbinfo_change_bt_before_last(struct glyph_break_info* gbinfo, Uint8 bt) +static BOOL gbctxt_change_bt_before_last(struct glyph_break_ctxt* gbctxt, + Uint8 bt) { - Uint8 org_bt; - - if (gbinfo->n < 1) { + // do not allow to change the first break value + if (gbctxt->n < 3) { return FALSE; } - org_bt = gbinfo->bs[gbinfo->n - 1]; - if (org_bt == BOV_UNKNOWN) { - gbinfo->bs[gbinfo->n - 1] = bt; + // do not apply this bt to the char before last one + if (gbctxt->base_bt != UCHAR_BREAK_UNSET) { + return FALSE; } - else if ((org_bt & BOV_BREAK_FLAG) == (bt & BOV_BREAK_FLAG)) { - gbinfo->bs[gbinfo->n - 1] = bt; + + if (gbctxt->bs[gbctxt->n - 2] & BOV_MANDATORY_FLAG) { + _DBG_PRINTF("%s: ignore the change: old one is mandatory\n", + __FUNCTION__); + } +#if 0 + // Because rules are applied in order, allowing breaks following SP + // in rule LB18 implies that any prohibited break in rules + // LB19–LB30 is equivalent to an indirect break. + else if (gbctxt->curr_od > LB18 + && GLYPH2UCHAR(gbctxt->gs[gbctxt->n - 3]) == UCHAR_SPACE) { + _DBG_PRINTF("%s: ignore the change\n", __FUNCTION__); + } +#endif + else if (gbctxt->curr_od < gbctxt->od[gbctxt->n - 2]) { + _DBG_PRINTF("%s: changed: curr_od(%d), org_od(%d)\n", + __FUNCTION__, gbctxt->curr_od, gbctxt->od[gbctxt->n - 2]); + gbctxt->bs[gbctxt->n - 2] = bt; + gbctxt->od[gbctxt->n - 2] = gbctxt->curr_od; } else { - gbinfo->bs[gbinfo->n - 1] = bt; - _DBG_PRINTF ("%s: break opportunity conflict\n", __FUNCTIOIN__); + _DBG_PRINTF("%s: ignore the change\n", __FUNCTION__); } return TRUE; } -static int get_next_glyph(struct glyph_break_info* gbinfo, +static BOOL gbctxt_change_bt_before_last_sp(struct glyph_break_ctxt* gbctxt, + Uint8 bt) +{ + // do not allow to change the first break value + if (gbctxt->n < 3) { + return FALSE; + } + + if (GLYPH2UCHAR(gbctxt->gs[gbctxt->n - 3]) == UCHAR_SPACE) { + _DBG_PRINTF("%s: force changed: curr_od(%d), org_od(%d)\n", + __FUNCTION__, gbctxt->curr_od, gbctxt->od[gbctxt->n - 2]); + gbctxt->bs[gbctxt->n - 2] = bt; + gbctxt->od[gbctxt->n - 2] = gbctxt->curr_od; + } + else if (gbctxt->curr_od < gbctxt->od[gbctxt->n - 2]) { + _DBG_PRINTF("%s: changed: curr_od(%d), org_od(%d)\n", + __FUNCTION__, gbctxt->curr_od, gbctxt->od[gbctxt->n - 2]); + gbctxt->bs[gbctxt->n - 2] = bt; + gbctxt->od[gbctxt->n - 2] = gbctxt->curr_od; + } + else { + _DBG_PRINTF("%s: ignore the change\n", __FUNCTION__); + } + + return TRUE; +} + +static int get_next_glyph(struct glyph_break_ctxt* gbctxt, const char* mstr, int mstr_len, Glyph32* gv, Uchar32* uc) { int mclen = 0; - if (mstr_len <= 0) + if (mstr_len <= 0 || *mstr == '\0') return 0; - if (gbinfo->mbc_devfont) { - mclen = gbinfo->mbc_devfont->charset_ops->len_first_char + if (gbctxt->mbc_devfont) { + mclen = gbctxt->mbc_devfont->charset_ops->len_first_char ((const unsigned char*)mstr, mstr_len); if (mclen > 0) { - *gv = gbinfo->mbc_devfont->charset_ops->char_glyph_value + *gv = gbctxt->mbc_devfont->charset_ops->char_glyph_value (NULL, 0, (Uint8*)mstr, mclen); *gv = SET_MBC_GLYPH(*gv); - if (gbinfo->mbc_devfont->charset_ops->conv_to_uc32) - *uc = gbinfo->mbc_devfont->charset_ops->conv_to_uc32(*gv); + if (gbctxt->mbc_devfont->charset_ops->conv_to_uc32) + *uc = gbctxt->mbc_devfont->charset_ops->conv_to_uc32(*gv); else *uc = GLYPH2UCHAR(*gv); } } if (*gv == INV_GLYPH_VALUE) { - mclen = gbinfo->sbc_devfont->charset_ops->len_first_char + mclen = gbctxt->sbc_devfont->charset_ops->len_first_char ((const unsigned char*)mstr, mstr_len); if (mclen > 0) { - *gv = gbinfo->sbc_devfont->charset_ops->char_glyph_value + *gv = gbctxt->sbc_devfont->charset_ops->char_glyph_value (NULL, 0, (Uint8*)mstr, mclen); - if (gbinfo->sbc_devfont->charset_ops->conv_to_uc32) - *uc = gbinfo->sbc_devfont->charset_ops->conv_to_uc32(*gv); + if (gbctxt->sbc_devfont->charset_ops->conv_to_uc32) + *uc = gbctxt->sbc_devfont->charset_ops->conv_to_uc32(*gv); else *uc = GLYPH2UCHAR(*gv); } @@ -209,10 +281,11 @@ static int get_next_glyph(struct glyph_break_info* gbinfo, return mclen; } -static UCharBreakType resolve_line_breaking_class( - LanguageCode content_language, UCharScriptType writing_system, - UCharBasicType gc, UCharBreakType bt) +static UCharBreakType resolve_lbc(struct glyph_break_ctxt* gbctxt, Uchar32 uc) { + UCharBasicType gc = UCharGetType(uc); + UCharBreakType bt = UCharGetBreak(uc); + /* * TODO: according to the content language and the writing system * to resolve AI, CB, CJ, SA, SG, and XX into other line breaking classes. @@ -247,7 +320,7 @@ static UCharBreakType resolve_line_breaking_class( return bt; } -static int collapse_space(struct glyph_break_info* gbinfo, +static int collapse_space(struct glyph_break_ctxt* gbctxt, const char* mstr, int mstr_len) { Uchar32 uc; @@ -258,7 +331,7 @@ static int collapse_space(struct glyph_break_info* gbinfo, int mclen; Glyph32 gv; - mclen = get_next_glyph(gbinfo, mstr, mstr_len, + mclen = get_next_glyph(gbctxt, mstr, mstr_len, &gv, &uc); if (mclen == 0) break; @@ -267,13 +340,13 @@ static int collapse_space(struct glyph_break_info* gbinfo, mstr_len -= mclen; cosumed += mclen; - bt = UCharGetBreak(uc); + bt = resolve_lbc(gbctxt, uc); } while (bt == UCHAR_BREAK_SPACE || uc == UCHAR_TAB); return cosumed; } -static int collapse_line_feed(struct glyph_break_info* gbinfo, +static int collapse_line_feed(struct glyph_break_ctxt* gbctxt, const char* mstr, int mstr_len) { int cosumed = 0; @@ -281,15 +354,15 @@ static int collapse_line_feed(struct glyph_break_info* gbinfo, Glyph32 gv; Uchar32 uc; - mclen = get_next_glyph(gbinfo, mstr, mstr_len, + mclen = get_next_glyph(gbctxt, mstr, mstr_len, &gv, &uc); - if (mclen > 0 && UCharGetBreak(uc) == UCHAR_BREAK_LINE_FEED) + if (mclen > 0 && resolve_lbc(gbctxt, uc) == UCHAR_BREAK_LINE_FEED) cosumed = mclen; return cosumed; } -static int check_glyphs_following_zw(struct glyph_break_info* gbinfo, +static int check_glyphs_following_zw(struct glyph_break_ctxt* gbctxt, const char* mstr, int mstr_len) { int cosumed = 0; @@ -299,15 +372,15 @@ static int check_glyphs_following_zw(struct glyph_break_info* gbinfo, Glyph32 gv; Uchar32 uc; - mclen = get_next_glyph(gbinfo, mstr, mstr_len, + mclen = get_next_glyph(gbctxt, mstr, mstr_len, &gv, &uc); if (mclen > 0) { mstr += mclen; mstr_len -= mclen; cosumed += mclen; - if (UCharGetBreak(uc) == UCHAR_BREAK_SPACE) { - gbinfo_push_back(gbinfo, gv, BOV_NOTALLOWED); + if (resolve_lbc(gbctxt, uc) == UCHAR_BREAK_SPACE) { + gbctxt_push_back(gbctxt, gv, BOV_NOTALLOWED); } else { break; @@ -321,98 +394,98 @@ static int check_glyphs_following_zw(struct glyph_break_info* gbinfo, return cosumed; } -static int is_next_glyph_bt(struct glyph_break_info* gbinfo, +static int is_next_glyph_bt(struct glyph_break_ctxt* gbctxt, const char* mstr, int mstr_len, Glyph32* gv, Uchar32* uc, UCharBreakType bt) { int mclen; - mclen = get_next_glyph(gbinfo, mstr, mstr_len, + mclen = get_next_glyph(gbctxt, mstr, mstr_len, gv, uc); - if (mclen > 0 && UCharGetBreak(*uc) == bt) + if (mclen > 0 && resolve_lbc(gbctxt, *uc) == bt) return mclen; return 0; } -static inline int is_next_glyph_sp(struct glyph_break_info* gbinfo, +static inline int is_next_glyph_sp(struct glyph_break_ctxt* gbctxt, const char* mstr, int mstr_len, Glyph32* gv, Uchar32* uc) { - return is_next_glyph_bt(gbinfo, mstr, mstr_len, gv, uc, + return is_next_glyph_bt(gbctxt, mstr, mstr_len, gv, uc, UCHAR_BREAK_SPACE); } -static inline int is_next_glyph_gl(struct glyph_break_info* gbinfo, +static inline int is_next_glyph_gl(struct glyph_break_ctxt* gbctxt, const char* mstr, int mstr_len, Glyph32* gv, Uchar32* uc) { - return is_next_glyph_bt(gbinfo, mstr, mstr_len, gv, uc, + return is_next_glyph_bt(gbctxt, mstr, mstr_len, gv, uc, UCHAR_BREAK_NON_BREAKING_GLUE); } -static inline int is_next_glyph_hl(struct glyph_break_info* gbinfo, +static inline int is_next_glyph_hl(struct glyph_break_ctxt* gbctxt, const char* mstr, int mstr_len, Glyph32*gv, Uchar32 *uc) { - return is_next_glyph_bt(gbinfo, mstr, mstr_len, gv, uc, + return is_next_glyph_bt(gbctxt, mstr, mstr_len, gv, uc, UCHAR_BREAK_HEBREW_LETTER); } -static inline int is_next_glyph_in(struct glyph_break_info* gbinfo, +static inline int is_next_glyph_in(struct glyph_break_ctxt* gbctxt, const char* mstr, int mstr_len, Glyph32*gv, Uchar32 *uc) { - return is_next_glyph_bt(gbinfo, mstr, mstr_len, gv, uc, + return is_next_glyph_bt(gbctxt, mstr, mstr_len, gv, uc, UCHAR_BREAK_INSEPARABLE); } -static inline int is_next_glyph_nu(struct glyph_break_info* gbinfo, +static inline int is_next_glyph_nu(struct glyph_break_ctxt* gbctxt, const char* mstr, int mstr_len, Glyph32*gv, Uchar32 *uc) { - return is_next_glyph_bt(gbinfo, mstr, mstr_len, gv, uc, + return is_next_glyph_bt(gbctxt, mstr, mstr_len, gv, uc, UCHAR_BREAK_NUMERIC); } -static inline int is_next_glyph_po(struct glyph_break_info* gbinfo, +static inline int is_next_glyph_po(struct glyph_break_ctxt* gbctxt, const char* mstr, int mstr_len, Glyph32*gv, Uchar32 *uc) { - return is_next_glyph_bt(gbinfo, mstr, mstr_len, gv, uc, + return is_next_glyph_bt(gbctxt, mstr, mstr_len, gv, uc, UCHAR_BREAK_POSTFIX); } -static inline int is_next_glyph_pr(struct glyph_break_info* gbinfo, +static inline int is_next_glyph_pr(struct glyph_break_ctxt* gbctxt, const char* mstr, int mstr_len, Glyph32*gv, Uchar32 *uc) { - return is_next_glyph_bt(gbinfo, mstr, mstr_len, gv, uc, + return is_next_glyph_bt(gbctxt, mstr, mstr_len, gv, uc, UCHAR_BREAK_PREFIX); } -static inline int is_next_glyph_op(struct glyph_break_info* gbinfo, +static inline int is_next_glyph_op(struct glyph_break_ctxt* gbctxt, const char* mstr, int mstr_len, Glyph32*gv, Uchar32 *uc) { - return is_next_glyph_bt(gbinfo, mstr, mstr_len, gv, uc, + return is_next_glyph_bt(gbctxt, mstr, mstr_len, gv, uc, UCHAR_BREAK_OPEN_PUNCTUATION); } -static inline int is_next_glyph_jt(struct glyph_break_info* gbinfo, +static inline int is_next_glyph_jt(struct glyph_break_ctxt* gbctxt, const char* mstr, int mstr_len, Glyph32*gv, Uchar32 *uc) { - return is_next_glyph_bt(gbinfo, mstr, mstr_len, gv, uc, + return is_next_glyph_bt(gbctxt, mstr, mstr_len, gv, uc, UCHAR_BREAK_HANGUL_T_JAMO); } -static int is_next_glyph_em(struct glyph_break_info* gbinfo, +static int is_next_glyph_em(struct glyph_break_ctxt* gbctxt, const char* mstr, int mstr_len, Glyph32*gv, Uchar32 *uc) { - return is_next_glyph_bt(gbinfo, mstr, mstr_len, gv, uc, + return is_next_glyph_bt(gbctxt, mstr, mstr_len, gv, uc, UCHAR_BREAK_EMOJI_MODIFIER); } -static int is_next_glyph_cm_zwj(struct glyph_break_info* gbinfo, +static int is_next_glyph_cm_zwj(struct glyph_break_ctxt* gbctxt, const char* mstr, int mstr_len, Glyph32* gv, Uchar32* uc) { int mclen; - mclen = get_next_glyph(gbinfo, mstr, mstr_len, gv, uc); + mclen = get_next_glyph(gbctxt, mstr, mstr_len, gv, uc); if (mclen > 0) { - UCharBreakType bt = UCharGetBreak(*uc); + UCharBreakType bt = resolve_lbc(gbctxt, *uc); if (bt == UCHAR_BREAK_COMBINING_MARK || bt == UCHAR_BREAK_ZERO_WIDTH_JOINER) return mclen; @@ -421,15 +494,15 @@ static int is_next_glyph_cm_zwj(struct glyph_break_info* gbinfo, return 0; } -static int is_next_glyph_hy_or_ba(struct glyph_break_info* gbinfo, +static int is_next_glyph_hy_or_ba(struct glyph_break_ctxt* gbctxt, const char* mstr, int mstr_len, Glyph32*gv, Uchar32 *uc) { int mclen; - mclen = get_next_glyph(gbinfo, mstr, mstr_len, + mclen = get_next_glyph(gbctxt, mstr, mstr_len, gv, uc); if (mclen > 0) { - UCharBreakType bt = UCharGetBreak(*uc); + UCharBreakType bt = resolve_lbc(gbctxt, *uc); if (bt == UCHAR_BREAK_HYPHEN || bt == UCHAR_BREAK_AFTER) return mclen; @@ -438,14 +511,14 @@ static int is_next_glyph_hy_or_ba(struct glyph_break_info* gbinfo, return 0; } -static int is_next_glyph_al_hl(struct glyph_break_info* gbinfo, +static int is_next_glyph_al_hl(struct glyph_break_ctxt* gbctxt, const char* mstr, int mstr_len, Glyph32*gv, Uchar32 *uc) { int mclen; - mclen = get_next_glyph(gbinfo, mstr, mstr_len, + mclen = get_next_glyph(gbctxt, mstr, mstr_len, gv, uc); if (mclen > 0) { - UCharBreakType bt = UCharGetBreak(*uc); + UCharBreakType bt = resolve_lbc(gbctxt, *uc); if (bt == UCHAR_BREAK_HEBREW_LETTER || bt == UCHAR_BREAK_ALPHABETIC) return mclen; } @@ -453,14 +526,14 @@ static int is_next_glyph_al_hl(struct glyph_break_info* gbinfo, return 0; } -static int is_next_glyph_pr_po(struct glyph_break_info* gbinfo, +static int is_next_glyph_pr_po(struct glyph_break_ctxt* gbctxt, const char* mstr, int mstr_len, Glyph32*gv, Uchar32 *uc) { int mclen; - mclen = get_next_glyph(gbinfo, mstr, mstr_len, + mclen = get_next_glyph(gbctxt, mstr, mstr_len, gv, uc); if (mclen > 0) { - UCharBreakType bt = UCharGetBreak(*uc); + UCharBreakType bt = resolve_lbc(gbctxt, *uc); if (bt == UCHAR_BREAK_PREFIX || bt == UCHAR_BREAK_POSTFIX) return mclen; } @@ -468,14 +541,14 @@ static int is_next_glyph_pr_po(struct glyph_break_info* gbinfo, return 0; } -static int is_next_glyph_id_eb_em(struct glyph_break_info* gbinfo, +static int is_next_glyph_id_eb_em(struct glyph_break_ctxt* gbctxt, const char* mstr, int mstr_len, Glyph32*gv, Uchar32 *uc) { int mclen; - mclen = get_next_glyph(gbinfo, mstr, mstr_len, + mclen = get_next_glyph(gbctxt, mstr, mstr_len, gv, uc); if (mclen > 0) { - UCharBreakType bt = UCharGetBreak(*uc); + UCharBreakType bt = resolve_lbc(gbctxt, *uc); if (bt == UCHAR_BREAK_IDEOGRAPHIC || bt == UCHAR_BREAK_EMOJI_BASE || bt == UCHAR_BREAK_EMOJI_MODIFIER) @@ -485,14 +558,14 @@ static int is_next_glyph_id_eb_em(struct glyph_break_info* gbinfo, return 0; } -static int is_next_glyph_jl_jv_jt_h2_h3(struct glyph_break_info* gbinfo, +static int is_next_glyph_jl_jv_jt_h2_h3(struct glyph_break_ctxt* gbctxt, const char* mstr, int mstr_len, Glyph32*gv, Uchar32 *uc) { int mclen; - mclen = get_next_glyph(gbinfo, mstr, mstr_len, + mclen = get_next_glyph(gbctxt, mstr, mstr_len, gv, uc); if (mclen > 0) { - UCharBreakType bt = UCharGetBreak(*uc); + UCharBreakType bt = resolve_lbc(gbctxt, *uc); if (bt == UCHAR_BREAK_HANGUL_L_JAMO || bt == UCHAR_BREAK_HANGUL_V_JAMO || bt == UCHAR_BREAK_HANGUL_T_JAMO @@ -504,14 +577,14 @@ static int is_next_glyph_jl_jv_jt_h2_h3(struct glyph_break_info* gbinfo, return 0; } -static int is_next_glyph_jl_jv_h2_h3(struct glyph_break_info* gbinfo, +static int is_next_glyph_jl_jv_h2_h3(struct glyph_break_ctxt* gbctxt, const char* mstr, int mstr_len, Glyph32*gv, Uchar32 *uc) { int mclen; - mclen = get_next_glyph(gbinfo, mstr, mstr_len, + mclen = get_next_glyph(gbctxt, mstr, mstr_len, gv, uc); if (mclen > 0) { - UCharBreakType bt = UCharGetBreak(*uc); + UCharBreakType bt = resolve_lbc(gbctxt, *uc); if (bt == UCHAR_BREAK_HANGUL_L_JAMO || bt == UCHAR_BREAK_HANGUL_V_JAMO || bt == UCHAR_BREAK_HANGUL_LV_SYLLABLE @@ -522,14 +595,14 @@ static int is_next_glyph_jl_jv_h2_h3(struct glyph_break_info* gbinfo, return 0; } -static int is_next_glyph_jv_jt(struct glyph_break_info* gbinfo, +static int is_next_glyph_jv_jt(struct glyph_break_ctxt* gbctxt, const char* mstr, int mstr_len, Glyph32*gv, Uchar32 *uc) { int mclen; - mclen = get_next_glyph(gbinfo, mstr, mstr_len, + mclen = get_next_glyph(gbctxt, mstr, mstr_len, gv, uc); if (mclen > 0) { - UCharBreakType bt = UCharGetBreak(*uc); + UCharBreakType bt = resolve_lbc(gbctxt, *uc); if (bt == UCHAR_BREAK_HANGUL_V_JAMO || bt == UCHAR_BREAK_HANGUL_T_JAMO) return mclen; @@ -538,14 +611,14 @@ static int is_next_glyph_jv_jt(struct glyph_break_info* gbinfo, return 0; } -static int is_next_glyph_al_hl_nu(struct glyph_break_info* gbinfo, +static int is_next_glyph_al_hl_nu(struct glyph_break_ctxt* gbctxt, const char* mstr, int mstr_len, Glyph32*gv, Uchar32 *uc) { int mclen; - mclen = get_next_glyph(gbinfo, mstr, mstr_len, + mclen = get_next_glyph(gbctxt, mstr, mstr_len, gv, uc); if (mclen > 0) { - UCharBreakType bt = UCharGetBreak(*uc); + UCharBreakType bt = resolve_lbc(gbctxt, *uc); if (bt == UCHAR_BREAK_HEBREW_LETTER || bt == UCHAR_BREAK_ALPHABETIC || bt == UCHAR_BREAK_NUMERIC) @@ -556,22 +629,22 @@ static int is_next_glyph_al_hl_nu(struct glyph_break_info* gbinfo, } #if 0 -static BOOL is_next_glyph_zw(struct glyph_break_info* gbinfo, +static BOOL is_next_glyph_zw(struct glyph_break_ctxt* gbctxt, const char* mstr, int mstr_len) { int mclen; Glyph32 gv; Uchar32 uc; - mclen = get_next_glyph(gbinfo, mstr, mstr_len, + mclen = get_next_glyph(gbctxt, mstr, mstr_len, &gv, &uc); - if (mclen > 0 && UCharGetBreak(uc) == UCHAR_BREAK_ZERO_WIDTH_SPACE) + if (mclen > 0 && resolve_lbc(gbctxt, uc) == UCHAR_BREAK_ZERO_WIDTH_SPACE) return TRUE; return FALSE; } -static int check_subsequent_cm_or_zwj(struct glyph_break_info* gbinfo, +static int check_subsequent_cm_or_zwj(struct glyph_break_ctxt* gbctxt, const char* mstr, int mstr_len) { int cosumed = 0; @@ -579,12 +652,12 @@ static int check_subsequent_cm_or_zwj(struct glyph_break_info* gbinfo, Glyph32 gv; Uchar32 uc; - while ((mclen = is_next_glyph_cm_zwj(gbinfo, + while ((mclen = is_next_glyph_cm_zwj(gbctxt, mstr, mstr_len, &gv, &uc)) > 0) { // FIXME: CM/ZWJ should have the same break class as // its base character. - gbinfo_push_back(gbinfo, gv, BOV_BEFORE_NOTALLOWED); + gbctxt_push_back(gbctxt, gv, BOV_BEFORE_NOTALLOWED); cosumed += mclen; } @@ -593,7 +666,7 @@ static int check_subsequent_cm_or_zwj(struct glyph_break_info* gbinfo, } #endif -static int check_subsequent_sp(struct glyph_break_info* gbinfo, +static int check_subsequent_sp(struct glyph_break_ctxt* gbctxt, const char* mstr, int mstr_len) { int cosumed = 0; @@ -601,15 +674,17 @@ static int check_subsequent_sp(struct glyph_break_info* gbinfo, Glyph32 gv; Uchar32 uc; - while ((mclen = is_next_glyph_sp(gbinfo, mstr, mstr_len, &gv, &uc)) > 0) { - gbinfo_push_back(gbinfo, gv, BOV_NOTALLOWED); + while ((mclen = is_next_glyph_sp(gbctxt, mstr, mstr_len, &gv, &uc)) > 0) { + gbctxt_push_back(gbctxt, gv, BOV_NOTALLOWED); + mstr += mclen; + mstr_len -= mclen; cosumed += mclen; } return cosumed; } -static int is_subsequent_sps_and_end_bt(struct glyph_break_info* gbinfo, +static int is_subsequent_sps_and_end_bt(struct glyph_break_ctxt* gbctxt, const char* mstr, int mstr_len, UCharBreakType end_bt) { Glyph32 gv; @@ -617,10 +692,10 @@ static int is_subsequent_sps_and_end_bt(struct glyph_break_info* gbinfo, int mclen; while (mstr_len > 0 && *mstr != '\0') { - mclen = get_next_glyph(gbinfo, mstr, mstr_len, + mclen = get_next_glyph(gbctxt, mstr, mstr_len, &gv, &uc); if (mclen > 0) { - UCharBreakType bt = UCharGetBreak(uc); + UCharBreakType bt = resolve_lbc(gbctxt, uc); if (bt == UCHAR_BREAK_SPACE) { mstr += mclen; mstr_len -= mclen; @@ -637,8 +712,8 @@ static int is_subsequent_sps_and_end_bt(struct glyph_break_info* gbinfo, return FALSE; } -static int check_subsequent_sps_and_end_bt(struct glyph_break_info* gbinfo, - const char* mstr, int mstr_len, UCharBreakType end_bt) +static int check_subsequent_sps_and_end_bt(struct glyph_break_ctxt* gbctxt, + const char* mstr, int mstr_len, BOOL col_sp, UCharBreakType end_bt) { int cosumed = 0; int mclen; @@ -646,15 +721,16 @@ static int check_subsequent_sps_and_end_bt(struct glyph_break_info* gbinfo, Uchar32 uc; while (mstr_len > 0 && *mstr != '\0') { - mclen = get_next_glyph(gbinfo, mstr, mstr_len, + mclen = get_next_glyph(gbctxt, mstr, mstr_len, &gv, &uc); if (mclen > 0) { - UCharBreakType bt = UCharGetBreak(uc); + UCharBreakType bt = resolve_lbc(gbctxt, uc); if (bt == UCHAR_BREAK_SPACE) { mstr += mclen; mstr_len -= mclen; cosumed += mclen; - gbinfo_push_back(gbinfo, gv, BOV_NOTALLOWED); + if (!col_sp) + gbctxt_push_back(gbctxt, gv, BOV_NOTALLOWED); continue; } else if (bt == end_bt) { @@ -668,7 +744,7 @@ static int check_subsequent_sps_and_end_bt(struct glyph_break_info* gbinfo, return cosumed; } -static BOOL is_even_nubmer_of_subsequent_ri(struct glyph_break_info* gbinfo, +static BOOL is_even_nubmer_of_subsequent_ri(struct glyph_break_ctxt* gbctxt, const char* mstr, int mstr_len) { int nr = 0; @@ -677,10 +753,10 @@ static BOOL is_even_nubmer_of_subsequent_ri(struct glyph_break_info* gbinfo, Uchar32 uc; while (mstr_len > 0 && *mstr != '\0') { - mclen = get_next_glyph(gbinfo, mstr, mstr_len, &gv, &uc); + mclen = get_next_glyph(gbctxt, mstr, mstr_len, &gv, &uc); mstr_len -= mclen; - if (mclen > 0 && UCharGetBreak(uc) == UCHAR_BREAK_REGIONAL_INDICATOR) { + if (mclen > 0 && resolve_lbc(gbctxt, uc) == UCHAR_BREAK_REGIONAL_INDICATOR) { nr++; continue; } @@ -694,7 +770,7 @@ static BOOL is_even_nubmer_of_subsequent_ri(struct glyph_break_info* gbinfo, return FALSE; } -static int check_even_nubmer_of_subsequent_ri(struct glyph_break_info* gbinfo, +static int check_even_nubmer_of_subsequent_ri(struct glyph_break_ctxt* gbctxt, const char* mstr, int mstr_len) { int nr = 0; @@ -704,14 +780,15 @@ static int check_even_nubmer_of_subsequent_ri(struct glyph_break_info* gbinfo, Uchar32 uc; while (mstr_len > 0 && *mstr != '\0') { - mclen = get_next_glyph(gbinfo, mstr, mstr_len, &gv, &uc); - if (mclen > 0 && UCharGetBreak(uc) == UCHAR_BREAK_REGIONAL_INDICATOR) { + mclen = get_next_glyph(gbctxt, mstr, mstr_len, &gv, &uc); + if (mclen > 0 + && resolve_lbc(gbctxt, uc) == UCHAR_BREAK_REGIONAL_INDICATOR) { mstr += mclen; mstr_len -= mclen; cosumed += mclen; nr++; - gbinfo_push_back(gbinfo, gv, BOV_NOTALLOWED); + gbctxt_push_back(gbctxt, gv, BOV_NOTALLOWED); continue; } else @@ -726,16 +803,23 @@ int GUIAPI GetGlyphsByRules(LOGFONT* logfont, const char* mstr, int mstr_len, Uint32 space_rule, Uint32 trans_rule, Glyph32** glyphs, Uint8** break_oppos, int* nr_glyphs) { - struct glyph_break_info gbinfo; + struct glyph_break_ctxt gbctxt; int cosumed = 0; + BOOL col_sp = FALSE; - gbinfo.mbc_devfont = logfont->mbc_devfont; - gbinfo.sbc_devfont = logfont->sbc_devfont; - gbinfo.gs = NULL; - gbinfo.bs = NULL; - gbinfo.len_buff = 0; - gbinfo.n = 0; - gbinfo.base_bt = UCHAR_BREAK_UNSET; + // CSS: collapses space according to space rule + if (space_rule == WSR_NORMAL || space_rule == WSR_NOWRAP) + col_sp = TRUE; + + gbctxt.mbc_devfont = logfont->mbc_devfont; + gbctxt.sbc_devfont = logfont->sbc_devfont; + gbctxt.gs = NULL; + gbctxt.bs = NULL; + gbctxt.len_buff = 0; + gbctxt.n = 0; + gbctxt.base_bt = UCHAR_BREAK_UNSET; + gbctxt.cl = content_language; + gbctxt.ws = writing_system; *glyphs = NULL; *break_oppos = NULL; @@ -744,30 +828,35 @@ int GUIAPI GetGlyphsByRules(LOGFONT* logfont, const char* mstr, int mstr_len, if (mstr_len == 0) return 0; - if (gbinfo_init(&gbinfo, mstr_len >> 1) <= 0) { + if (gbctxt_init(&gbctxt, mstr_len >> 1) <= 0) { goto error; } - while (mstr_len > 0) { + while (TRUE) { Glyph32 gv; Uchar32 uc; - int mclen; + int mclen = 0; UCharBreakType bt; Uint8 bo; Glyph32 next_gv; Uchar32 next_uc; - int next_mclen; + int next_mclen = 0; - mclen = get_next_glyph(&gbinfo, mstr, mstr_len, &gv, &uc); + mclen = get_next_glyph(&gbctxt, mstr, mstr_len, &gv, &uc); if (mclen == 0) { // badly encoded or end of text break; } + mstr += mclen; + mstr_len -= mclen; + + _DBG_PRINTF ("Got a glyph: %04X\n", uc); if ((space_rule == WSR_NORMAL || space_rule == WSR_NOWRAP || space_rule == WSR_PRE_LINE) && uc == UCHAR_TAB) { // Every tab is converted to a space (U+0020). + _DBG_PRINTF ("CSS: Every tab is converted to a space (U+0020)\n"); uc = UCHAR_SPACE; if (IS_MBC_GLYPH(gv)) gv = SET_MBC_GLYPH(UCHAR_SPACE); @@ -780,19 +869,16 @@ int GUIAPI GetGlyphsByRules(LOGFONT* logfont, const char* mstr, int mstr_len, */ // LB1 Resolve line breaking class - bt = resolve_line_breaking_class(content_language, writing_system, - UCharGetType(uc), UCharGetBreak(uc)); + gbctxt.curr_od = LB1; + bt = resolve_lbc(&gbctxt, uc); /* Start and end of text */ // LB2 Never break at the start of text. - if (gbinfo.n == 0) { - if (gbinfo_push_back(&gbinfo, 0, BOV_NOTALLOWED) == 0) + if (gbctxt.n == 0) { + _DBG_PRINTF ("LB2 Never break at the start of text\n"); + gbctxt.curr_od = LB2; + if (gbctxt_push_back(&gbctxt, 0, BOV_NOTALLOWED) == 0) goto error; - goto next_glyph; - } - // LB3 Always break at the end of text. - else if (*mstr == '\0') { - break; } // Only break at forced line breaks. @@ -804,29 +890,45 @@ int GUIAPI GetGlyphsByRules(LOGFONT* logfont, const char* mstr, int mstr_len, bo = BOV_UNKNOWN; // Set default break opportunity of the current glyph - if (gbinfo_push_back(&gbinfo, gv, bo) == 0) + if (gbctxt_push_back(&gbctxt, gv, bo) == 0) goto error; + // LB3 Always break at the end of text. + if (get_next_glyph(&gbctxt, mstr, mstr_len, &next_gv, &next_uc) == 0) { + _DBG_PRINTF ("LB3 Always break at the end of text\n"); + gbctxt.curr_od = LB3; + gbctxt_change_bt_last(&gbctxt, BOV_MANDATORY); + } + /* Mandatory breaks */ // LB4 Always break after hard line breaks - // LB6 Do not break before hard line breaks. + // LB6 Do not break before hard line breaks if (bt == UCHAR_BREAK_MANDATORY) { - gbinfo_change_bt_last(&gbinfo, BOV_MANDATORY); - gbinfo_change_bt_before_last(&gbinfo, BOV_NOTALLOWED); + _DBG_PRINTF ("LB4 Always break after hard line breaks\n"); + gbctxt.curr_od = LB4; + gbctxt_change_bt_last(&gbctxt, BOV_MANDATORY); + _DBG_PRINTF ("LB6 Do not break before hard line breaks\n"); + gbctxt.curr_od = LB6; + gbctxt_change_bt_before_last(&gbctxt, BOV_NOTALLOWED); } // LB5 Treat CR followed by LF, as well as CR, LF, // and NL as hard line breaks. // LB6 Do not break before hard line breaks. else if (bt == UCHAR_BREAK_CARRIAGE_RETURN) { - mclen += collapse_line_feed(&gbinfo, mstr, mstr_len); + next_mclen = collapse_line_feed(&gbctxt, mstr, mstr_len); - if (space_rule == WSR_NORMAL || space_rule == WSR_NOWRAP) + if (col_sp) // Collapse new lines bo = BOV_NOTALLOWED; else bo = BOV_MANDATORY; - gbinfo_change_bt_last(&gbinfo, bo); - gbinfo_change_bt_before_last(&gbinfo, BOV_NOTALLOWED); + + _DBG_PRINTF ("LB5 Treat CR followed by LF, as well as CR, LF, and NL as hard line breaks.\n"); + gbctxt.curr_od = LB5; + gbctxt_change_bt_last(&gbctxt, bo); + _DBG_PRINTF ("LB6 Do not break before hard line breaks\n"); + gbctxt.curr_od = LB6; + gbctxt_change_bt_before_last(&gbctxt, BOV_NOTALLOWED); } // LB5 Treat CR followed by LF, as well as CR, LF, // and NL as hard line breaks. @@ -834,33 +936,46 @@ int GUIAPI GetGlyphsByRules(LOGFONT* logfont, const char* mstr, int mstr_len, else if (bt == UCHAR_BREAK_LINE_FEED || bt == UCHAR_BREAK_NEXT_LINE) { - if (space_rule == WSR_NORMAL || space_rule == WSR_NOWRAP) + if (col_sp) // Collapse new lines bo = BOV_NOTALLOWED; else bo = BOV_MANDATORY; - gbinfo_change_bt_last(&gbinfo, bo); - gbinfo_change_bt_before_last(&gbinfo, BOV_NOTALLOWED); + _DBG_PRINTF ("LB5 Treat CR followed by LF, as well as CR, LF, and NL as hard line breaks.\n"); + gbctxt.curr_od = LB5; + gbctxt_change_bt_last(&gbctxt, bo); + _DBG_PRINTF ("LB6 Do not break before hard line breaks\n"); + gbctxt.curr_od = LB6; + gbctxt_change_bt_before_last(&gbctxt, BOV_NOTALLOWED); } /* Explicit breaks and non-breaks */ - // LB7: Do not break before spaces or zero width space. - if (bt == UCHAR_BREAK_SPACE + // LB7 Do not break before spaces or zero width space. + else if (bt == UCHAR_BREAK_SPACE || bt == UCHAR_BREAK_ZERO_WIDTH_SPACE) { - gbinfo_change_bt_before_last(&gbinfo, BOV_NOTALLOWED); - if (space_rule == WSR_NORMAL || space_rule == WSR_NOWRAP) { - // CSS: collapses space according to space rule - mclen += collapse_space(&gbinfo, mstr, mstr_len); + _DBG_PRINTF ("LB7 Do not break before spaces or zero width space\n"); + gbctxt.curr_od = LB7; + gbctxt_change_bt_before_last(&gbctxt, BOV_NOTALLOWED); + + if (col_sp) { + next_mclen = collapse_space(&gbctxt, mstr, mstr_len); } } // LB8: Break before any character following a zero-width space, // even if one or more spaces intervene. - if (bt == UCHAR_BREAK_ZERO_WIDTH_SPACE) { - gbinfo_change_bt_last(&gbinfo, BOV_MANDATORY); - mclen += check_glyphs_following_zw(&gbinfo, - mstr + mclen, mstr_len - mclen); + else if (bt == UCHAR_BREAK_ZERO_WIDTH_SPACE) { + _DBG_PRINTF ("LB8: Break before any character following a zero-width space...\n"); + gbctxt.curr_od = LB8; + gbctxt_change_bt_last(&gbctxt, BOV_ALLOWED); + if (col_sp) { + // CSS: collapses space according to space rule + next_mclen = collapse_space(&gbctxt, mstr, mstr_len); + } + else { + next_mclen = check_glyphs_following_zw(&gbctxt, mstr, mstr_len); + } } // Only break at forced line breaks. @@ -872,46 +987,50 @@ int GUIAPI GetGlyphsByRules(LOGFONT* logfont, const char* mstr, int mstr_len, // LB8a Do not break between a zero width joiner and an ideograph, // emoji base or emoji modifier. if (bt == UCHAR_BREAK_ZERO_WIDTH_JOINER - && (next_mclen = is_next_glyph_id_eb_em(&gbinfo, - mstr + mclen, mstr_len - mclen, - &next_gv, &next_uc)) > 0) { + && is_next_glyph_id_eb_em(&gbctxt, + mstr, mstr_len, &next_gv, &next_uc) > 0) { - gbinfo_change_bt_last(&gbinfo, BOV_NOTALLOWED); + _DBG_PRINTF ("LB8a Do not break between a zero width joiner and ID, EB, EM\n"); + gbctxt.curr_od = LB8a; + gbctxt_change_bt_last(&gbctxt, BOV_NOTALLOWED); } /* Combining marks */ - // LB9: Do not break a combining character sequence; + // LB9 Do not break a combining character sequence; // treat it as if it has the line breaking class of // the base character in all of the following rules. // Treat ZWJ as if it were CM. // CM/ZWJ should have the same break class as // its base character. - if ((bt == UCHAR_BREAK_COMBINING_MARK - || bt == UCHAR_BREAK_ZERO_WIDTH_JOINER) - && gbinfo.base_bt != UCHAR_BREAK_UNSET) { - bt = gbinfo.base_bt; - } else if (bt != UCHAR_BREAK_MANDATORY && bt != UCHAR_BREAK_CARRIAGE_RETURN && bt != UCHAR_BREAK_LINE_FEED && bt != UCHAR_BREAK_NEXT_LINE && bt != UCHAR_BREAK_SPACE && bt != UCHAR_BREAK_ZERO_WIDTH_SPACE - && (is_next_glyph_cm_zwj(&gbinfo, - mstr + mclen, mstr_len - mclen, &next_gv, &next_uc)) > 0) { - bo = BOV_NOTALLOWED; - gbinfo_change_bt_last(&gbinfo, bo); + && is_next_glyph_cm_zwj(&gbctxt, + mstr, mstr_len, &next_gv, &next_uc) > 0) { + + _DBG_PRINTF ("LB9 Do not break a combining character sequence\n"); + gbctxt.curr_od = LB9; + gbctxt_change_bt_last(&gbctxt, BOV_NOTALLOWED); // CM/ZWJ should have the same break class as // its base character. - gbinfo.base_bt = bt; + gbctxt.base_bt = bt; + goto next_glyph; } - else if (gbinfo.base_bt != UCHAR_BREAK_UNSET) { - gbinfo.base_bt = UCHAR_BREAK_UNSET; + else if ((bt == UCHAR_BREAK_COMBINING_MARK + || bt == UCHAR_BREAK_ZERO_WIDTH_JOINER) + && gbctxt.base_bt != UCHAR_BREAK_UNSET) { + _DBG_PRINTF ("LB9 CM/ZWJ should have the same break class as its base character\n"); + bt = gbctxt.base_bt; } // LB10 Treat any remaining combining mark or ZWJ as AL. - else if (bt == UCHAR_BREAK_COMBINING_MARK - || bt == UCHAR_BREAK_ZERO_WIDTH_JOINER) { + else if ((bt == UCHAR_BREAK_COMBINING_MARK + || bt == UCHAR_BREAK_ZERO_WIDTH_JOINER) + && gbctxt.base_bt == UCHAR_BREAK_UNSET) { + _DBG_PRINTF ("LB10 Treat any remaining combining mark or ZWJ as AL\n"); bt = UCHAR_BREAK_ALPHABETIC; } @@ -920,103 +1039,122 @@ int GUIAPI GetGlyphsByRules(LOGFONT* logfont, const char* mstr, int mstr_len, // and related characters. if (bt == UCHAR_BREAK_WORD_JOINER) { bo = BOV_NOTALLOWED; - gbinfo_change_bt_last(&gbinfo, bo); - gbinfo_change_bt_before_last(&gbinfo, bo); + _DBG_PRINTF ("LB11 Do not break before or after Word joiner and ...\n"); + gbctxt.curr_od = LB11; + gbctxt_change_bt_last(&gbctxt, bo); + gbctxt_change_bt_before_last(&gbctxt, bo); } // LB12 Do not break after NBSP and related characters. else if (bt == UCHAR_BREAK_NON_BREAKING_GLUE) { - bo = BOV_NOTALLOWED; - gbinfo_change_bt_last(&gbinfo, bo); + _DBG_PRINTF ("LB12 Do not break after NBSP and related characters\n"); + gbctxt.curr_od = LB12; + gbctxt_change_bt_last(&gbctxt, BOV_NOTALLOWED); } /* Non-breaking characters */ // LB12a Do not break before NBSP and related characters, // except after spaces and hyphens. - if (bt != UCHAR_BREAK_SPACE + else if (bt != UCHAR_BREAK_SPACE && bt != UCHAR_BREAK_AFTER && bt != UCHAR_BREAK_HYPHEN - && (next_mclen = is_next_glyph_gl(&gbinfo, - mstr + mclen, mstr_len - mclen, - &next_gv, &next_uc)) > 0) { - gbinfo_change_bt_last(&gbinfo, BOV_NOTALLOWED); + && is_next_glyph_gl(&gbctxt, + mstr, mstr_len, &next_gv, &next_uc) > 0) { + _DBG_PRINTF ("LB12a Do not break before NBSP and related characters, except after SP and HY\n"); + gbctxt.curr_od = LB12a; + gbctxt_change_bt_last(&gbctxt, BOV_NOTALLOWED); } /* Opening and closing */ // LB13 Do not break before ‘]’ or ‘!’ or ‘;’ or ‘/’, even after spaces. - if (bt == UCHAR_BREAK_CLOSE_PUNCTUATION + else if (bt == UCHAR_BREAK_CLOSE_PUNCTUATION || bt == UCHAR_BREAK_CLOSE_PARANTHESIS || bt == UCHAR_BREAK_EXCLAMATION || bt == UCHAR_BREAK_INFIX_SEPARATOR || bt == UCHAR_BREAK_SYMBOL) { - gbinfo_change_bt_before_last(&gbinfo, BOV_NOTALLOWED); + _DBG_PRINTF ("LB13 Do not break before ‘]’ or ‘!’ or ‘;’ or ‘/’, even after spaces\n"); + gbctxt.curr_od = LB13; + gbctxt_change_bt_before_last_sp(&gbctxt, BOV_NOTALLOWED); } // LB14 Do not break after ‘[’, even after spaces. else if (bt == UCHAR_BREAK_OPEN_PUNCTUATION) { - gbinfo_change_bt_last(&gbinfo, BOV_NOTALLOWED); + _DBG_PRINTF ("LB14 Do not break after ‘[’, even after spaces\n"); + gbctxt.curr_od = LB14; + gbctxt_change_bt_last(&gbctxt, BOV_NOTALLOWED); // For any possible subsequent space. - mclen += check_subsequent_sp(&gbinfo, - mstr + mclen, mstr_len - mclen); + if (col_sp) { + // CSS: collapses space according to space rule + next_mclen = collapse_space(&gbctxt, mstr, mstr_len); + } + else { + next_mclen = check_subsequent_sp(&gbctxt, mstr, mstr_len); + } } // LB15 Do not break within ‘”[’, even with intervening spaces. else if (bt == UCHAR_BREAK_QUOTATION - && (is_subsequent_sps_and_end_bt(&gbinfo, - mstr + mclen, mstr_len - mclen, + && (is_subsequent_sps_and_end_bt(&gbctxt, mstr, mstr_len, UCHAR_BREAK_OPEN_PUNCTUATION))) { - gbinfo_change_bt_last(&gbinfo, BOV_NOTALLOWED); + _DBG_PRINTF ("LB15 Do not break within ‘”[’, even with intervening spaces\n"); + gbctxt.curr_od = LB15; + gbctxt_change_bt_last(&gbctxt, BOV_NOTALLOWED); // For subsequent spaces and OP. - mclen += check_subsequent_sps_and_end_bt(&gbinfo, - mstr + mclen, mstr_len - mclen, + next_mclen = check_subsequent_sps_and_end_bt(&gbctxt, + mstr, mstr_len, col_sp, UCHAR_BREAK_OPEN_PUNCTUATION); } // LB16 Do not break between closing punctuation and a nonstarter // (lb=NS), even with intervening spaces. - else if ((bt == UCHAR_BREAK_CLOSE_PUNCTUATION + if ((bt == UCHAR_BREAK_CLOSE_PUNCTUATION || bt == UCHAR_BREAK_CLOSE_PARANTHESIS) - && (is_subsequent_sps_and_end_bt(&gbinfo, - mstr + mclen, mstr_len - mclen, + && (is_subsequent_sps_and_end_bt(&gbctxt, mstr, mstr_len, UCHAR_BREAK_NON_STARTER))) { - gbinfo_change_bt_last(&gbinfo, BOV_NOTALLOWED); + _DBG_PRINTF ("LB16 Do not break between closing punctuation and NS, even...\n"); + gbctxt.curr_od = LB16; + gbctxt_change_bt_last(&gbctxt, BOV_NOTALLOWED); // For subsequent spaces and NS. - mclen += check_subsequent_sps_and_end_bt(&gbinfo, - mstr + mclen, mstr_len - mclen, + next_mclen = check_subsequent_sps_and_end_bt(&gbctxt, + mstr, mstr_len, col_sp, UCHAR_BREAK_NON_STARTER); } // LB17 Do not break within ‘——’, even with intervening spaces. else if (bt == UCHAR_BREAK_BEFORE_AND_AFTER - && (is_subsequent_sps_and_end_bt(&gbinfo, - mstr + mclen, mstr_len - mclen, + && (is_subsequent_sps_and_end_bt(&gbctxt, mstr, mstr_len, UCHAR_BREAK_BEFORE_AND_AFTER))) { - gbinfo_change_bt_last(&gbinfo, BOV_NOTALLOWED); + _DBG_PRINTF ("LB17 Do not break within ‘——’, even with intervening spaces\n"); + gbctxt.curr_od = LB17; + gbctxt_change_bt_last(&gbctxt, BOV_NOTALLOWED); // For subsequent spaces and B2. - mclen += check_subsequent_sps_and_end_bt(&gbinfo, - mstr + mclen, mstr_len - mclen, + next_mclen = check_subsequent_sps_and_end_bt(&gbctxt, + mstr, mstr_len, col_sp, UCHAR_BREAK_BEFORE_AND_AFTER); } - /* Spaces */ // LB18 Break after spaces. - if (bt == UCHAR_BREAK_SPACE) { - gbinfo_change_bt_last(&gbinfo, BOV_ALLOWED); + else if (bt == UCHAR_BREAK_SPACE) { + _DBG_PRINTF ("LB18 Break after spaces\n"); + gbctxt.curr_od = LB18; + gbctxt_change_bt_last(&gbctxt, BOV_ALLOWED); } - /* Special case rules */ // LB19 Do not break before or after quotation marks, such as ‘ ” ’. - if (bt == UCHAR_BREAK_QUOTATION) { - gbinfo_change_bt_last(&gbinfo, BOV_NOTALLOWED); - gbinfo_change_bt_before_last(&gbinfo, BOV_NOTALLOWED); + else if (bt == UCHAR_BREAK_QUOTATION) { + _DBG_PRINTF ("LB19 Do not break before or after quotation marks, such as ‘ ” ’\n"); + gbctxt.curr_od = LB19; + gbctxt_change_bt_last(&gbctxt, BOV_NOTALLOWED); + gbctxt_change_bt_before_last(&gbctxt, BOV_NOTALLOWED); } // LB20 Break before and after unresolved CB. else if (bt == UCHAR_BREAK_CONTINGENT) { - bo = BOV_ALLOWED; - gbinfo_change_bt_last(&gbinfo, bo); - gbinfo_change_bt_before_last(&gbinfo, bo); + _DBG_PRINTF ("LB20 Break before and after unresolved CB.\n"); + gbctxt.curr_od = LB20; + gbctxt_change_bt_last(&gbctxt, BOV_ALLOWED); + gbctxt_change_bt_before_last(&gbctxt, BOV_ALLOWED); } // LB21 Do not break before hyphen-minus, other hyphens, // fixed-width spaces, small kana, and other non-starters, @@ -1024,28 +1162,33 @@ int GUIAPI GetGlyphsByRules(LOGFONT* logfont, const char* mstr, int mstr_len, else if (bt == UCHAR_BREAK_AFTER || bt == UCHAR_BREAK_HYPHEN || bt == UCHAR_BREAK_NON_STARTER) { - gbinfo_change_bt_before_last(&gbinfo, BOV_NOTALLOWED); + _DBG_PRINTF ("LB21.1 Do not break before hyphen-minus, other hyphens...\n"); + gbctxt.curr_od = LB21; + gbctxt_change_bt_before_last(&gbctxt, BOV_NOTALLOWED); } else if (bt == UCHAR_BREAK_BEFORE) { - gbinfo_change_bt_last(&gbinfo, BOV_NOTALLOWED); + _DBG_PRINTF ("LB21.2 Do not break before hyphen-minus, other hyphens...\n"); + gbctxt.curr_od = LB21; + gbctxt_change_bt_last(&gbctxt, BOV_NOTALLOWED); } // LB21a Don't break after Hebrew + Hyphen. else if (bt == UCHAR_BREAK_HEBREW_LETTER - && (next_mclen = is_next_glyph_hy_or_ba(&gbinfo, - mstr + mclen, mstr_len - mclen, - &next_gv, &next_uc)) > 0) { - mclen += next_mclen; + && (next_mclen = is_next_glyph_hy_or_ba(&gbctxt, + mstr, mstr_len, &next_gv, &next_uc)) > 0) { - gbinfo_change_bt_last(&gbinfo, BOV_NOTALLOWED); - if (gbinfo_push_back(&gbinfo, next_gv, BOV_NOTALLOWED) == 0) + _DBG_PRINTF ("LB21a Don't break after Hebrew + Hyphen\n"); + gbctxt.curr_od = LB21a; + gbctxt_change_bt_last(&gbctxt, BOV_NOTALLOWED); + if (gbctxt_push_back(&gbctxt, next_gv, BOV_NOTALLOWED) == 0) goto error; } // LB21b Don’t break between Solidus and Hebrew letters. else if (bt == UCHAR_BREAK_SYMBOL - && (next_mclen = is_next_glyph_hl(&gbinfo, - mstr + mclen, mstr_len - mclen, - &next_gv, &next_uc)) > 0) { - gbinfo_change_bt_last(&gbinfo, BOV_NOTALLOWED); + && is_next_glyph_hl(&gbctxt, + mstr, mstr_len, &next_gv, &next_uc) > 0) { + _DBG_PRINTF ("LB21b Don’t break between Solidus and Hebrew letters\n"); + gbctxt.curr_od = LB21b; + gbctxt_change_bt_last(&gbctxt, BOV_NOTALLOWED); } // LB22 Do not break between two ellipses, or between letters, // numbers or exclamations and ellipsis. @@ -1057,167 +1200,191 @@ int GUIAPI GetGlyphsByRules(LOGFONT* logfont, const char* mstr, int mstr_len, || bt == UCHAR_BREAK_EMOJI_MODIFIER || bt == UCHAR_BREAK_INSEPARABLE || bt == UCHAR_BREAK_NUMERIC) - && (next_mclen = is_next_glyph_in(&gbinfo, - mstr + mclen, mstr_len - mclen, - &next_gv, &next_uc)) > 0) { - gbinfo_change_bt_last(&gbinfo, BOV_NOTALLOWED); + && is_next_glyph_in(&gbctxt, + mstr, mstr_len, &next_gv, &next_uc) > 0) { + + _DBG_PRINTF ("LB22 Do not break between two ellipses, or between letters...\n"); + gbctxt.curr_od = LB22; + gbctxt_change_bt_last(&gbctxt, BOV_NOTALLOWED); } /* Numbers */ // LB23 Do not break between digits and letters. - if ((bt == UCHAR_BREAK_HEBREW_LETTER + else if ((bt == UCHAR_BREAK_HEBREW_LETTER || bt == UCHAR_BREAK_ALPHABETIC) - && (next_mclen = is_next_glyph_nu(&gbinfo, - mstr + mclen, mstr_len - mclen, - &next_gv, &next_uc)) > 0) { - gbinfo_change_bt_last(&gbinfo, BOV_NOTALLOWED); + && is_next_glyph_nu(&gbctxt, + mstr, mstr_len, &next_gv, &next_uc) > 0) { + _DBG_PRINTF ("LB23 Do not break between digits and letters\n"); + gbctxt.curr_od = LB23; + gbctxt_change_bt_last(&gbctxt, BOV_NOTALLOWED); } else if (bt == UCHAR_BREAK_NUMERIC - && (next_mclen = is_next_glyph_al_hl(&gbinfo, - mstr + mclen, mstr_len - mclen, - &next_gv, &next_uc)) > 0) { - gbinfo_change_bt_last(&gbinfo, BOV_NOTALLOWED); + && is_next_glyph_al_hl(&gbctxt, + mstr, mstr_len, &next_gv, &next_uc) > 0) { + _DBG_PRINTF ("LB23 Do not break between digits and letters\n"); + gbctxt.curr_od = LB23; + gbctxt_change_bt_last(&gbctxt, BOV_NOTALLOWED); } // LB23a Do not break between numeric prefixes and ideographs, // or between ideographs and numeric postfixes. else if (bt == UCHAR_BREAK_PREFIX - && (next_mclen = is_next_glyph_id_eb_em(&gbinfo, - mstr + mclen, mstr_len - mclen, - &next_gv, &next_uc)) > 0) { - gbinfo_change_bt_last(&gbinfo, BOV_NOTALLOWED); + && is_next_glyph_id_eb_em(&gbctxt, + mstr, mstr_len, &next_gv, &next_uc) > 0) { + _DBG_PRINTF ("LB23a.1 Do not break between numeric prefixes and ID...\n"); + gbctxt.curr_od = LB23a; + gbctxt_change_bt_last(&gbctxt, BOV_NOTALLOWED); } else if ((bt == UCHAR_BREAK_IDEOGRAPHIC || bt == UCHAR_BREAK_EMOJI_BASE || bt == UCHAR_BREAK_EMOJI_MODIFIER) - && (next_mclen = is_next_glyph_po(&gbinfo, - mstr + mclen, mstr_len - mclen, - &next_gv, &next_uc)) > 0) { - gbinfo_change_bt_last(&gbinfo, BOV_NOTALLOWED); + && is_next_glyph_po(&gbctxt, + mstr, mstr_len, &next_gv, &next_uc) > 0) { + _DBG_PRINTF ("LB23a.2 Do not break between numeric prefixes and ID...\n"); + gbctxt.curr_od = LB23a; + gbctxt_change_bt_last(&gbctxt, BOV_NOTALLOWED); } // LB24 Do not break between numeric prefix/postfix and letters, // or between letters and prefix/postfix. else if ((bt == UCHAR_BREAK_PREFIX || bt == UCHAR_BREAK_POSTFIX) - && (next_mclen = is_next_glyph_al_hl(&gbinfo, - mstr + mclen, mstr_len - mclen, - &next_gv, &next_uc)) > 0) { - gbinfo_change_bt_last(&gbinfo, BOV_NOTALLOWED); + && is_next_glyph_al_hl(&gbctxt, + mstr, mstr_len, &next_gv, &next_uc) > 0) { + _DBG_PRINTF ("LB24 Do not break between numeric prefix/postfix and letters\n"); + gbctxt.curr_od = LB24; + gbctxt_change_bt_last(&gbctxt, BOV_NOTALLOWED); } else if ((bt == UCHAR_BREAK_ALPHABETIC || bt == UCHAR_BREAK_HEBREW_LETTER) - && (next_mclen = is_next_glyph_pr_po(&gbinfo, - mstr + mclen, mstr_len - mclen, - &next_gv, &next_uc)) > 0) { - gbinfo_change_bt_last(&gbinfo, BOV_NOTALLOWED); + && is_next_glyph_pr_po(&gbctxt, + mstr, mstr_len, &next_gv, &next_uc) > 0) { + _DBG_PRINTF ("LB24 Do not break between numeric prefix/postfix and letters\n"); + gbctxt.curr_od = LB24; + gbctxt_change_bt_last(&gbctxt, BOV_NOTALLOWED); } // LB25 Do not break between the following pairs of classes // relevant to numbers else if (bt == UCHAR_BREAK_CLOSE_PUNCTUATION - && (next_mclen = is_next_glyph_po(&gbinfo, - mstr + mclen, mstr_len - mclen, - &next_gv, &next_uc)) > 0) { - gbinfo_change_bt_last(&gbinfo, BOV_NOTALLOWED); + && is_next_glyph_po(&gbctxt, + mstr, mstr_len, &next_gv, &next_uc) > 0) { + _DBG_PRINTF ("LB25.1 Do not break between the following pairs of classes\n"); + gbctxt.curr_od = LB25; + gbctxt_change_bt_last(&gbctxt, BOV_NOTALLOWED); } else if (bt == UCHAR_BREAK_CLOSE_PUNCTUATION - && (next_mclen = is_next_glyph_pr(&gbinfo, - mstr + mclen, mstr_len - mclen, - &next_gv, &next_uc)) > 0) { - gbinfo_change_bt_last(&gbinfo, BOV_NOTALLOWED); + && is_next_glyph_pr(&gbctxt, + mstr, mstr_len, &next_gv, &next_uc) > 0) { + _DBG_PRINTF ("LB25.2 Do not break between the following pairs of classes\n"); + gbctxt_change_bt_last(&gbctxt, BOV_NOTALLOWED); } else if (bt == UCHAR_BREAK_CLOSE_PARANTHESIS - && (next_mclen = is_next_glyph_po(&gbinfo, - mstr + mclen, mstr_len - mclen, - &next_gv, &next_uc)) > 0) { - gbinfo_change_bt_last(&gbinfo, BOV_NOTALLOWED); + && is_next_glyph_po(&gbctxt, + mstr, mstr_len, &next_gv, &next_uc) > 0) { + gbctxt.curr_od = LB25; + _DBG_PRINTF ("LB25.3 Do not break between the following pairs of classes\n"); + gbctxt_change_bt_last(&gbctxt, BOV_NOTALLOWED); } else if (bt == UCHAR_BREAK_CLOSE_PARANTHESIS - && (next_mclen = is_next_glyph_pr(&gbinfo, - mstr + mclen, mstr_len - mclen, - &next_gv, &next_uc)) > 0) { - gbinfo_change_bt_last(&gbinfo, BOV_NOTALLOWED); + && is_next_glyph_pr(&gbctxt, + mstr, mstr_len, &next_gv, &next_uc) > 0) { + _DBG_PRINTF ("LB25.4 Do not break between the following pairs of classes\n"); + gbctxt.curr_od = LB25; + gbctxt_change_bt_last(&gbctxt, BOV_NOTALLOWED); } else if (bt == UCHAR_BREAK_NUMERIC - && (next_mclen = is_next_glyph_po(&gbinfo, - mstr + mclen, mstr_len - mclen, - &next_gv, &next_uc)) > 0) { - gbinfo_change_bt_last(&gbinfo, BOV_NOTALLOWED); + && is_next_glyph_po(&gbctxt, + mstr, mstr_len, &next_gv, &next_uc) > 0) { + _DBG_PRINTF ("LB25.5 Do not break between the following pairs of classes\n"); + gbctxt.curr_od = LB25; + gbctxt_change_bt_last(&gbctxt, BOV_NOTALLOWED); } else if (bt == UCHAR_BREAK_NUMERIC - && (next_mclen = is_next_glyph_pr(&gbinfo, - mstr + mclen, mstr_len - mclen, - &next_gv, &next_uc)) > 0) { - gbinfo_change_bt_last(&gbinfo, BOV_NOTALLOWED); + && is_next_glyph_pr(&gbctxt, + mstr, mstr_len, &next_gv, &next_uc) > 0) { + _DBG_PRINTF ("LB25.6 Do not break between the following pairs of classes\n"); + gbctxt.curr_od = LB25; + gbctxt_change_bt_last(&gbctxt, BOV_NOTALLOWED); } else if (bt == UCHAR_BREAK_POSTFIX - && (next_mclen = is_next_glyph_op(&gbinfo, - mstr + mclen, mstr_len - mclen, - &next_gv, &next_uc)) > 0) { - gbinfo_change_bt_last(&gbinfo, BOV_NOTALLOWED); + && is_next_glyph_op(&gbctxt, + mstr, mstr_len, &next_gv, &next_uc) > 0) { + gbctxt.curr_od = LB25; + _DBG_PRINTF ("LB25.7 Do not break between the following pairs of classes\n"); + gbctxt_change_bt_last(&gbctxt, BOV_NOTALLOWED); } else if (bt == UCHAR_BREAK_POSTFIX - && (next_mclen = is_next_glyph_nu(&gbinfo, - mstr + mclen, mstr_len - mclen, - &next_gv, &next_uc)) > 0) { - gbinfo_change_bt_last(&gbinfo, BOV_NOTALLOWED); + && is_next_glyph_nu(&gbctxt, + mstr, mstr_len, &next_gv, &next_uc) > 0) { + gbctxt.curr_od = LB25; + _DBG_PRINTF ("LB25.8 Do not break between the following pairs of classes\n"); + gbctxt_change_bt_last(&gbctxt, BOV_NOTALLOWED); } else if (bt == UCHAR_BREAK_PREFIX - && (next_mclen = is_next_glyph_op(&gbinfo, - mstr + mclen, mstr_len - mclen, - &next_gv, &next_uc)) > 0) { - gbinfo_change_bt_last(&gbinfo, BOV_NOTALLOWED); + && is_next_glyph_op(&gbctxt, + mstr, mstr_len, &next_gv, &next_uc) > 0) { + gbctxt.curr_od = LB25; + _DBG_PRINTF ("LB25.9 Do not break between the following pairs of classes\n"); + gbctxt_change_bt_last(&gbctxt, BOV_NOTALLOWED); } else if (bt == UCHAR_BREAK_PREFIX - && (next_mclen = is_next_glyph_nu(&gbinfo, - mstr + mclen, mstr_len - mclen, - &next_gv, &next_uc)) > 0) { - gbinfo_change_bt_last(&gbinfo, BOV_NOTALLOWED); + && is_next_glyph_nu(&gbctxt, + mstr, mstr_len, &next_gv, &next_uc) > 0) { + _DBG_PRINTF ("LB25.a Do not break between the following pairs of classes\n"); + gbctxt.curr_od = LB25; + gbctxt_change_bt_last(&gbctxt, BOV_NOTALLOWED); } else if (bt == UCHAR_BREAK_HYPHEN - && (next_mclen = is_next_glyph_nu(&gbinfo, - mstr + mclen, mstr_len - mclen, - &next_gv, &next_uc)) > 0) { - gbinfo_change_bt_last(&gbinfo, BOV_NOTALLOWED); + && is_next_glyph_nu(&gbctxt, + mstr, mstr_len, &next_gv, &next_uc) > 0) { + _DBG_PRINTF ("LB25.b Do not break between the following pairs of classes\n"); + gbctxt.curr_od = LB25; + gbctxt_change_bt_last(&gbctxt, BOV_NOTALLOWED); } else if (bt == UCHAR_BREAK_INFIX_SEPARATOR - && (next_mclen = is_next_glyph_nu(&gbinfo, - mstr + mclen, mstr_len - mclen, - &next_gv, &next_uc)) > 0) { - gbinfo_change_bt_last(&gbinfo, BOV_NOTALLOWED); + && is_next_glyph_nu(&gbctxt, + mstr, mstr_len, &next_gv, &next_uc) > 0) { + _DBG_PRINTF ("LB25.c Do not break between the following pairs of classes\n"); + gbctxt.curr_od = LB25; + gbctxt_change_bt_last(&gbctxt, BOV_NOTALLOWED); } else if (bt == UCHAR_BREAK_NUMERIC - && (next_mclen = is_next_glyph_nu(&gbinfo, - mstr + mclen, mstr_len - mclen, - &next_gv, &next_uc)) > 0) { - gbinfo_change_bt_last(&gbinfo, BOV_NOTALLOWED); + && is_next_glyph_nu(&gbctxt, + mstr, mstr_len, &next_gv, &next_uc) > 0) { + _DBG_PRINTF ("LB25.d Do not break between the following pairs of classes\n"); + gbctxt.curr_od = LB25; + gbctxt_change_bt_last(&gbctxt, BOV_NOTALLOWED); } else if (bt == UCHAR_BREAK_SYMBOL - && (next_mclen = is_next_glyph_nu(&gbinfo, - mstr + mclen, mstr_len - mclen, - &next_gv, &next_uc)) > 0) { - gbinfo_change_bt_last(&gbinfo, BOV_NOTALLOWED); + && is_next_glyph_nu(&gbctxt, + mstr, mstr_len, &next_gv, &next_uc) > 0) { + _DBG_PRINTF ("LB25.e Do not break between the following pairs of classes\n"); + gbctxt.curr_od = LB25; + gbctxt_change_bt_last(&gbctxt, BOV_NOTALLOWED); } /* Korean syllable blocks */ // LB26 Do not break a Korean syllable. else if (bt == UCHAR_BREAK_HANGUL_L_JAMO - && (next_mclen = is_next_glyph_jl_jv_h2_h3(&gbinfo, - mstr + mclen, mstr_len - mclen, - &next_gv, &next_uc)) > 0) { - gbinfo_change_bt_last(&gbinfo, BOV_NOTALLOWED); + && is_next_glyph_jl_jv_h2_h3(&gbctxt, + mstr, mstr_len, &next_gv, &next_uc) > 0) { + _DBG_PRINTF ("LB26.1 Do not break a Korean syllable.\n"); + gbctxt.curr_od = LB26; + gbctxt_change_bt_last(&gbctxt, BOV_NOTALLOWED); } else if ((bt == UCHAR_BREAK_HANGUL_V_JAMO || bt == UCHAR_BREAK_HANGUL_LV_SYLLABLE) - && (next_mclen = is_next_glyph_jv_jt(&gbinfo, - mstr + mclen, mstr_len - mclen, - &next_gv, &next_uc)) > 0) { - gbinfo_change_bt_last(&gbinfo, BOV_NOTALLOWED); + && is_next_glyph_jv_jt(&gbctxt, + mstr, mstr_len, &next_gv, &next_uc) > 0) { + _DBG_PRINTF ("LB26.2 Do not break a Korean syllable.\n"); + gbctxt.curr_od = LB26; + gbctxt_change_bt_last(&gbctxt, BOV_NOTALLOWED); } else if ((bt == UCHAR_BREAK_HANGUL_T_JAMO || bt == UCHAR_BREAK_HANGUL_LV_SYLLABLE) - && (next_mclen = is_next_glyph_jt(&gbinfo, - mstr + mclen, mstr_len - mclen, - &next_gv, &next_uc)) > 0) { - gbinfo_change_bt_last(&gbinfo, BOV_NOTALLOWED); + && is_next_glyph_jt(&gbctxt, + mstr, mstr_len, &next_gv, &next_uc) > 0) { + _DBG_PRINTF ("LB26.3 Do not break a Korean syllable.\n"); + gbctxt.curr_od = LB26; + gbctxt_change_bt_last(&gbctxt, BOV_NOTALLOWED); } // LB27 Treat a Korean Syllable Block the same as ID. else if ((bt == UCHAR_BREAK_HANGUL_L_JAMO @@ -1225,47 +1392,52 @@ int GUIAPI GetGlyphsByRules(LOGFONT* logfont, const char* mstr, int mstr_len, || bt == UCHAR_BREAK_HANGUL_T_JAMO || bt == UCHAR_BREAK_HANGUL_LV_SYLLABLE || bt == UCHAR_BREAK_HANGUL_LVT_SYLLABLE) - && (next_mclen = is_next_glyph_in(&gbinfo, - mstr + mclen, mstr_len - mclen, - &next_gv, &next_uc)) > 0) { - gbinfo_change_bt_last(&gbinfo, BOV_NOTALLOWED); + && is_next_glyph_in(&gbctxt, + mstr, mstr_len, &next_gv, &next_uc) > 0) { + _DBG_PRINTF ("LB27.1 Treat a Korean Syllable Block the same as ID.\n"); + gbctxt.curr_od = LB27; + gbctxt_change_bt_last(&gbctxt, BOV_NOTALLOWED); } else if ((bt == UCHAR_BREAK_HANGUL_L_JAMO || bt == UCHAR_BREAK_HANGUL_V_JAMO || bt == UCHAR_BREAK_HANGUL_T_JAMO || bt == UCHAR_BREAK_HANGUL_LV_SYLLABLE || bt == UCHAR_BREAK_HANGUL_LVT_SYLLABLE) - && (next_mclen = is_next_glyph_po(&gbinfo, - mstr + mclen, mstr_len - mclen, - &next_gv, &next_uc)) > 0) { - gbinfo_change_bt_last(&gbinfo, BOV_NOTALLOWED); + && is_next_glyph_po(&gbctxt, + mstr, mstr_len, &next_gv, &next_uc) > 0) { + _DBG_PRINTF ("LB27.2 Treat a Korean Syllable Block the same as ID.\n"); + gbctxt.curr_od = LB27; + gbctxt_change_bt_last(&gbctxt, BOV_NOTALLOWED); } else if (bt == UCHAR_BREAK_PREFIX - && (next_mclen = is_next_glyph_jl_jv_jt_h2_h3(&gbinfo, - mstr + mclen, mstr_len - mclen, - &next_gv, &next_uc)) > 0) { - gbinfo_change_bt_last(&gbinfo, BOV_NOTALLOWED); + && is_next_glyph_jl_jv_jt_h2_h3(&gbctxt, + mstr, mstr_len, &next_gv, &next_uc) > 0) { + _DBG_PRINTF ("LB27.3 Treat a Korean Syllable Block the same as ID.\n"); + gbctxt.curr_od = LB27; + gbctxt_change_bt_last(&gbctxt, BOV_NOTALLOWED); } /* Finally, join alphabetic letters into words and break everything else. */ // LB28 Do not break between alphabetics (“at”). - if ((bt == UCHAR_BREAK_HEBREW_LETTER + else if ((bt == UCHAR_BREAK_HEBREW_LETTER || bt == UCHAR_BREAK_ALPHABETIC) - && (next_mclen = is_next_glyph_al_hl(&gbinfo, - mstr + mclen, mstr_len - mclen, - &next_gv, &next_uc)) > 0) { - gbinfo_change_bt_last(&gbinfo, BOV_NOTALLOWED); + && is_next_glyph_al_hl(&gbctxt, + mstr, mstr_len, &next_gv, &next_uc) > 0) { + _DBG_PRINTF ("LB28 Do not break between alphabetics (“at”)\n"); + gbctxt.curr_od = LB28; + gbctxt_change_bt_last(&gbctxt, BOV_NOTALLOWED); } // LB29 Do not break between numeric punctuation // and alphabetics (“e.g.”). else if (bt == UCHAR_BREAK_INFIX_SEPARATOR - && (next_mclen = is_next_glyph_al_hl(&gbinfo, - mstr + mclen, mstr_len - mclen, - &next_gv, &next_uc)) > 0) { - gbinfo_change_bt_last(&gbinfo, BOV_NOTALLOWED); + && is_next_glyph_al_hl(&gbctxt, + mstr, mstr_len, &next_gv, &next_uc) > 0) { + _DBG_PRINTF ("LB29 Do not break between numeric punctuation\n"); + gbctxt.curr_od = LB29; + gbctxt_change_bt_last(&gbctxt, BOV_NOTALLOWED); } // LB30 Do not break between letters, numbers, or ordinary symbols and @@ -1273,77 +1445,90 @@ int GUIAPI GetGlyphsByRules(LOGFONT* logfont, const char* mstr, int mstr_len, else if ((bt == UCHAR_BREAK_HEBREW_LETTER || bt == UCHAR_BREAK_ALPHABETIC || bt == UCHAR_BREAK_NUMERIC) - && (next_mclen = is_next_glyph_op(&gbinfo, - mstr + mclen, mstr_len - mclen, - &next_gv, &next_uc)) > 0) { - gbinfo_change_bt_last(&gbinfo, BOV_NOTALLOWED); + && is_next_glyph_op(&gbctxt, + mstr, mstr_len, &next_gv, &next_uc) > 0) { + _DBG_PRINTF ("LB30.1 Do not break between letters, numbers...\n"); + gbctxt.curr_od = LB30; + gbctxt_change_bt_last(&gbctxt, BOV_NOTALLOWED); } else if (bt == UCHAR_BREAK_CLOSE_PARANTHESIS - && (next_mclen = is_next_glyph_al_hl_nu(&gbinfo, - mstr + mclen, mstr_len - mclen, - &next_gv, &next_uc)) > 0) { - gbinfo_change_bt_last(&gbinfo, BOV_NOTALLOWED); + && is_next_glyph_al_hl_nu(&gbctxt, + mstr, mstr_len, &next_gv, &next_uc) > 0) { + _DBG_PRINTF ("LB30.2 Do not break between letters, numbers...\n"); + gbctxt.curr_od = LB30; + gbctxt_change_bt_last(&gbctxt, BOV_NOTALLOWED); } // LB30a Break between two regional indicator symbols if and only if // there are an even number of regional indicators preceding the // position of the break. - if (bt == UCHAR_BREAK_REGIONAL_INDICATOR - && is_even_nubmer_of_subsequent_ri(&gbinfo, + else if (bt == UCHAR_BREAK_REGIONAL_INDICATOR + && is_even_nubmer_of_subsequent_ri(&gbctxt, mstr - mclen, mstr_len + mclen)) { - mclen = check_even_nubmer_of_subsequent_ri(&gbinfo, + _DBG_PRINTF ("LB30a Break between two regional indicator symbols...\n"); + gbctxt.curr_od = LB30a; + next_mclen = check_even_nubmer_of_subsequent_ri(&gbctxt, mstr - mclen, mstr_len + mclen); + next_mclen -= mclen; } else if (bt != UCHAR_BREAK_REGIONAL_INDICATOR - && is_even_nubmer_of_subsequent_ri(&gbinfo, - mstr + mclen, mstr_len - mclen)) { + && is_even_nubmer_of_subsequent_ri(&gbctxt, + mstr, mstr_len)) { - gbinfo_change_bt_last(&gbinfo, BOV_NOTALLOWED); - - mclen += check_even_nubmer_of_subsequent_ri(&gbinfo, - mstr + mclen, mstr_len - mclen); + _DBG_PRINTF ("LB30a Break between two regional indicator symbols...\n"); + gbctxt.curr_od = LB30a; + gbctxt_change_bt_last(&gbctxt, BOV_NOTALLOWED); + next_mclen = check_even_nubmer_of_subsequent_ri(&gbctxt, + mstr, mstr_len); } // LB30b Do not break between an emoji base and an emoji modifier. - if (bt == UCHAR_BREAK_EMOJI_BASE - && (next_mclen = is_next_glyph_em(&gbinfo, - mstr + mclen, mstr_len - mclen, - &next_gv, &next_uc)) > 0) { - gbinfo_change_bt_last(&gbinfo, BOV_NOTALLOWED); + else if (bt == UCHAR_BREAK_EMOJI_BASE + && is_next_glyph_em(&gbctxt, + mstr, mstr_len, &next_gv, &next_uc) > 0) { + _DBG_PRINTF ("LB30b Do not break between an emoji base and an emoji modifier\n"); + gbctxt.curr_od = LB30b; + gbctxt_change_bt_last(&gbctxt, BOV_NOTALLOWED); } + gbctxt.base_bt = UCHAR_BREAK_UNSET; + next_glyph: - mstr_len -= mclen; - mstr += mclen; - cosumed += mclen; + mstr_len -= next_mclen; + mstr += next_mclen; + cosumed += mclen + next_mclen; // Return if we got any BK! - if (gbinfo.bs[gbinfo.n] == BOV_MANDATORY) { + if (gbctxt.bs[gbctxt.n] == BOV_MANDATORY) { break; } } - if (gbinfo.n > 0) { + if (gbctxt.n > 0) { // LB31 Break everywhere else. int n; - for (n = 1; n <= gbinfo.n; n++) { - if (gbinfo.bs[n] == BOV_UNKNOWN) { - gbinfo.bs[n] = BOV_ALLOWED; + for (n = 1; n < gbctxt.n; n++) { + if (gbctxt.bs[n] == BOV_UNKNOWN) { + _DBG_PRINTF ("LB31 Break everywhere else: %d\n", n); + gbctxt.bs[n] = BOV_ALLOWED; } } - *glyphs = gbinfo.gs; - *break_oppos = gbinfo.bs; - *nr_glyphs = gbinfo.n; + *glyphs = gbctxt.gs; + *break_oppos = gbctxt.bs; + *nr_glyphs = gbctxt.n - 1; } else goto error; + if (gbctxt.od) free(gbctxt.od); + return cosumed; error: - if (gbinfo.gs) free(gbinfo.gs); - if (gbinfo.bs) free(gbinfo.bs); + if (gbctxt.gs) free(gbctxt.gs); + if (gbctxt.bs) free(gbctxt.bs); + if (gbctxt.od) free(gbctxt.od); return 0; }