implement new API: GetACharsExtentPointEx(); enhance GetTextExtentPoint() and GetTabbedTextExtentPoint() to support BIDI charsets

This commit is contained in:
Vincent Wei
2023-04-23 12:36:55 +08:00
parent 11be6af9d3
commit 800329086e
4 changed files with 200 additions and 12 deletions

View File

@@ -12541,6 +12541,8 @@ typedef struct _ACHARMAPINFO {
int char_len;
/** The direction of the character; TRUE for RTL, FALSE for LTR. */
BOOL is_rtol;
/** The BIDI type */
BidiType type;
} ACHARMAPINFO;
/**
@@ -12632,7 +12634,7 @@ MG_EXPORT int GUIAPI BIDIGetTextVisualAChars (LOGFONT* log_font,
* Achar32* achars, int nr_achars, int pel,
* void* extra, CB_REVERSE_ARRAY cb_reverse_extra)
* \brief Reorder the specified logical glyph string in visual order and
* reorder an extra array to reflect the visule order of the achars.
* reorder an extra array to reflect the visual order of the achars.
*
* This function reorders the logical glyph string in place to visual order.
* If \a extra and \a cb_reverse_extra are both not NULL, it also reorders
@@ -12837,6 +12839,31 @@ MG_EXPORT int GUIAPI GetACharsExtent (HDC hdc, Achar32* achars, int nr_achars,
MG_EXPORT int GUIAPI GetACharsExtentPoint (HDC hdc, Achar32* achars,
int nr_achars, int max_extent, SIZE* size);
/**
* \fn int GUIAPI GetACharsExtentPointEx (HDC hdc, Achar32* achars, \
* int nr_achars, int max_extent, int* dx_chars, SIZE* size)
* \brief Get the visual extent value of an achar string.
*
* This function gets the visual extent value of a glpyh string.
* Note that this function ignore all breaks in the achar string.
*
* \param hdc The device context.
* \param achars The pointer to the achar string.
* \param nr_achars The length of the achar string len.
* \param max_extent The maximal output extent value.
* \param dx_achars The output positions of each character in the text will be
* returned through this pointer. It can be NULL.
* \param size The real extent of all visual achars in the achar string.
*
* \return The index of the last achar which can be fit to the extent.
*
* \sa GetACharsExtentPoint
*
* Since 5.0.12
*/
MG_EXPORT int GUIAPI GetACharsExtentPointEx (HDC hdc, Achar32* achars,
int nr_achars, int max_extent, int* dx_achars, SIZE* size);
/**
* \fn Glyph32 GUIAPI GetGlyphValue (LOGFONT* logfont, const char* mchar, \
* int mchar_len, const char* pre_mchar, int pre_len)

View File

@@ -738,6 +738,7 @@ Achar32* __mg_legacy_bidi_map_reorder (const CHARSETOPS* charset_ops,
for (i=0; i<run_len; i++)
{
(map+run_pos+i)->is_rtol = (node_p)->level & 1;
(map+run_pos+i)->type = (node_p)->type;
}
}

View File

@@ -533,6 +533,97 @@ int GUIAPI TabbedTextOutEx (HDC hdc, int x, int y, const char* spText,
return advance;
}
static int get_tabbed_text_extent_point_for_bidi(HDC hdc,
const char* text, int len, int max_extent,
int* fit_chars, int* pos_chars, int* dx_chars, SIZE* size)
{
PDC pdc = dc_HDC2PDC(hdc);
LOGFONT *log_font = pdc->pLogFont;
DEVFONT* sbc_devfont = log_font->devfonts[0];
DEVFONT* mbc_devfont = log_font->devfonts[1];
DEVFONT* devfont;
Achar32 *achars = NULL;
ACHARMAPINFO* achars_map = NULL;
int *dx_achars = NULL;
int nr_fit_achars = 0;
int nr_achars = BIDIGetTextLogicalAChars(log_font, text, len,
&achars, &achars_map);
if (nr_achars <= 0) {
goto done;
}
_gdi_start_new_line(pdc);
int tab_width = sbc_devfont->font_ops->get_ave_width(log_font, sbc_devfont)
* pdc->tabstop;
int line_height = log_font->size + pdc->alExtra + pdc->blExtra;
size->cy = line_height;
int left_achars = nr_achars;
int last_line_width = 0;
while (left_achars > 0) {
if (pos_chars)
pos_chars[nr_fit_achars] = achars_map[nr_fit_achars].byte_index;
if (dx_chars)
dx_chars[nr_fit_achars] = last_line_width;
Uint32 achar_type = GetACharBidiType(log_font, achars[nr_fit_achars]);
Glyph32 gv = GetGlyphValueAlt(log_font, achars[nr_fit_achars]);
int adv_x = 0, adv_y = 0;
switch (achar_type & ACHARTYPE_BASIC_MASK) {
case ACHAR_BASIC_ZEROWIDTH:
adv_x = adv_y = 0;
break;
case ACHAR_BASIC_LF:
adv_y = line_height;
case ACHAR_BASIC_CR:
if (last_line_width > size->cx) {
size->cx = last_line_width;
adv_x = 0;
}
last_line_width = 0;
_gdi_start_new_line(pdc);
break;
case ACHAR_BASIC_HT:
adv_x = tab_width;
last_line_width += tab_width;
_gdi_start_new_line(pdc);
break;
default:
last_line_width += _gdi_get_glyph_advance (pdc, gv,
(pdc->ta_flags & TA_X_MASK) != TA_RIGHT,
0, 0, &adv_x, &adv_y, NULL);
last_line_width += pdc->cExtra;
break;
}
if (max_extent > 0 && last_line_width > max_extent) {
break;
}
size->cx += adv_x;
size->cy += adv_y;
if (last_line_width > size->cx)
size->cx = last_line_width;
left_achars--;
nr_fit_achars++;
}
if (fit_chars)
*fit_chars = nr_fit_achars;
done:
if (achars)
free(achars);
if (achars_map)
free(achars_map);
return nr_fit_achars;
}
int GUIAPI GetTabbedTextExtentPoint (HDC hdc, const char* text,
int len, int max_extent,
int* fit_chars, int* pos_chars, int* dx_chars, SIZE* size)
@@ -553,9 +644,11 @@ int GUIAPI GetTabbedTextExtentPoint (HDC hdc, const char* text,
/* set size to zero first */
size->cx = size->cy = 0;
/* This function does not support BIDI */
if (mbc_devfont && pdc->bidi_flags && mbc_devfont->charset_ops->bidi_char_type)
return -1;
if (mbc_devfont && pdc->bidi_flags &&
mbc_devfont->charset_ops->bidi_char_type) {
return get_tabbed_text_extent_point_for_bidi(hdc, text, len,
max_extent, fit_chars, pos_chars, dx_chars, size);
}
_gdi_start_new_line (pdc);

