Split GetUCharsAndBreaks into two APIs: GetUCharsUntilParagraphBoundary and UStrGetBreaks

This commit is contained in:
Vincent Wei
2019-03-13 12:21:45 +08:00
parent 2c5ddd93cb
commit 6842cd3933
8 changed files with 6461 additions and 3161 deletions
+93 -55
View File
@@ -8490,6 +8490,78 @@ MG_EXPORT void GUIAPI UBidiShape(Uint32 shaping_flags,
const BidiLevel *embedding_levels, int len,
BidiArabicProp *ar_props, Uchar32* ucs);
/**
* \fn int GUIAPI UStrGetBreaks(Uchar32* ucs, int nr_ucs,
* UCharScriptType writing_system, Uint8 ctr, Uint8 wbr, Uint8 lbp,
* Uint16** break_oppos);
* \brief Convert a multi-byte character string to a Unicode character string
* and calculate the breaking opportunities under the specified rules and
* line breaking policy.
*
* This function calculates and allocates the Uchar32 string and the breaking
* opportunities of the characters from a multi-byte string under the specified
* content language \a content_language, the writing system \a writing_system,
* the white space rule \a wsr, the text transformation rule
* \a ctr, the word breaking rule \a wbr, and the line breaking policy \a lbp.
*
* The implementation of this function conforms to UNICODE LINE BREAKING
* ALGORITHM:
*
* https://www.unicode.org/reports/tr14/tr14-39.html
*
* and UNICODE TEXT SEGMENTATION:
*
* https://www.unicode.org/reports/tr29/tr29-33.html
*
* and the CSS Text Module Level 3:
*
* https://www.w3.org/TR/css-text-3/
*
* The function will return if it encounters any hard line break or the null
* character. The hard line break will be included in the returned Uchar32 if
* there was one.
*
* Note that you are responsible for freeing the Uchar32 string and the
* break opportunities array allocated by this function.
*
* \param logfont The logfont used to parse the string.
* \param mstr The pointer to the multi-byte string.
* \param mstr_len The length of \a mstr in bytes.
* \param content_language The content lanuage identifier.
* \param writing_system The writing system (script) identifier.
* \param wsr The white space rule; see \a white_space_rules.
* \param ctr The character transformation rule;
* see \a char_transform_rule.
* \param wbr The word breaking rule; see \a word_break_rules.
* \param lbp The line breaking policy;
* see \a line_break_policies.
* \param uchars The pointer to a buffer to store the address of the
* Uchar32 array which contains the Unicode character values.
* \param break_oppos The pointer to a buffer to store the address of the
* Uint16 array which contains the break opportunities of the glyphs.
* Note that the length of this array is always one longer than
* the glyphs array. The first unit of the array stores the
* break opportunity before the first glyph, and the others store
* the break opportunities after other gyphs.
* The break opportunity can be one of the following values:
* - BOV_LB_MANDATORY\n
* The mandatory breaking.
* - BOV_LB_NOTALLOWED\n
* No breaking allowed after the glyph definitely.
* - BOV_LB_ALLOWED\n
* Breaking allowed after the glyph.
* \param nr_glyphs The buffer to store the number of the allocated glyphs.
*
* \return The number of the bytes consumed in \a mstr; zero on error.
*
* \note Only available when support for UNICODE is enabled.
*
* \sa DrawGlyphStringEx, white_space_rules, char_transform_rule
*/
MG_EXPORT int GUIAPI UStrGetBreaks(Uchar32* ucs, int nr_ucs,
UCharScriptType writing_system, Uint8 ctr, Uint8 wbr, Uint8 lbp,
Uint16** break_oppos);
/** The function determines whether a character is alphanumeric. */
MG_EXPORT BOOL GUIAPI IsUCharAlnum(Uchar32 uc);
@@ -11812,70 +11884,38 @@ static inline int GUIAPI LanguageCodeFromISO639s1Code (const char* iso639_1)
*/
#define BOV_LB_NOTALLOWED 0x0003
/** @} end of breaking_opportunities */
/**
* \fn int GUIAPI GetUCharsAndBreaks(LOGFONT* logfont,
* const char* mstr, unsigned int mstr_len,
* LanguageCode content_language, UCharScriptType writing_system,
* Uint8 wsr, Uint8 ctr, Uint8 wbr, Uint8 lbp,
* Uchar32** uchars, Uint16** break_oppos,
* int* nr_uchars);
* \brief Convert a multi-byte character string to a Unicode character string
* and calculate the breaking opportunities under the specified rules and
* line breaking policy.
* \fn int GUIAPI GetUCharsUntilParagraphBoundary(LOGFONT* logfont,
* const char* mstr, int mstr_len, Uint8 wsr,
* Uchar32** uchars, int* nr_uchars);
* \brief Convert a multi-byte character string to a Unicode character
* (Uchar32) string until the end of text (null character) or an
* explicit paragraph boundary encountered.
*
* This function calculates and allocates the Uchar32 string and the breaking
* opportunities of the characters from a multi-byte string under the specified
* content language \a content_language, the writing system \a writing_system,
* the white space rule \a wsr, the text transformation rule
* \a ctr, the word breaking rule \a wbr, and the line breaking policy \a lbp.
* This function calculates and allocates the Uchar32 string from a multi-byte
* string until it encounters the end of text (null character) or an explicit
* paragraph boundary. It also processes the text according to the specified
* white space rule \a wsr and the text transformation rule \a ctr.
*
* The implementation of this function conforms to UNICODE LINE BREAKING
* ALGORITHM:
*
* https://www.unicode.org/reports/tr14/tr14-39.html
*
* and UNICODE TEXT SEGMENTATION:
*
* https://www.unicode.org/reports/tr29/tr29-33.html
*
* and the CSS Text Module Level 3:
* The implementation of this function conforms to the CSS Text Module Level 3:
*
* https://www.w3.org/TR/css-text-3/
*
* The function will return if it encounters any hard line break or the null
* character. The hard line break will be included in the returned Uchar32 if
* there was one.
*
* Note that you are responsible for freeing the Uchar32 string and the
* break opportunities array allocated by this function.
* Note that you are responsible for freeing the Uchar32 string allocated
* by this function.
*
* \param logfont The logfont used to parse the string.
* \param mstr The pointer to the multi-byte string.
* \param mstr_len The length of \a mstr in bytes.
* \param content_language The content lanuage identifier.
* \param writing_system The writing system (script) identifier.
* \param wsr The white space rule; see \a white_space_rules.
* \param ctr The character transformation rule;
* see \a char_transform_rule.
* \param wbr The word breaking rule; see \a word_break_rules.
* \param lbp The line breaking policy;
* see \a line_break_policies.
* \param uchars The pointer to a buffer to store the address of the
* Uchar32 array which contains the Unicode character values.
* \param break_oppos The pointer to a buffer to store the address of the
* Uint16 array which contains the break opportunities of the glyphs.
* Note that the length of this array is always one longer than
* the glyphs array. The first unit of the array stores the
* break opportunity before the first glyph, and the others store
* the break opportunities after other gyphs.
* The break opportunity can be one of the following values:
* - BOV_LB_MANDATORY\n
* The mandatory breaking.
* - BOV_LB_NOTALLOWED\n
* No breaking allowed after the glyph definitely.
* - BOV_LB_ALLOWED\n
* Breaking allowed after the glyph.
* \param nr_glyphs The buffer to store the number of the allocated glyphs.
* \param nr_uchars The buffer to store the number of the allocated
* Uchar32 array.
*
* \return The number of the bytes consumed in \a mstr; zero on error.
*
@@ -11883,11 +11923,9 @@ static inline int GUIAPI LanguageCodeFromISO639s1Code (const char* iso639_1)
*
* \sa DrawGlyphStringEx, white_space_rules, char_transform_rule
*/
MG_EXPORT int GUIAPI GetUCharsAndBreaks(LOGFONT* logfont,
const char* mstr, int mstr_len,
LanguageCode content_language, UCharScriptType writing_system,
Uint8 wsr, Uint8 ctr, Uint8 wbr, Uint8 lbp,
Uchar32** uchars, Uint16** break_oppos, int* nr_ucs);
MG_EXPORT int GUIAPI GetUCharsUntilParagraphBoundary(LOGFONT* logfont,
const char* mstr, int mstr_len, Uint8 wsr,
Uchar32** uchars, int* nr_uchars);
/**
* \fn AChar2UChar(LOGFONT* logfont, Achar32 chv)
@@ -12208,7 +12246,7 @@ typedef struct _SHAPEDGLYPH {
* \a content_language, and the writing system \a writing_system.
*
* This function also performs the basic shaping process according to the
* Unicode character properties if the content language is Arabic.
* Unicode character properties if the content language is Arabic.
* The shaping process includes:
*
* - Shaping (substituting) glyphs.
+1
View File
@@ -14,6 +14,7 @@ SRC_FILES = charset.c charset-arabic.c legacy-bidi.c charset-unicode.c \
bitmapfont.c scripteasy.c \
unicode-emoji.c \
unicode-bidi.c \
unicode-break.c \
unicode-joining-types.c unicode-joining.c unicode-shape.c \
unicode-shape-arabic.c
File diff suppressed because it is too large Load Diff
+23
View File
@@ -43,10 +43,33 @@
#ifndef GUI_UNICODE_OPS_H
#define GUI_UNICODE_OPS_H
#define UCHAR_SPACE 0x0020
#define UCHAR_SHY 0x00AD
#define UCHAR_IDSPACE 0x3000
#define UCHAR_TAB 0x0009
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
static inline BOOL is_uchar_letter(Uchar32 uc,
UCharGeneralCategory gc, UCharBreakType bt)
{
if ((gc >= UCHAR_CATEGORY_LOWERCASE_LETTER
&& gc <= UCHAR_CATEGORY_UPPERCASE_LETTER)
|| (gc >= UCHAR_CATEGORY_DECIMAL_NUMBER
&& gc <= UCHAR_CATEGORY_OTHER_NUMBER))
return TRUE;
if (bt == UCHAR_BREAK_NUMERIC
|| bt == UCHAR_BREAK_ALPHABETIC
|| bt == UCHAR_BREAK_IDEOGRAPHIC
|| bt == UCHAR_BREAK_AMBIGUOUS)
return TRUE;
return FALSE;
}
BOOL _unicode_is_emoji(Uchar32 ch);
BOOL _unicode_is_emoji_presentation(Uchar32 ch);
BOOL _unicode_is_emoji_modifier(Uchar32 ch);
+1 -1
View File
@@ -13,7 +13,7 @@ SRC_FILES = gdi.c attr.c clip.c map.c coor.c rect.c \
region.c generators.c polygon.c flood.c \
advapi.c midash.c mispans.c miwideline.c \
mifillarc.c mifpolycon.c miarc.c rotatebmp.c \
text.c achar.c glyph.c legacy-bidi.c \
text.c achar-uchar.c glyph.c legacy-bidi.c \
textout.c tabbedtextout.c drawtext.c \
glyph-unicode.c shaped-glyph.c
endif
+249 -1
View File
@@ -31,8 +31,10 @@
* For more information about the commercial license, please refer to
* <http://www.minigui.com/en/about/licensing-policy/>.
*/
/*
** achar.c: API implementation for abstract character.
** achar-uchar.c: API implementation for conversion between
** abstract characters and Unicode characters.
**
** Create date: 2019/03/05
*/
@@ -184,6 +186,8 @@ Uint16 GUIAPI GetACharBidiType (LOGFONT* log_font, Achar32 chv)
#ifdef _MGCHARSET_UNICODE
#include "unicode-ops.h"
Uchar32 GUIAPI Achar2UChar(LOGFONT* logfont, Achar32 chv)
{
Uchar32 uc;
@@ -331,4 +335,248 @@ int GUIAPI UChars2AChars(LOGFONT* logfont, const Uchar32* ucs,
return i;
}
#define MIN_LEN_UCHARS 4
#define INC_LEN_UCHARS 8
struct ustr_ctxt {
Uchar32* ucs;
int len_buff;
int n;
Uint8 wsr;
};
static int usctxt_init_spaces(struct ustr_ctxt* ctxt, int size)
{
// pre-allocate buffers
ctxt->len_buff = size;
if (ctxt->len_buff < MIN_LEN_UCHARS)
ctxt->len_buff = MIN_LEN_UCHARS;
ctxt->ucs = (Uchar32*)malloc(sizeof(Uchar32) * ctxt->len_buff);
if (ctxt->ucs == NULL)
return 0;
ctxt->n = 0;
return ctxt->len_buff;
}
static int usctxt_push_back(struct ustr_ctxt* ctxt, Uchar32 uc)
{
/* realloc buffers if it needs */
if ((ctxt->n + 2) >= ctxt->len_buff) {
ctxt->len_buff += INC_LEN_UCHARS;
ctxt->ucs = (Uchar32*)realloc(ctxt->ucs,
sizeof(Uchar32) * ctxt->len_buff);
if (ctxt->ucs == NULL)
return 0;
}
ctxt->ucs[ctxt->n] = uc;
ctxt->n++;
return ctxt->n;
}
static int get_next_uchar(LOGFONT* lf, const char* mstr, int mstr_len,
Uchar32* uc)
{
int mclen = 0;
if (mstr_len <= 0 || *mstr == '\0')
return 0;
if (lf->devfonts[1]) {
mclen = lf->devfonts[1]->charset_ops->len_first_char
((const unsigned char*)mstr, mstr_len);
if (mclen > 0) {
Achar32 chv = lf->devfonts[1]->charset_ops->get_char_value
(NULL, 0, (Uint8*)mstr, mclen);
if (lf->devfonts[1]->charset_ops->conv_to_uc32)
*uc = lf->devfonts[1]->charset_ops->conv_to_uc32(chv);
else
*uc = chv;
chv = SET_MBCHV(chv);
}
}
if (mclen == 0) {
mclen = lf->devfonts[0]->charset_ops->len_first_char
((const unsigned char*)mstr, mstr_len);
if (mclen > 0) {
Achar32 chv = lf->devfonts[0]->charset_ops->get_char_value
(NULL, 0, (Uint8*)mstr, mclen);
if (lf->devfonts[0]->charset_ops->conv_to_uc32)
*uc = lf->devfonts[0]->charset_ops->conv_to_uc32(chv);
else
*uc = chv;
}
}
return mclen;
}
static int is_next_mchar_bt(LOGFONT* lf,
const char* mstr, int mstr_len, Uchar32* uc,
UCharBreakType bt)
{
int mclen;
mclen = get_next_uchar(lf, mstr, mstr_len, uc);
if (mclen > 0 && UCharGetBreakType(*uc) == bt)
return mclen;
return 0;
}
static inline int is_next_mchar_lf(LOGFONT* lf,
const char* mstr, int mstr_len, Uchar32* uc)
{
return is_next_mchar_bt(lf, mstr, mstr_len, uc,
UCHAR_BREAK_LINE_FEED);
}
static int collapse_space(LOGFONT* lf, const char* mstr, int mstr_len)
{
Uchar32 uc;
UCharBreakType bt;
int cosumed = 0;
do {
int mclen;
mclen = get_next_uchar(lf, mstr, mstr_len, &uc);
if (mclen == 0)
break;
bt = UCharGetBreakType(uc);
if (bt != UCHAR_BREAK_SPACE && uc != UCHAR_TAB)
break;
mstr += mclen;
mstr_len -= mclen;
cosumed += mclen;
} while (1);
return cosumed;
}
/*
Reference:
[CSS Text Module Level 3](https://www.w3.org/TR/css-text-3/)
*/
int GUIAPI GetUCharsUntilParagraphBoundary(LOGFONT* logfont,
const char* mstr, int mstr_len, Uint8 wsr,
Uchar32** uchars, int* nr_uchars)
{
struct ustr_ctxt ctxt;
int cosumed = 0;
BOOL col_sp = FALSE;
BOOL col_nl = FALSE;
// CSS: collapses space according to space rule
if (wsr == WSR_NORMAL || wsr == WSR_NOWRAP || wsr == WSR_PRE_LINE)
col_sp = TRUE;
// CSS: collapses new lines acoording to space rule
if (wsr == WSR_NORMAL || wsr == WSR_NOWRAP)
col_nl = TRUE;
*uchars = NULL;
*nr_uchars = 0;
if (mstr_len == 0)
return 0;
ctxt.wsr = wsr;
if (usctxt_init_spaces(&ctxt, mstr_len >> 1) <= 0) {
goto error;
}
while (TRUE) {
Uchar32 uc, next_uc;
UCharBreakType bt;
int mclen = 0;
int next_mclen;
int cosumed_one_loop = 0;
mclen = get_next_uchar(logfont, mstr, mstr_len, &uc);
if (mclen == 0) {
// badly encoded or end of text
break;
}
mstr += mclen;
mstr_len -= mclen;
cosumed += mclen;
if ((wsr == WSR_NORMAL || wsr == WSR_NOWRAP
|| wsr == WSR_PRE_LINE) && uc == UCHAR_TAB) {
_DBG_PRINTF ("CSS: Every tab is converted to a space (U+0020)\n");
uc = UCHAR_SPACE;
}
bt = UCharGetBreakType(uc);
if (usctxt_push_back(&ctxt, uc) == 0)
goto error;
/* Check mandatory breaks */
if (bt == UCHAR_BREAK_MANDATORY) {
break;
}
else if (bt == UCHAR_BREAK_CARRIAGE_RETURN
&& (next_mclen = is_next_mchar_lf(logfont,
mstr, mstr_len, &next_uc)) > 0) {
cosumed_one_loop += next_mclen;
if (col_nl) {
ctxt.n--;
}
else {
if (usctxt_push_back(&ctxt, next_uc) == 0)
goto error;
break;
}
}
else if (bt == UCHAR_BREAK_CARRIAGE_RETURN
|| bt == UCHAR_BREAK_LINE_FEED
|| bt == UCHAR_BREAK_NEXT_LINE) {
if (col_nl) {
ctxt.n--;
}
else {
break;
}
}
/* collapse spaces */
else if (col_sp && (bt == UCHAR_BREAK_SPACE
|| bt == UCHAR_BREAK_ZERO_WIDTH_SPACE)) {
cosumed_one_loop += collapse_space(logfont, mstr, mstr_len);
}
mstr_len -= cosumed_one_loop;
mstr += cosumed_one_loop;
cosumed += cosumed_one_loop;
}
if (ctxt.n > 0) {
*uchars = ctxt.ucs;
*nr_uchars = ctxt.n;
}
else
goto error;
return cosumed;
error:
if (ctxt.ucs) free(ctxt.ucs);
return 0;
}
#endif /* _MGCHARSET_UNICODE */
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff