part implementation of GetGlyphsByRules

This commit is contained in:
Vincent Wei
2019-01-23 14:36:56 +08:00
parent 1cfd2fe324
commit 4e67f8c56b
2 changed files with 415 additions and 183 deletions
+104 -97
View File
@@ -5974,18 +5974,18 @@ typedef enum {
* @UCHAR_BREAK_HANGUL_T_JAMO: Hangul T Jamo (JT)
* @UCHAR_BREAK_HANGUL_LV_SYLLABLE: Hangul LV Syllable (H2)
* @UCHAR_BREAK_HANGUL_LVT_SYLLABLE: Hangul LVT Syllable (H3)
* @UCHAR_BREAK_CLOSE_PARANTHESIS: Closing Parenthesis (CP). Since 2.28
* @UCHAR_BREAK_CONDITIONAL_JAPANESE_STARTER: Conditional Japanese Starter (CJ). Since: 2.32
* @UCHAR_BREAK_HEBREW_LETTER: Hebrew Letter (HL). Since: 2.32
* @UCHAR_BREAK_REGIONAL_INDICATOR: Regional Indicator (RI). Since: 2.36
* @UCHAR_BREAK_EMOJI_BASE: Emoji Base (EB). Since: 2.50
* @UCHAR_BREAK_EMOJI_MODIFIER: Emoji Modifier (EM). Since: 2.50
* @UCHAR_BREAK_ZERO_WIDTH_JOINER: Zero Width Joiner (ZWJ). Since: 2.50
* @UCHAR_BREAK_CLOSE_PARANTHESIS: Closing Parenthesis (CP).
* @UCHAR_BREAK_CONDITIONAL_JAPANESE_STARTER: Conditional Japanese Starter (CJ).
* @UCHAR_BREAK_HEBREW_LETTER: Hebrew Letter (HL).
* @UCHAR_BREAK_REGIONAL_INDICATOR: Regional Indicator (RI).
* @UCHAR_BREAK_EMOJI_BASE: Emoji Base (EB).
* @UCHAR_BREAK_EMOJI_MODIFIER: Emoji Modifier (EM).
* @UCHAR_BREAK_ZERO_WIDTH_JOINER: Zero Width Joiner (ZWJ).
*
* These are the possible line break classifications.
*
* Since new unicode versions may add new types here, applications should be ready
* to handle unknown values. They may be regarded as %UCHAR_BREAK_UNKNOWN.
* Since new unicode versions may add new types here, applications should be
* ready to handle unknown values. They may be regarded as %UCHAR_BREAK_UNKNOWN.
*
* See [Unicode Line Breaking Algorithm](http://www.unicode.org/unicode/reports/tr14/).
*/
@@ -6112,94 +6112,88 @@ typedef enum {
* @UCHAR_SCRIPT_PHOENICIAN: Phoenician
* @UCHAR_SCRIPT_PHAGS_PA: Phags-pa
* @UCHAR_SCRIPT_NKO: N'Ko
* @UCHAR_SCRIPT_KAYAH_LI: Kayah Li. Since 2.16.3
* @UCHAR_SCRIPT_LEPCHA: Lepcha. Since 2.16.3
* @UCHAR_SCRIPT_REJANG: Rejang. Since 2.16.3
* @UCHAR_SCRIPT_SUNDANESE: Sundanese. Since 2.16.3
* @UCHAR_SCRIPT_SAURASHTRA: Saurashtra. Since 2.16.3
* @UCHAR_SCRIPT_CHAM: Cham. Since 2.16.3
* @UCHAR_SCRIPT_OL_CHIKI: Ol Chiki. Since 2.16.3
* @UCHAR_SCRIPT_VAI: Vai. Since 2.16.3
* @UCHAR_SCRIPT_CARIAN: Carian. Since 2.16.3
* @UCHAR_SCRIPT_LYCIAN: Lycian. Since 2.16.3
* @UCHAR_SCRIPT_LYDIAN: Lydian. Since 2.16.3
* @UCHAR_SCRIPT_AVESTAN: Avestan. Since 2.26
* @UCHAR_SCRIPT_BAMUM: Bamum. Since 2.26
* @UCHAR_SCRIPT_EGYPTIAN_HIEROGLYPHS:
* Egyptian Hieroglpyhs. Since 2.26
* @UCHAR_SCRIPT_IMPERIAL_ARAMAIC:
* Imperial Aramaic. Since 2.26
* @UCHAR_SCRIPT_INSCRIPTIONAL_PAHLAVI:
* Inscriptional Pahlavi. Since 2.26
* @UCHAR_SCRIPT_INSCRIPTIONAL_PARTHIAN:
* Inscriptional Parthian. Since 2.26
* @UCHAR_SCRIPT_JAVANESE: Javanese. Since 2.26
* @UCHAR_SCRIPT_KAITHI: Kaithi. Since 2.26
* @UCHAR_SCRIPT_LISU: Lisu. Since 2.26
* @UCHAR_SCRIPT_MEETEI_MAYEK:
* Meetei Mayek. Since 2.26
* @UCHAR_SCRIPT_OLD_SOUTH_ARABIAN:
* Old South Arabian. Since 2.26
* @UCHAR_SCRIPT_OLD_TURKIC: Old Turkic. Since 2.28
* @UCHAR_SCRIPT_SAMARITAN: Samaritan. Since 2.26
* @UCHAR_SCRIPT_TAI_THAM: Tai Tham. Since 2.26
* @UCHAR_SCRIPT_TAI_VIET: Tai Viet. Since 2.26
* @UCHAR_SCRIPT_BATAK: Batak. Since 2.28
* @UCHAR_SCRIPT_BRAHMI: Brahmi. Since 2.28
* @UCHAR_SCRIPT_MANDAIC: Mandaic. Since 2.28
* @UCHAR_SCRIPT_CHAKMA: Chakma. Since: 2.32
* @UCHAR_SCRIPT_MEROITIC_CURSIVE: Meroitic Cursive. Since: 2.32
* @UCHAR_SCRIPT_MEROITIC_HIEROGLYPHS: Meroitic Hieroglyphs. Since: 2.32
* @UCHAR_SCRIPT_MIAO: Miao. Since: 2.32
* @UCHAR_SCRIPT_SHARADA: Sharada. Since: 2.32
* @UCHAR_SCRIPT_SORA_SOMPENG: Sora Sompeng. Since: 2.32
* @UCHAR_SCRIPT_TAKRI: Takri. Since: 2.32
* @UCHAR_SCRIPT_BASSA_VAH: Bassa. Since: 2.42
* @UCHAR_SCRIPT_CAUCASIAN_ALBANIAN: Caucasian Albanian. Since: 2.42
* @UCHAR_SCRIPT_DUPLOYAN: Duployan. Since: 2.42
* @UCHAR_SCRIPT_ELBASAN: Elbasan. Since: 2.42
* @UCHAR_SCRIPT_GRANTHA: Grantha. Since: 2.42
* @UCHAR_SCRIPT_KHOJKI: Kjohki. Since: 2.42
* @UCHAR_SCRIPT_KHUDAWADI: Khudawadi, Sindhi. Since: 2.42
* @UCHAR_SCRIPT_LINEAR_A: Linear A. Since: 2.42
* @UCHAR_SCRIPT_MAHAJANI: Mahajani. Since: 2.42
* @UCHAR_SCRIPT_MANICHAEAN: Manichaean. Since: 2.42
* @UCHAR_SCRIPT_MENDE_KIKAKUI: Mende Kikakui. Since: 2.42
* @UCHAR_SCRIPT_MODI: Modi. Since: 2.42
* @UCHAR_SCRIPT_MRO: Mro. Since: 2.42
* @UCHAR_SCRIPT_NABATAEAN: Nabataean. Since: 2.42
* @UCHAR_SCRIPT_OLD_NORTH_ARABIAN: Old North Arabian. Since: 2.42
* @UCHAR_SCRIPT_OLD_PERMIC: Old Permic. Since: 2.42
* @UCHAR_SCRIPT_PAHAWH_HMONG: Pahawh Hmong. Since: 2.42
* @UCHAR_SCRIPT_PALMYRENE: Palmyrene. Since: 2.42
* @UCHAR_SCRIPT_PAU_CIN_HAU: Pau Cin Hau. Since: 2.42
* @UCHAR_SCRIPT_PSALTER_PAHLAVI: Psalter Pahlavi. Since: 2.42
* @UCHAR_SCRIPT_SIDDHAM: Siddham. Since: 2.42
* @UCHAR_SCRIPT_TIRHUTA: Tirhuta. Since: 2.42
* @UCHAR_SCRIPT_WARANG_CITI: Warang Citi. Since: 2.42
* @UCHAR_SCRIPT_AHOM: Ahom. Since: 2.48
* @UCHAR_SCRIPT_ANATOLIAN_HIEROGLYPHS: Anatolian Hieroglyphs. Since: 2.48
* @UCHAR_SCRIPT_HATRAN: Hatran. Since: 2.48
* @UCHAR_SCRIPT_MULTANI: Multani. Since: 2.48
* @UCHAR_SCRIPT_OLD_HUNGARIAN: Old Hungarian. Since: 2.48
* @UCHAR_SCRIPT_SIGNWRITING: Signwriting. Since: 2.48
* @UCHAR_SCRIPT_ADLAM: Adlam. Since: 2.50
* @UCHAR_SCRIPT_BHAIKSUKI: Bhaiksuki. Since: 2.50
* @UCHAR_SCRIPT_MARCHEN: Marchen. Since: 2.50
* @UCHAR_SCRIPT_NEWA: Newa. Since: 2.50
* @UCHAR_SCRIPT_OSAGE: Osage. Since: 2.50
* @UCHAR_SCRIPT_TANGUT: Tangut. Since: 2.50
* @UCHAR_SCRIPT_MASARAM_GONDI: Masaram Gondi. Since: 2.54
* @UCHAR_SCRIPT_NUSHU: Nushu. Since: 2.54
* @UCHAR_SCRIPT_SOYOMBO: Soyombo. Since: 2.54
* @UCHAR_SCRIPT_ZANABAZAR_SQUARE: Zanabazar Square. Since: 2.54
* @UCHAR_SCRIPT_DOGRA: Dogra. Since: 2.58
* @UCHAR_SCRIPT_GUNJALA_GONDI: Gunjala Gondi. Since: 2.58
* @UCHAR_SCRIPT_HANIFI_ROHINGYA: Hanifi Rohingya. Since: 2.58
* @UCHAR_SCRIPT_MAKASAR: Makasar. Since: 2.58
* @UCHAR_SCRIPT_MEDEFAIDRIN: Medefaidrin. Since: 2.58
* @UCHAR_SCRIPT_OLD_SOGDIAN: Old Sogdian. Since: 2.58
* @UCHAR_SCRIPT_SOGDIAN: Sogdian. Since: 2.58
* @UCHAR_SCRIPT_KAYAH_LI: Kayah Li.
* @UCHAR_SCRIPT_LEPCHA: Lepcha.
* @UCHAR_SCRIPT_REJANG: Rejang.
* @UCHAR_SCRIPT_SUNDANESE: Sundanese.
* @UCHAR_SCRIPT_SAURASHTRA: Saurashtra.
* @UCHAR_SCRIPT_CHAM: Cham.
* @UCHAR_SCRIPT_OL_CHIKI: Ol Chiki.
* @UCHAR_SCRIPT_VAI: Vai.
* @UCHAR_SCRIPT_CARIAN: Carian.
* @UCHAR_SCRIPT_LYCIAN: Lycian.
* @UCHAR_SCRIPT_LYDIAN: Lydian.
* @UCHAR_SCRIPT_AVESTAN: Avestan.
* @UCHAR_SCRIPT_BAMUM: Bamum.
* @UCHAR_SCRIPT_EGYPTIAN_HIEROGLYPHS: Egyptian Hieroglpyhs.
* @UCHAR_SCRIPT_IMPERIAL_ARAMAIC: Imperial Aramaic.
* @UCHAR_SCRIPT_INSCRIPTIONAL_PAHLAVI: Inscriptional Pahlavi.
* @UCHAR_SCRIPT_INSCRIPTIONAL_PARTHIAN: Inscriptional Parthian.
* @UCHAR_SCRIPT_JAVANESE: Javanese.
* @UCHAR_SCRIPT_KAITHI: Kaithi.
* @UCHAR_SCRIPT_LISU: Lisu.
* @UCHAR_SCRIPT_MEETEI_MAYEK: Meetei Mayek.
* @UCHAR_SCRIPT_OLD_SOUTH_ARABIAN: Old South Arabian.
* @UCHAR_SCRIPT_OLD_TURKIC: Old Turkic.
* @UCHAR_SCRIPT_SAMARITAN: Samaritan.
* @UCHAR_SCRIPT_TAI_THAM: Tai Tham.
* @UCHAR_SCRIPT_TAI_VIET: Tai Viet.
* @UCHAR_SCRIPT_BATAK: Batak.
* @UCHAR_SCRIPT_BRAHMI: Brahmi.
* @UCHAR_SCRIPT_MANDAIC: Mandaic.
* @UCHAR_SCRIPT_CHAKMA: Chakma.
* @UCHAR_SCRIPT_MEROITIC_CURSIVE: Meroitic Cursive.
* @UCHAR_SCRIPT_MEROITIC_HIEROGLYPHS: Meroitic Hieroglyphs.
* @UCHAR_SCRIPT_MIAO: Miao.
* @UCHAR_SCRIPT_SHARADA: Sharada.
* @UCHAR_SCRIPT_SORA_SOMPENG: Sora Sompeng.
* @UCHAR_SCRIPT_TAKRI: Takri.
* @UCHAR_SCRIPT_BASSA_VAH: Bassa.
* @UCHAR_SCRIPT_CAUCASIAN_ALBANIAN: Caucasian Albanian.
* @UCHAR_SCRIPT_DUPLOYAN: Duployan.
* @UCHAR_SCRIPT_ELBASAN: Elbasan.
* @UCHAR_SCRIPT_GRANTHA: Grantha.
* @UCHAR_SCRIPT_KHOJKI: Kjohki.
* @UCHAR_SCRIPT_KHUDAWADI: Khudawadi, Sindhi.
* @UCHAR_SCRIPT_LINEAR_A: Linear A.
* @UCHAR_SCRIPT_MAHAJANI: Mahajani.
* @UCHAR_SCRIPT_MANICHAEAN: Manichaean.
* @UCHAR_SCRIPT_MENDE_KIKAKUI: Mende Kikakui.
* @UCHAR_SCRIPT_MODI: Modi.
* @UCHAR_SCRIPT_MRO: Mro.
* @UCHAR_SCRIPT_NABATAEAN: Nabataean.
* @UCHAR_SCRIPT_OLD_NORTH_ARABIAN: Old North Arabian.
* @UCHAR_SCRIPT_OLD_PERMIC: Old Permic.
* @UCHAR_SCRIPT_PAHAWH_HMONG: Pahawh Hmong.
* @UCHAR_SCRIPT_PALMYRENE: Palmyrene.
* @UCHAR_SCRIPT_PAU_CIN_HAU: Pau Cin Hau.
* @UCHAR_SCRIPT_PSALTER_PAHLAVI: Psalter Pahlavi.
* @UCHAR_SCRIPT_SIDDHAM: Siddham.
* @UCHAR_SCRIPT_TIRHUTA: Tirhuta.
* @UCHAR_SCRIPT_WARANG_CITI: Warang Citi.
* @UCHAR_SCRIPT_AHOM: Ahom.
* @UCHAR_SCRIPT_ANATOLIAN_HIEROGLYPHS: Anatolian Hieroglyphs.
* @UCHAR_SCRIPT_HATRAN: Hatran.
* @UCHAR_SCRIPT_MULTANI: Multani.
* @UCHAR_SCRIPT_OLD_HUNGARIAN: Old Hungarian.
* @UCHAR_SCRIPT_SIGNWRITING: Signwriting.
* @UCHAR_SCRIPT_ADLAM: Adlam.
* @UCHAR_SCRIPT_BHAIKSUKI: Bhaiksuki.
* @UCHAR_SCRIPT_MARCHEN: Marchen.
* @UCHAR_SCRIPT_NEWA: Newa.
* @UCHAR_SCRIPT_OSAGE: Osage.
* @UCHAR_SCRIPT_TANGUT: Tangut.
* @UCHAR_SCRIPT_MASARAM_GONDI: Masaram Gondi.
* @UCHAR_SCRIPT_NUSHU: Nushu.
* @UCHAR_SCRIPT_SOYOMBO: Soyombo.
* @UCHAR_SCRIPT_ZANABAZAR_SQUARE: Zanabazar Square.
* @UCHAR_SCRIPT_DOGRA: Dogra.
* @UCHAR_SCRIPT_GUNJALA_GONDI: Gunjala Gondi.
* @UCHAR_SCRIPT_HANIFI_ROHINGYA: Hanifi Rohingya.
* @UCHAR_SCRIPT_MAKASAR: Makasar.
* @UCHAR_SCRIPT_MEDEFAIDRIN: Medefaidrin.
* @UCHAR_SCRIPT_OLD_SOGDIAN: Old Sogdian.
* @UCHAR_SCRIPT_SOGDIAN: Sogdian.
*
* This enumeration identifies different writing
* systems. The values correspond to the names as defined in the
@@ -10360,14 +10354,27 @@ static inline int GUIAPI LanguageCodeFromISO639s1Code (const char* iso639_1)
/**
* The break opportunity code
*/
#define BOV_BEFORE_MASK 0xF0
#define BOV_AFTER_MASK 0x0F
#define BOV_BEFORE_NOTALLOWED 0x00
#define BOV_BEFORE_MANDATORY 0x10
#define BOV_BEFORE_ALLOWED 0x20
#define BOV_AFTER_NOTALLOWED 0x00
#define BOV_AFTER_MANDATORY 0x10
#define BOV_AFTER_ALLOWED 0x20
typedef enum {
BOV_UNKNOWN,
BOV_MANDATORY_AFTER,
BOV_MANDATORY_BEFORE,
BOV_ALLOWED_AFTER,
BOV_ALLOWED_BEFORE,
BOV_ALLOWED_BOTH,
BOV_NOT_ALLOWED_AFTER,
BOV_NOT_ALLOWED_BEFORE,
BOV_NOT_ALLOWED_BOTH,
} BreakOpportunityCode;
/**
+311 -86
View File
@@ -66,45 +66,45 @@
#ifdef _MGCHARSET_UNICODE
#define MIN_LEN_GLYPHS 4
#define INC_LEN_GLYPHS 4
static int get_next_glyph(DEVFONT* mbc_devfont, DEVFONT* sbc_devfont,
const char* mstr, int mstr_len, Glyph32* g, Uchar32* uc)
const char* mstr, int mstr_len, Glyph32* gv, Uchar32* uc)
{
int mchar_len = 0;
int mclen = 0;
if (mstr_len <= 0)
return 0;
if (mbc_devfont) {
mchar_len = mbc_devfont->charset_ops->len_first_char
mclen = mbc_devfont->charset_ops->len_first_char
((const unsigned char*)mstr, mstr_len);
if (mchar_len > 0) {
*g = mbc_devfont->charset_ops->char_glyph_value
(NULL, 0, (Uint8*)mstr, mchar_len);
*g = SET_MBC_GLYPH(*g);
if (mclen > 0) {
*gv = mbc_devfont->charset_ops->char_glyph_value
(NULL, 0, (Uint8*)mstr, mclen);
*gv = SET_MBC_GLYPH(*gv);
if (mbc_devfont->charset_ops->conv_to_uc32)
*uc = mbc_devfont->charset_ops->conv_to_uc32(*g);
*uc = mbc_devfont->charset_ops->conv_to_uc32(*gv);
else
*uc = GLYPH2UCHAR(*g);
*uc = GLYPH2UCHAR(*gv);
}
}
if (*g == INV_GLYPH_VALUE) {
mchar_len = sbc_devfont->charset_ops->len_first_char
if (*gv == INV_GLYPH_VALUE) {
mclen = sbc_devfont->charset_ops->len_first_char
((const unsigned char*)mstr, mstr_len);
if (mchar_len > 0) {
*g = sbc_devfont->charset_ops->char_glyph_value
(NULL, 0, (Uint8*)mstr, mchar_len);
if (mclen > 0) {
*gv = sbc_devfont->charset_ops->char_glyph_value
(NULL, 0, (Uint8*)mstr, mclen);
if (sbc_devfont->charset_ops->conv_to_uc32)
*uc = sbc_devfont->charset_ops->conv_to_uc32(*g);
*uc = sbc_devfont->charset_ops->conv_to_uc32(*gv);
else
*uc = GLYPH2UCHAR(*g);
*uc = GLYPH2UCHAR(*gv);
}
}
return mchar_len;
return mclen;
}
static UCharBreakType resolve_line_breaking_class(
@@ -152,18 +152,18 @@ static int collapse_space(DEVFONT* mbc_devfont, DEVFONT* sbc_devfont,
int cosumed = 0;
do {
int mchar_len;
Glyph32 g;
int mclen;
Glyph32 gv;
Uchar32 uc;
mchar_len = get_next_glyph(mbc_devfont, sbc_devfont, mstr, mstr_len,
&g, &uc);
if (mchar_len == 0)
mclen = get_next_glyph(mbc_devfont, sbc_devfont, mstr, mstr_len,
&gv, &uc);
if (mclen == 0)
break;
mstr += mchar_len;
mstr_len -= mchar_len;
cosumed += mchar_len;
mstr += mclen;
mstr_len -= mclen;
cosumed += mclen;
bt = UCharGetBreak(uc);
} while (bt == UCHAR_BREAK_SPACE);
@@ -171,17 +171,124 @@ static int collapse_space(DEVFONT* mbc_devfont, DEVFONT* sbc_devfont,
return cosumed;
}
static int collapse_line_feed(DEVFONT* mbc_devfont, DEVFONT* sbc_devfont,
const char* mstr, int mstr_len)
{
int cosumed = 0;
int mclen;
Glyph32 gv;
Uchar32 uc;
mclen = get_next_glyph(mbc_devfont, sbc_devfont, mstr, mstr_len,
&gv, &uc);
if (mclen > 0 && UCharGetBreak(uc) == UCHAR_BREAK_LINE_FEED)
cosumed = mclen;
return cosumed;
}
static BOOL is_next_glyph_zw(DEVFONT* mbc_devfont, DEVFONT* sbc_devfont,
const char* mstr, int mstr_len)
{
int mclen;
Glyph32 gv;
Uchar32 uc;
mclen = get_next_glyph(mbc_devfont, sbc_devfont, mstr, mstr_len,
&gv, &uc);
if (mclen > 0 && UCharGetBreak(uc) == UCHAR_BREAK_ZERO_WIDTH_SPACE)
return TRUE;
return FALSE;
}
static int is_next_glyph_cm_or_zwj(DEVFONT* mbc_devfont, DEVFONT* sbc_devfont,
const char* mstr, int mstr_len, Glyph32* gv, Uchar32* uc)
{
int mclen;
mclen = get_next_glyph(mbc_devfont, sbc_devfont, mstr, mstr_len,
gv, uc);
if (mclen > 0) {
UCharBreakType bt = UCharGetBreak(*uc);
if (bt == UCHAR_BREAK_COMBINING_MARK
|| bt == UCHAR_BREAK_ZERO_WIDTH_JOINER)
return mclen;
}
return 0;
}
#define MIN_LEN_GLYPHS 4
#define INC_LEN_GLYPHS 4
struct glyph_break_info {
int len_buff;
int n;
Glyph32* gs;
Uint8* bs;
};
static int gbinfo_init(struct glyph_break_info* gbinfo, int size)
{
// pre-allocate buffers
gbinfo->len_buff = size;
if (gbinfo->len_buff < MIN_LEN_GLYPHS)
gbinfo->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)
return 0;
return gbinfo->len_buff;
}
static int gbinfo_push_back(struct glyph_break_info* gbinfo, 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)
return 0;
}
gbinfo->gs[gbinfo->n] = gv;
gbinfo->bs[gbinfo->n] = bt;
gbinfo->n++;
return gbinfo->n;
}
static int check_subsequent_cm_or_zwj(DEVFONT* mbc_devfont, DEVFONT* sbc_devfont,
const char* mstr, int mstr_len, struct glyph_break_info* gbinfo)
{
int cosumed = 0;
int mclen;
Glyph32 gv;
Uchar32 uc;
while ((mclen = is_next_glyph_cm_or_zwj(mbc_devfont, sbc_devfont,
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_NOT_ALLOWED_BEFORE);
cosumed += mclen;
}
return cosumed;
}
int GUIAPI GetGlyphsByRules(LOGFONT* logfont, const char* mstr, int mstr_len,
LanguageCode content_language, UCharScriptType writing_system,
Uint32 space_rule, Uint32 trans_rule,
Glyph32** glyphs, Uint8** break_oppos, int* nr_glyphs)
{
Glyph32* gs = NULL;
Uint8* bs = NULL;
int len_buff;
int n = 0;
struct glyph_break_info gbinfo = {0, 0, NULL, NULL};
int cosumed = 0;
DEVFONT* sbc_devfont = logfont->sbc_devfont;
DEVFONT* mbc_devfont = logfont->mbc_devfont;
@@ -191,85 +298,203 @@ int GUIAPI GetGlyphsByRules(LOGFONT* logfont, const char* mstr, int mstr_len,
if (mstr_len == 0)
return 0;
// pre-allocate buffers
len_buff = mstr_len >> 1;
if (len_buff < MIN_LEN_GLYPHS)
len_buff = MIN_LEN_GLYPHS;
gs = (Glyph32*)malloc(sizeof(Glyph32) * len_buff);
bs = (Uint8*)malloc(sizeof(Uint8) * len_buff);
if (gs == NULL || bs == NULL)
if (gbinfo_init(&gbinfo, mstr_len >> 1) <= 0) {
goto error;
}
while (mstr_len > 0 && *mstr != '\0') {
Glyph32 g = INV_GLYPH_VALUE;
Uchar32 uc = 0;
int mchar_len;
while (mstr_len > 0) {
Glyph32 gv;
Uchar32 uc;
int mclen;
UCharBasicType gc;
UCharBreakType bt;
mchar_len = get_next_glyph(mbc_devfont, sbc_devfont, mstr, mstr_len,
&g, &uc);
if (mchar_len == 0)
Glyph32 next_gv;
Uchar32 next_uc;
UCharBasicType next_gc;
UCharBreakType next_bt;
int next_mclen;
mclen = get_next_glyph(mbc_devfont, sbc_devfont, mstr, mstr_len,
&gv, &uc);
if (mclen == 0) {
// badly encoded or end of text
break;
gc = UCharGetType(uc);
bt = UCharGetBreak(uc);
// CSS: collapses space acoording to space rule
if ((space_rule == WSR_NORMAL || space_rule == WSR_NOWRAP)
&& bt == UCHAR_BREAK_SPACE) {
mchar_len += collapse_space(mbc_devfont, sbc_devfont, mstr,
mstr_len);
}
mstr_len -= mchar_len;
mstr += mchar_len;
cosumed += mchar_len;
gs[n] = g;
bs[n] = BOV_UNKNOWN;
if (space_rule == WSR_PRE || space_rule == WSR_NOWRAP) {
// only break at forced line breaks.
// TODO: only break at forced line breaks.
}
else {
/* Complete Line Breaking Algorithm goes here */
// LB1: Resolve line breaking classes
bt = resolve_line_breaking_class(content_language, writing_system,
gc, bt);
// mark all breaking opportunities
}
/* check and realloc buffers */
n++;
if (n == len_buff) {
len_buff += INC_LEN_GLYPHS;
gs = (Glyph32*)realloc(gs, sizeof(Glyph32) * len_buff);
bs = (Uint8*)realloc(bs, sizeof(Uint8) * len_buff);
if (gs == NULL || bs == NULL)
// LB1 Resolve line breaking class
gc = UCharGetType(uc);
bt = UCharGetBreak(uc);
bt = resolve_line_breaking_class(content_language, writing_system,
gc, bt);
// LB2 Never break at the start of text.
if (gbinfo.n == 0) {
Uint8 bo = BOV_BEFORE_NOTALLOWED;
if (gbinfo_push_back(&gbinfo, gv, bo) == 0)
goto error;
}
// LB3 Always break at the end of text.
else if (*mstr == '\0') {
break;
}
// LB4 Always break after hard line breaks
// LB6 Do not break before hard line breaks.
else if (bt == UCHAR_BREAK_MANDATORY) {
Uint8 bo = BOV_AFTER_MANDATORY | BOV_BEFORE_NOTALLOWED;
if (gbinfo_push_back(&gbinfo, gv, bo) == 0)
goto error;
}
// 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(mbc_devfont, sbc_devfont, mstr,
mstr_len);
Uint8 bo = BOV_AFTER_MANDATORY | BOV_BEFORE_NOTALLOWED;
if (gbinfo_push_back(&gbinfo, gv, bo) == 0)
goto error;
}
// 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_LINE_FEED
|| bt == UCHAR_BREAK_NEXT_LINE) {
Uint8 bo = BOV_AFTER_MANDATORY | BOV_BEFORE_NOTALLOWED;
if (gbinfo_push_back(&gbinfo, gv, bo) == 0)
goto error;
}
// LB7: Do not break before spaces or zero width space.
else if (bt == UCHAR_BREAK_SPACE) {
Uint8 bo = BOV_BEFORE_NOTALLOWED;
if (gbinfo_push_back(&gbinfo, gv, bo) == 0)
goto error;
if (space_rule == WSR_NORMAL || space_rule == WSR_NOWRAP) {
// CSS: collapses space according to space rule
mclen += collapse_space(mbc_devfont, sbc_devfont, mstr,
mstr_len);
}
}
// LB7: Do not break before spaces or zero width space.
else if (bt == UCHAR_BREAK_ZERO_WIDTH_SPACE) {
Uint8 bo = BOV_BEFORE_NOTALLOWED;
if (gbinfo_push_back(&gbinfo, gv, bo) == 0)
goto error;
}
// LB8: Break before any character following a zero-width space,
// even if one or more spaces intervene.
else if (is_next_glyph_zw(mbc_devfont, sbc_devfont, mstr, mstr_len)) {
Uint8 bo = BOV_BEFORE_MANDATORY;
if (gbinfo_push_back(&gbinfo, gv, bo) == 0)
goto error;
}
// LB8a Do not break between a zero width joiner and an ideograph,
// emoji base or emoji modifier.
else if (bt == UCHAR_BREAK_ZERO_WIDTH_JOINER) {
next_mclen = get_next_glyph(mbc_devfont, sbc_devfont,
mstr, mstr_len, &next_gv, &next_uc);
Uint8 bo;
if (next_mclen > 0) {
next_gc = UCharGetType(next_uc);
next_bt = UCharGetBreak(next_uc);
next_bt = resolve_line_breaking_class(content_language,
writing_system, next_gc, next_bt);
if (next_bt == UCHAR_BREAK_IDEOGRAPHIC
|| next_bt == UCHAR_BREAK_EMOJI_BASE
|| next_bt == UCHAR_BREAK_EMOJI_MODIFIER) {
mclen += next_mclen;
bo = BOV_AFTER_NOTALLOWED;
if (gbinfo_push_back(&gbinfo, gv, bo) == 0)
goto error;
bo = BOV_BEFORE_NOTALLOWED;
if (gbinfo_push_back(&gbinfo, next_gv, bo) == 0)
goto error;
}
}
}
// 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.
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
&& (next_mclen = is_next_glyph_cm_or_zwj(mbc_devfont,
sbc_devfont, mstr, mstr_len, &next_gv, &next_uc)) > 0) {
Uint8 bo;
mclen += next_mclen;
bo = BOV_AFTER_NOTALLOWED;
if (gbinfo_push_back(&gbinfo, gv, bo) == 0)
goto error;
// FIXME: CM/ZWJ should have the same break class as
// its base character.
bo = BOV_BEFORE_NOTALLOWED;
if (gbinfo_push_back(&gbinfo, next_gv, bo) == 0)
goto error;
// For any possible subsequent CM/ZWJ characters.
mclen += check_subsequent_cm_or_zwj(mbc_devfont,
sbc_devfont, mstr + next_mclen, mstr_len - next_mclen,
&gbinfo);
}
// LB10 Treat any remaining combining mark or ZWJ as AL.
else if (bt == UCHAR_BREAK_COMBINING_MARK
|| bt == UCHAR_BREAK_ZERO_WIDTH_JOINER) {
bt = UCHAR_BREAK_ALPHABETIC;
}
// LB11 Do not break before or after Word joiner
// and related characters.
else if (bt == UCHAR_BREAK_WORD_JOINER) {
Uint8 bo = BOV_BEFORE_NOTALLOWED | BOV_AFTER_NOTALLOWED;
if (gbinfo_push_back(&gbinfo, gv, bo) == 0)
goto error;
}
mstr_len -= mclen;
mstr += mclen;
cosumed += mclen;
// Return if we got any BK!
if ((gbinfo.bs[gbinfo.n] & BOV_AFTER_MASK) == BOV_AFTER_MANDATORY) {
break;
}
}
if (n == 0) {
if (gs) free(gs);
if (bs) free(bs);
if (gbinfo.n == 0) {
if (gbinfo.gs) free(gbinfo.gs);
if (gbinfo.bs) free(gbinfo.bs);
return 0;
}
else {
*glyphs = gs;
*break_oppos = bs;
*nr_glyphs = n;
*glyphs = gbinfo.gs;
*break_oppos = gbinfo.bs;
*nr_glyphs = gbinfo.n;
}
return cosumed;
error:
if (gs) free(gs);
if (bs) free(bs);
if (gbinfo.gs) free(gbinfo.gs);
if (gbinfo.bs) free(gbinfo.bs);
return 0;
}