View File

@@ -441,9 +441,61 @@ int GUIAPI TextOutOmitted (HDC hdc, int x, int y,
#undef STRDOT_LEN
int GUIAPI GetTextExtentPoint (HDC hdc, const char* text, int len,
int max_extent,
int* fit_chars, int* pos_chars, int* dx_chars, SIZE* size)
static int get_text_extent_point_for_bidi(HDC hdc,
const char* text, int len, int max_extent,
int* fit_chars, int* pos_chars, int* dx_chars, SIZE* size)
{
PDC pdc = dc_HDC2PDC(hdc);
LOGFONT *log_font = pdc->pLogFont;
Achar32 *achars = NULL;
ACHARMAPINFO* achars_map = NULL;
int *dx_achars = NULL;
int nr_fit_achars = 0;
int nr_achars = BIDIGetTextLogicalAChars(log_font, text, len,
&achars, &achars_map);
if (nr_achars <= 0) {
goto done;
}
dx_achars = malloc(sizeof(int) * nr_achars);
if (dx_chars == NULL || achars == NULL || achars_map == NULL)
goto done;
BIDILogAChars2VisAChars(log_font, achars, nr_achars, achars_map);
nr_fit_achars = GetACharsExtentPointEx(hdc, achars, nr_achars,
max_extent, dx_achars, size);
if (fit_chars) {
*fit_chars = nr_fit_achars;
}
if (pos_chars || dx_chars) {
for (int i = 0; i < nr_fit_achars; i++) {
if (pos_chars) {
pos_chars[i] = achars_map[i].byte_index;
}
if (dx_chars) {
dx_chars[i] = dx_achars[i];
}
}
}
done:
if (achars)
free(achars);
if (achars_map)
free(achars_map);
if (dx_achars)
free(dx_achars);
return nr_fit_achars;
}
int GUIAPI GetTextExtentPoint (HDC hdc,
const char* text, int len, int max_extent,
int* fit_chars, int* pos_chars, int* dx_chars, SIZE* size)
{
PDC pdc = dc_HDC2PDC (hdc);
LOGFONT* log_font = pdc->pLogFont;
@@ -459,8 +511,12 @@ int GUIAPI GetTextExtentPoint (HDC hdc, const char* text, int len,
size->cx = size->cy = 0;
/* This function does not support BIDI */
if (mbc_devfont && pdc->bidi_flags && mbc_devfont->charset_ops->bidi_char_type)
if (mbc_devfont && pdc->bidi_flags &&
mbc_devfont->charset_ops->bidi_char_type) {
get_text_extent_point_for_bidi(pdc, text, len, max_extent,
fit_chars, pos_chars, dx_chars, size);
return -1;
}
_gdi_start_new_line(pdc);
@@ -538,8 +594,8 @@ int GUIAPI DrawACharString (HDC hdc, int startx, int starty,
return ctxt.advance;
}
int GUIAPI GetACharsExtentPoint(HDC hdc, Achar32* achars, int nr_achars,
int max_extent, SIZE* size)
int GUIAPI GetACharsExtentPointEx (HDC hdc, Achar32* achars, int nr_achars,
int max_extent, int *dx_achars, SIZE* size)
{
int i = 0;
int advance = 0;
@@ -552,7 +608,11 @@ int GUIAPI GetACharsExtentPoint(HDC hdc, Achar32* achars, int nr_achars,
size->cx = 0;
size->cy = 0;
while(i < nr_achars){
while (i < nr_achars){
if (dx_achars) {
dx_achars[i] = advance;
}
devfont = SELECT_DEVFONT_BY_ACHAR(log_font, achars[i]);
char_type = devfont->charset_ops->char_type(achars[i]);
@@ -578,7 +638,7 @@ int GUIAPI GetACharsExtentPoint(HDC hdc, Achar32* achars, int nr_achars,
size->cx += adv_x;
size->cy += adv_y;
i ++;
i++;
}
_gdi_calc_glyphs_size_from_two_points (pdc, 0, 0,
@@ -587,6 +647,13 @@ int GUIAPI GetACharsExtentPoint(HDC hdc, Achar32* achars, int nr_achars,
return i;
}
int GUIAPI GetACharsExtentPoint(HDC hdc, Achar32* achars, int nr_achars,
int max_extent, SIZE* size)
{
return GetACharsExtentPointEx(hdc, achars, nr_achars, max_extent,
NULL, size);
}
int GUIAPI GetACharsExtent(HDC hdc, Achar32* achars, int nr_achars, SIZE* size)
{
int i = 0;