TTF_CutUTF8 TTF_PosUTF8


#1

please add functions below, they can fast cut utf8 string to TextArea or RichText:

typedef void (*TTF_CutUTF8_Callback)(void* data, int width);

int TTF_CutUTF8(TTF_Font *font, const char *text, int max_w, int *text_width, TTF_CutUTF8_Callback callback, void* data)
{
    int x, z;
    int minx, maxx;
    int miny, maxy;
    c_glyph *glyph;
    FT_Error error;
    FT_Long use_kerning;
    FT_UInt prev_index = 0;
    int outline_delta = 0;
    size_t textlen;
    int src_len = 0;
    int cur_len = 0;

    TTF_CHECKPOINTER(text, -1);

    /* Initialize everything to 0 */
    minx = maxx = 0;
    miny = maxy = 0;

    /* check kerning */
    use_kerning = FT_HAS_KERNING( font->face ) && font->kerning;

    /* Init outline handling */
    if ( font->outline  > 0 ) {
        outline_delta = font->outline * 2;
    }

    /* Load each character and sum it's bounding box */
    textlen = SDL_strlen(text);
    cur_len = textlen;
    src_len = textlen;
    *text_width = 0;
	x= 0;
	while ( textlen > 0 ) {
        Uint16 c = UTF8_getch(&text, &textlen);
        if ( c == UNICODE_BOM_NATIVE || c == UNICODE_BOM_SWAPPED ) {
            cur_len = textlen;
            if (callback) callback(data, *text_width);
            continue;
        }

        error = Find_Glyph(font, c, CACHED_METRICS);
        if ( error ) {
            TTF_SetFTError("Couldn't find glyph", error);
            return -1;
        }
        glyph = font->current;

        /* handle kerning */
        if ( use_kerning && prev_index && glyph->index ) {
            FT_Vector delta;
            FT_Get_Kerning( font->face, prev_index, glyph->index, ft_kerning_default, &delta );
            x += delta.x >> 6;
        }

#if 0
        if ( (ch == text) && (glyph->minx < 0) ) {
        /* Fixes the texture wrapping bug when the first letter
         * has a negative minx value or horibearing value.  The entire
         * bounding box must be adjusted to be bigger so the entire
         * letter can fit without any texture corruption or wrapping.
         *
         * Effects: First enlarges bounding box.
         * Second, xstart has to start ahead of its normal spot in the
         * negative direction of the negative minx value.
         * (pushes everything to the right).
         *
         * This will make the memory copy of the glyph bitmap data
         * work out correctly.
         * */
            z -= glyph->minx;
        }
#endif

        z = x + glyph->minx;
        if ( minx > z ) {
            minx = z;
        }
        if ( TTF_HANDLE_STYLE_BOLD(font) ) {
            x += font->glyph_overhang;
        }
        if ( glyph->advance > glyph->maxx ) {
            z = x + glyph->advance;
        } else {
            z = x + glyph->maxx;
        }
        if ( maxx < z ) {
            maxx = z;
        }
        x += glyph->advance;

        if ( glyph->miny < miny ) {
            miny = glyph->miny;
        }
        if ( glyph->maxy > maxy ) {
            maxy = glyph->maxy;
        }
        prev_index = glyph->index;

        if ((maxx - minx) + outline_delta > max_w)
            break;

		*text_width = (maxx - minx) + outline_delta;
		cur_len = textlen;
        if (callback) callback(data, *text_width);
    }

	return  src_len - cur_len;
}

int TTF_PosUTF8(TTF_Font *font, const char *text, int offset)
{
    int x, z;
    int minx, maxx;
    int miny, maxy;
    c_glyph *glyph;
    FT_Error error;
    FT_Long use_kerning;
    FT_UInt prev_index = 0;
    int outline_delta = 0;
    size_t textlen;
    int cur_width = 0;
    int tmp = 0;

    TTF_CHECKPOINTER(text, -1);

    /* Initialize everything to 0 */
    minx = maxx = 0;
    miny = maxy = 0;

    /* check kerning */
    use_kerning = FT_HAS_KERNING( font->face ) && font->kerning;

    /* Init outline handling */
    if ( font->outline  > 0 ) {
        outline_delta = font->outline * 2;
    }

    /* Load each character and sum it's bounding box */
    textlen = SDL_strlen(text);
    x= 0;
    while ( textlen > 0 ) {
        Uint16 c = UTF8_getch(&text, &textlen);
        if ( c == UNICODE_BOM_NATIVE || c == UNICODE_BOM_SWAPPED ) {
            continue;
        }

        error = Find_Glyph(font, c, CACHED_METRICS);
        if ( error ) {
            TTF_SetFTError("Couldn't find glyph", error);
            return -1;
        }
        glyph = font->current;

        /* handle kerning */
        if ( use_kerning && prev_index && glyph->index ) {
            FT_Vector delta;
            FT_Get_Kerning( font->face, prev_index, glyph->index, ft_kerning_default, &delta );
            x += delta.x >> 6;
        }

#if 0
        if ( (ch == text) && (glyph->minx < 0) ) {
        /* Fixes the texture wrapping bug when the first letter
         * has a negative minx value or horibearing value.  The entire
         * bounding box must be adjusted to be bigger so the entire
         * letter can fit without any texture corruption or wrapping.
         *
         * Effects: First enlarges bounding box.
         * Second, xstart has to start ahead of its normal spot in the
         * negative direction of the negative minx value.
         * (pushes everything to the right).
         *
         * This will make the memory copy of the glyph bitmap data
         * work out correctly.
         * */
            z -= glyph->minx;
        }
#endif

        z = x + glyph->minx;
        if ( minx > z ) {
            minx = z;
        }
        if ( TTF_HANDLE_STYLE_BOLD(font) ) {
            x += font->glyph_overhang;
        }
        if ( glyph->advance > glyph->maxx ) {
            z = x + glyph->advance;
        } else {
            z = x + glyph->maxx;
        }
        if ( maxx < z ) {
            maxx = z;
        }
        x += glyph->advance;

        if ( glyph->miny < miny ) {
            miny = glyph->miny;
        }
        if ( glyph->maxy > maxy ) {
            maxy = glyph->maxy;
        }
        prev_index = glyph->index;

        tmp = (maxx - minx) + outline_delta;
        if (tmp - (tmp - cur_width) / 2 > offset) break;

        cur_width = tmp;
    }

    return  cur_width;
}

#2

SDL2_ttf source has changed a lot compared to the patch.
and something similar is added:
https://hg.libsdl.org/SDL_ttf/file/8be7bd6ac3d0/SDL_ttf.h#l179

    /* Get the measurement string of text without rendering
       e.g. the number of characters that can be rendered before reaching 'measure_width'

       in:
       measure_width - in pixels to measure this text

       out:
       count  - number of characters that can be rendered
       extent - latest calculated width
    */
    extern DECLSPEC int SDLCALL TTF_MeasureText(TTF_Font *font, const char *text, int measure_width, int *extent, int *count);
    extern DECLSPEC int SDLCALL TTF_MeasureUTF8(TTF_Font *font, const char *text, int measure_width, int *extent, int *count);
    extern DECLSPEC int SDLCALL TTF_MeasureUNICODE(TTF_Font *font, const Uint16 *text, int measure_width, int *extent, int *count);

#3

thanks for your answer~