diff --git a/include/gdi.h b/include/gdi.h index 2645adfd..aefd44cf 100644 --- a/include/gdi.h +++ b/include/gdi.h @@ -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) diff --git a/src/font/legacy-bidi.c b/src/font/legacy-bidi.c index 1e277ac3..ecbf3269 100644 --- a/src/font/legacy-bidi.c +++ b/src/font/legacy-bidi.c @@ -738,6 +738,7 @@ Achar32* __mg_legacy_bidi_map_reorder (const CHARSETOPS* charset_ops, for (i=0; iis_rtol = (node_p)->level & 1; + (map+run_pos+i)->type = (node_p)->type; } } diff --git a/src/newgdi/tabbedtextout.c b/src/newgdi/tabbedtextout.c index a582d446..562c9b15 100644 --- a/src/newgdi/tabbedtextout.c +++ b/src/newgdi/tabbedtextout.c @@ -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); diff --git a/src/newgdi/textout.c b/src/newgdi/textout.c index 18abd155..f84a1f28 100644 --- a/src/newgdi/textout.c +++ b/src/newgdi/textout.c @@ -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;