Fixed bug 3318 - testime.c enhancement with GNU Unifont support
authorSam Lantinga <slouken@libsdl.org>
Sat, 01 Oct 2016 12:43:14 -0700
changeset 10416d6e839e8b339
parent 10415 53980a18cdde
child 10417 b307b3ebce7d
Fixed bug 3318 - testime.c enhancement with GNU Unifont support

Simon Hug

I'm proposing some changes to the IME test program test/testime.c. The patch includes support for the GNU Unifont hex file, making the SDL_ttf dependency optional. There were also one or two bugs that prevented the text and underline from showing up poperly.
test/testime.c
     1.1 --- a/test/testime.c	Sat Oct 01 12:33:26 2016 -0700
     1.2 +++ b/test/testime.c	Sat Oct 01 12:43:14 2016 -0700
     1.3 @@ -9,7 +9,9 @@
     1.4    including commercial applications, and to alter it and redistribute it
     1.5    freely.
     1.6  */
     1.7 -/* A simple program to test the Input Method support in the SDL library (2.0+) */
     1.8 +/* A simple program to test the Input Method support in the SDL library (2.0+)
     1.9 +   If you build without SDL_ttf, you can use the GNU Unifont hex file instead.
    1.10 +   Download at http://unifoundry.com/unifont.html */
    1.11  
    1.12  #include <stdlib.h>
    1.13  #include <stdio.h>
    1.14 @@ -22,21 +24,342 @@
    1.15  
    1.16  #include "SDL_test_common.h"
    1.17  
    1.18 -#define DEFAULT_PTSIZE  30
    1.19 -#define DEFAULT_FONT    "/System/Library/Fonts/华文细黑.ttf"
    1.20 +#define DEFAULT_PTSIZE 30
    1.21 +#ifdef HAVE_SDL_TTF
    1.22 +#ifdef __MACOSX__
    1.23 +#define DEFAULT_FONT "/System/Library/Fonts/华文细黑.ttf"
    1.24 +#elif __WIN32__
    1.25 +/* Some japanese font present on at least Windows 8.1. */
    1.26 +#define DEFAULT_FONT "C:\\Windows\\Fonts\\yugothic.ttf"
    1.27 +#else
    1.28 +#define DEFAULT_FONT "NoDefaultFont.ttf"
    1.29 +#endif
    1.30 +#else
    1.31 +#define DEFAULT_FONT "unifont-9.0.02.hex"
    1.32 +#endif
    1.33  #define MAX_TEXT_LENGTH 256
    1.34  
    1.35  static SDLTest_CommonState *state;
    1.36  static SDL_Rect textRect, markedRect;
    1.37 -static SDL_Color lineColor = {0,0,0,0};
    1.38 +static SDL_Color lineColor = {0,0,0,255};
    1.39  static SDL_Color backColor = {255,255,255,255};
    1.40 -#ifdef HAVE_SDL_TTF
    1.41 -static SDL_Color textColor = {0,0,0,0};
    1.42 -#endif
    1.43 +static SDL_Color textColor = {0,0,0,255};
    1.44  static char text[MAX_TEXT_LENGTH], markedText[SDL_TEXTEDITINGEVENT_TEXT_SIZE];
    1.45  static int cursor = 0;
    1.46  #ifdef HAVE_SDL_TTF
    1.47  static TTF_Font *font;
    1.48 +#else
    1.49 +#define UNIFONT_MAX_CODEPOINT 0x1ffff
    1.50 +#define UNIFONT_NUM_GLYPHS 0x20000
    1.51 +/* Using 512x512 textures that are supported everywhere. */
    1.52 +#define UNIFONT_TEXTURE_WIDTH 512
    1.53 +#define UNIFONT_GLYPHS_IN_ROW (UNIFONT_TEXTURE_WIDTH / 16)
    1.54 +#define UNIFONT_GLYPHS_IN_TEXTURE (UNIFONT_GLYPHS_IN_ROW * UNIFONT_GLYPHS_IN_ROW)
    1.55 +#define UNIFONT_NUM_TEXTURES ((UNIFONT_NUM_GLYPHS + UNIFONT_GLYPHS_IN_TEXTURE - 1) / UNIFONT_GLYPHS_IN_TEXTURE)
    1.56 +#define UNIFONT_TEXTURE_SIZE (UNIFONT_TEXTURE_WIDTH * UNIFONT_TEXTURE_WIDTH * 4)
    1.57 +#define UNIFONT_TEXTURE_PITCH (UNIFONT_TEXTURE_WIDTH * 4)
    1.58 +#define UNIFONT_DRAW_SCALE 2
    1.59 +struct UnifontGlyph {
    1.60 +    Uint8 width;
    1.61 +    Uint8 data[32];
    1.62 +} *unifontGlyph;
    1.63 +static SDL_Texture **unifontTexture;
    1.64 +static Uint8 unifontTextureLoaded[UNIFONT_NUM_TEXTURES] = {0};
    1.65 +
    1.66 +/* Unifont loading code start */
    1.67 +
    1.68 +static Uint8 dehex(char c)
    1.69 +{
    1.70 +    if (c >= '0' && c <= '9')
    1.71 +        return c - '0';
    1.72 +    else if (c >= 'a' && c <= 'f')
    1.73 +        return c - 'a' + 10;
    1.74 +    else if (c >= 'A' && c <= 'F')
    1.75 +        return c - 'A' + 10;
    1.76 +    return 255;
    1.77 +}
    1.78 +
    1.79 +static Uint8 dehex2(char c1, char c2)
    1.80 +{
    1.81 +    return (dehex(c1) << 4) | dehex(c2);
    1.82 +}
    1.83 +
    1.84 +static Uint8 validate_hex(const char *cp, size_t len, Uint32 *np)
    1.85 +{
    1.86 +    Uint32 n = 0;
    1.87 +    for (; len > 0; cp++, len--)
    1.88 +    {
    1.89 +        Uint8 c = dehex(*cp);
    1.90 +        if (c == 255)
    1.91 +            return 0;
    1.92 +        n = (n << 4) | c;
    1.93 +    }
    1.94 +    if (np != NULL)
    1.95 +        *np = n;
    1.96 +    return 1;
    1.97 +}
    1.98 +
    1.99 +static void unifont_init(const char *fontname)
   1.100 +{
   1.101 +    Uint8 hexBuffer[65];
   1.102 +    Uint32 numGlyphs = 0;
   1.103 +    int lineNumber = 1;
   1.104 +    size_t bytesRead;
   1.105 +    SDL_RWops *hexFile;
   1.106 +    const size_t unifontGlyphSize = UNIFONT_NUM_GLYPHS * sizeof(struct UnifontGlyph);
   1.107 +    const size_t unifontTextureSize = UNIFONT_NUM_TEXTURES * state->num_windows * sizeof(void *);
   1.108 +
   1.109 +    /* Allocate memory for the glyph data so the file can be closed after initialization. */
   1.110 +    unifontGlyph = SDL_malloc(unifontGlyphSize);
   1.111 +    if (unifontGlyph == NULL)
   1.112 +    {
   1.113 +        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Failed to allocate %d KiB for glyph data.\n", (int)(unifontGlyphSize + 1023) / 1024);
   1.114 +        exit(-1);
   1.115 +    }
   1.116 +    SDL_memset(unifontGlyph, 0, unifontGlyphSize);
   1.117 +
   1.118 +    /* Allocate memory for texture pointers for all renderers. */
   1.119 +    unifontTexture = SDL_malloc(unifontTextureSize);
   1.120 +    if (unifontTexture == NULL)
   1.121 +    {
   1.122 +        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Failed to allocate %d KiB for texture pointer data.\n", (int)(unifontTextureSize + 1023) / 1024);
   1.123 +        exit(-1);
   1.124 +    }
   1.125 +    SDL_memset(unifontTexture, 0, unifontTextureSize);
   1.126 +
   1.127 +    hexFile = SDL_RWFromFile(fontname, "rb");
   1.128 +    if (hexFile == NULL)
   1.129 +    {
   1.130 +        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Failed to open font file: %s\n", fontname);
   1.131 +        exit(-1);
   1.132 +    }
   1.133 +
   1.134 +    /* Read all the glyph data into memory to make it accessible later when textures are created. */
   1.135 +    do {
   1.136 +        int i, codepointHexSize;
   1.137 +        size_t bytesOverread;
   1.138 +        Uint8 glyphWidth;
   1.139 +        Uint32 codepoint;
   1.140 +
   1.141 +        bytesRead = SDL_RWread(hexFile, hexBuffer, 1, 9);
   1.142 +        if (numGlyphs > 0 && bytesRead == 0)
   1.143 +            break; /* EOF */
   1.144 +        if ((numGlyphs == 0 && bytesRead == 0) || (numGlyphs > 0 && bytesRead < 9))
   1.145 +        {
   1.146 +            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unfiont: Unexpected end of hex file.\n");
   1.147 +            exit(-1);
   1.148 +        }
   1.149 +
   1.150 +        /* Looking for the colon that separates the codepoint and glyph data at position 2, 4, 6 and 8. */
   1.151 +        if (hexBuffer[2] == ':')
   1.152 +            codepointHexSize = 2;
   1.153 +        else if (hexBuffer[4] == ':')
   1.154 +            codepointHexSize = 4;
   1.155 +        else if (hexBuffer[6] == ':')
   1.156 +            codepointHexSize = 6;
   1.157 +        else if (hexBuffer[8] == ':')
   1.158 +            codepointHexSize = 8;
   1.159 +        else
   1.160 +        {
   1.161 +            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Could not find codepoint and glyph data separator symbol in hex file on line %d.\n", lineNumber);
   1.162 +            exit(-1);
   1.163 +        }
   1.164 +
   1.165 +        if (!validate_hex((const char *)hexBuffer, codepointHexSize, &codepoint))
   1.166 +        {
   1.167 +            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Malformed hexadecimal number in hex file on line %d.\n", lineNumber);
   1.168 +            exit(-1);
   1.169 +        }
   1.170 +        if (codepoint > UNIFONT_MAX_CODEPOINT)
   1.171 +            SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "unifont: Codepoint on line %d exceeded limit of 0x%x.\n", lineNumber, UNIFONT_MAX_CODEPOINT);
   1.172 +
   1.173 +        /* If there was glyph data read in the last file read, move it to the front of the buffer. */
   1.174 +        bytesOverread = 8 - codepointHexSize;
   1.175 +        if (codepointHexSize < 8)
   1.176 +            SDL_memmove(hexBuffer, hexBuffer + codepointHexSize + 1, bytesOverread);
   1.177 +        bytesRead = SDL_RWread(hexFile, hexBuffer + bytesOverread, 1, 33 - bytesOverread);
   1.178 +        if (bytesRead < (33 - bytesOverread))
   1.179 +        {
   1.180 +            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Unexpected end of hex file.\n");
   1.181 +            exit(-1);
   1.182 +        }
   1.183 +        if (hexBuffer[32] == '\n')
   1.184 +            glyphWidth = 8;
   1.185 +        else
   1.186 +        {
   1.187 +            glyphWidth = 16;
   1.188 +            bytesRead = SDL_RWread(hexFile, hexBuffer + 33, 1, 32);
   1.189 +            if (bytesRead < 32)
   1.190 +            {
   1.191 +                SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Unexpected end of hex file.\n");
   1.192 +                exit(-1);
   1.193 +            }
   1.194 +        }
   1.195 +
   1.196 +        if (!validate_hex((const char *)hexBuffer, glyphWidth * 4, NULL))
   1.197 +        {
   1.198 +            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Malformed hexadecimal glyph data in hex file on line %d.\n", lineNumber);
   1.199 +            exit(-1);
   1.200 +        }
   1.201 +
   1.202 +        if (codepoint <= UNIFONT_MAX_CODEPOINT)
   1.203 +        {
   1.204 +            if (unifontGlyph[codepoint].width > 0)
   1.205 +                SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "unifont: Ignoring duplicate codepoint 0x%08x in hex file on line %d.\n", codepoint, lineNumber);
   1.206 +            else
   1.207 +            {
   1.208 +                unifontGlyph[codepoint].width = glyphWidth;
   1.209 +                /* Pack the hex data into a more compact form. */
   1.210 +                for (i = 0; i < glyphWidth * 2; i++)
   1.211 +                    unifontGlyph[codepoint].data[i] = dehex2(hexBuffer[i * 2], hexBuffer[i * 2 + 1]);
   1.212 +                numGlyphs++;
   1.213 +            }
   1.214 +        }
   1.215 +
   1.216 +        lineNumber++;
   1.217 +    } while (bytesRead > 0);
   1.218 +
   1.219 +    SDL_RWclose(hexFile);
   1.220 +    SDL_Log("unifont: Loaded %u glyphs.\n", numGlyphs);
   1.221 +}
   1.222 +
   1.223 +static void unifont_make_rgba(Uint8 *src, Uint8 *dst, Uint8 width)
   1.224 +{
   1.225 +    int i, j;
   1.226 +    Uint8 *row = dst;
   1.227 +
   1.228 +    for (i = 0; i < width * 2; i++)
   1.229 +    {
   1.230 +        Uint8 data = src[i];
   1.231 +        for (j = 0; j < 8; j++)
   1.232 +        {
   1.233 +            if (data & 0x80)
   1.234 +            {
   1.235 +                row[0] = textColor.r;
   1.236 +                row[1] = textColor.g;
   1.237 +                row[2] = textColor.b;
   1.238 +                row[3] = textColor.a;
   1.239 +            }
   1.240 +            else
   1.241 +            {
   1.242 +                row[0] = 0;
   1.243 +                row[1] = 0;
   1.244 +                row[2] = 0;
   1.245 +                row[3] = 0;
   1.246 +            }
   1.247 +            data <<= 1;
   1.248 +            row += 4;
   1.249 +        }
   1.250 +
   1.251 +        if (width == 8 || (width == 16 && i % 2 == 1))
   1.252 +        {
   1.253 +            dst += UNIFONT_TEXTURE_PITCH;
   1.254 +            row = dst;
   1.255 +        }
   1.256 +    }
   1.257 +}
   1.258 +
   1.259 +static void unifont_load_texture(Uint32 textureID)
   1.260 +{
   1.261 +    int i;
   1.262 +    Uint8 * textureRGBA;
   1.263 +
   1.264 +    if (textureID >= UNIFONT_NUM_TEXTURES)
   1.265 +    {
   1.266 +        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Tried to load out of range texture %u.\n", textureID);
   1.267 +        exit(-1);
   1.268 +    }
   1.269 +
   1.270 +    textureRGBA = SDL_malloc(UNIFONT_TEXTURE_SIZE);
   1.271 +    if (textureRGBA == NULL)
   1.272 +    {
   1.273 +        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Failed to allocate %d MiB for a texture.\n", UNIFONT_TEXTURE_SIZE / 1024 / 1024);
   1.274 +        exit(-1);
   1.275 +    }
   1.276 +    SDL_memset(textureRGBA, 0, UNIFONT_TEXTURE_SIZE);
   1.277 +
   1.278 +    /* Copy the glyphs into memory in RGBA format. */
   1.279 +    for (i = 0; i < UNIFONT_GLYPHS_IN_TEXTURE; i++)
   1.280 +    {
   1.281 +        Uint32 codepoint = UNIFONT_GLYPHS_IN_TEXTURE * textureID + i;
   1.282 +        if (unifontGlyph[codepoint].width > 0)
   1.283 +        {
   1.284 +            const Uint32 cInTex = codepoint % UNIFONT_GLYPHS_IN_TEXTURE;
   1.285 +            const size_t offset = (cInTex / UNIFONT_GLYPHS_IN_ROW) * UNIFONT_TEXTURE_PITCH * 16 + (cInTex % UNIFONT_GLYPHS_IN_ROW) * 16 * 4;
   1.286 +            unifont_make_rgba(unifontGlyph[codepoint].data, textureRGBA + offset, unifontGlyph[codepoint].width);
   1.287 +        }
   1.288 +    }
   1.289 +
   1.290 +    /* Create textures and upload the RGBA data from above. */
   1.291 +    for (i = 0; i < state->num_windows; ++i)
   1.292 +    {
   1.293 +        SDL_Renderer *renderer = state->renderers[i];
   1.294 +        SDL_Texture *tex = unifontTexture[UNIFONT_NUM_TEXTURES * i + textureID];
   1.295 +        if (state->windows[i] == NULL || renderer == NULL || tex != NULL)
   1.296 +            continue;
   1.297 +        tex = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC, UNIFONT_TEXTURE_WIDTH, UNIFONT_TEXTURE_WIDTH);
   1.298 +        if (tex == NULL)
   1.299 +        {
   1.300 +            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Failed to create texture %u for renderer %d.\n", textureID, i);
   1.301 +            exit(-1);
   1.302 +        }
   1.303 +        unifontTexture[UNIFONT_NUM_TEXTURES * i + textureID] = tex;
   1.304 +        SDL_SetTextureBlendMode(tex, SDL_BLENDMODE_BLEND);
   1.305 +        if (SDL_UpdateTexture(tex, NULL, textureRGBA, UNIFONT_TEXTURE_PITCH) != 0)
   1.306 +        {
   1.307 +            SDL_Log("unifont error: Failed to update texture %u data for renderer %d.\n", textureID, i);
   1.308 +        }
   1.309 +    }
   1.310 +
   1.311 +    SDL_free(textureRGBA);
   1.312 +    unifontTextureLoaded[textureID] = 1;
   1.313 +}
   1.314 +
   1.315 +static Sint32 unifont_draw_glyph(Uint32 codepoint, int rendererID, SDL_Rect *dstrect)
   1.316 +{
   1.317 +    SDL_Texture *texture;
   1.318 +    const Uint32 textureID = codepoint / UNIFONT_GLYPHS_IN_TEXTURE;
   1.319 +    SDL_Rect srcrect;
   1.320 +    srcrect.w = srcrect.h = 16;
   1.321 +    if (codepoint > UNIFONT_MAX_CODEPOINT)
   1.322 +        return 0;
   1.323 +    if (!unifontTextureLoaded[textureID])
   1.324 +        unifont_load_texture(textureID);
   1.325 +    texture = unifontTexture[UNIFONT_NUM_TEXTURES * rendererID + textureID];
   1.326 +    if (texture != NULL)
   1.327 +    {
   1.328 +        const Uint32 cInTex = codepoint % UNIFONT_GLYPHS_IN_TEXTURE;
   1.329 +        srcrect.x = cInTex % UNIFONT_GLYPHS_IN_ROW * 16;
   1.330 +        srcrect.y = cInTex / UNIFONT_GLYPHS_IN_ROW * 16;
   1.331 +        SDL_RenderCopy(state->renderers[rendererID], texture, &srcrect, dstrect);
   1.332 +    }
   1.333 +    return unifontGlyph[codepoint].width;
   1.334 +}
   1.335 +
   1.336 +static void unifont_cleanup()
   1.337 +{
   1.338 +    int i, j;
   1.339 +    for (i = 0; i < state->num_windows; ++i)
   1.340 +    {
   1.341 +        SDL_Renderer *renderer = state->renderers[i];
   1.342 +        if (state->windows[i] == NULL || renderer == NULL)
   1.343 +            continue;
   1.344 +        for (j = 0; j < UNIFONT_NUM_TEXTURES; j++)
   1.345 +        {
   1.346 +            SDL_Texture *tex = unifontTexture[UNIFONT_NUM_TEXTURES * i + j];
   1.347 +            if (tex != NULL)
   1.348 +                SDL_DestroyTexture(tex);
   1.349 +        }
   1.350 +    }
   1.351 +
   1.352 +    for (j = 0; j < UNIFONT_NUM_TEXTURES; j++)
   1.353 +          unifontTextureLoaded[j] = 0;
   1.354 +
   1.355 +    SDL_free(unifontTexture);
   1.356 +    SDL_free(unifontGlyph);
   1.357 +}
   1.358 +
   1.359 +/* Unifont code end */
   1.360  #endif
   1.361  
   1.362  size_t utf8_length(unsigned char c)
   1.363 @@ -80,6 +403,30 @@
   1.364      return p;
   1.365  }
   1.366  
   1.367 +Uint32 utf8_decode(char *p, size_t len)
   1.368 +{
   1.369 +    Uint32 codepoint = 0;
   1.370 +    size_t i = 0;
   1.371 +    if (!len)
   1.372 +        return 0;
   1.373 +
   1.374 +    for (; i < len; ++i)
   1.375 +    {
   1.376 +        if (i == 0)
   1.377 +            codepoint = (0xff >> len) & *p;
   1.378 +        else
   1.379 +        {
   1.380 +            codepoint <<= 6;
   1.381 +            codepoint |= 0x3f & *p;
   1.382 +        }
   1.383 +        if (!*p)
   1.384 +            return 0;
   1.385 +        p++;
   1.386 +    }
   1.387 +
   1.388 +    return codepoint;
   1.389 +}
   1.390 +
   1.391  void usage()
   1.392  {
   1.393      SDL_Log("usage: testime [--font fontfile]\n");
   1.394 @@ -107,38 +454,61 @@
   1.395  #ifdef HAVE_SDL_TTF
   1.396      TTF_CloseFont(font);
   1.397      TTF_Quit();
   1.398 +#else
   1.399 +    unifont_cleanup();
   1.400  #endif
   1.401  }
   1.402  
   1.403 -void _Redraw(SDL_Renderer * renderer) {
   1.404 -    int w = 0, h = textRect.h;
   1.405 -    SDL_Rect cursorRect, underlineRect;
   1.406 +void _Redraw(int rendererID) {
   1.407 +    SDL_Renderer * renderer = state->renderers[rendererID];
   1.408 +    SDL_Rect drawnTextRect, cursorRect, underlineRect;
   1.409 +    drawnTextRect = textRect;
   1.410 +    drawnTextRect.w = 0;
   1.411  
   1.412      SDL_SetRenderDrawColor(renderer, backColor.r, backColor.g, backColor.b, backColor.a);
   1.413      SDL_RenderFillRect(renderer,&textRect);
   1.414  
   1.415 -#ifdef HAVE_SDL_TTF
   1.416      if (*text)
   1.417      {
   1.418 +#ifdef HAVE_SDL_TTF
   1.419          SDL_Surface *textSur = TTF_RenderUTF8_Blended(font, text, textColor);
   1.420 -        SDL_Rect dest;
   1.421          SDL_Texture *texture;
   1.422 -        dest.x = textRect.x;
   1.423 -        dest.y = textRect.y;
   1.424 -        dest.w = textSur->w;
   1.425 -        dest.h = textSur->h;
   1.426 +
   1.427 +        /* Vertically center text */
   1.428 +        drawnTextRect.y = textRect.y + (textRect.h - textSur->h) / 2;
   1.429 +        drawnTextRect.w = textSur->w;
   1.430 +        drawnTextRect.h = textSur->h;
   1.431  
   1.432          texture = SDL_CreateTextureFromSurface(renderer,textSur);
   1.433          SDL_FreeSurface(textSur);
   1.434  
   1.435 -        SDL_RenderCopy(renderer,texture,NULL,&dest);
   1.436 +        SDL_RenderCopy(renderer,texture,NULL,&drawnTextRect);
   1.437          SDL_DestroyTexture(texture);
   1.438 -        TTF_SizeUTF8(font, text, &w, &h);
   1.439 +#else
   1.440 +        char *utext = text;
   1.441 +        Uint32 codepoint;
   1.442 +        size_t len;
   1.443 +        SDL_Rect dstrect;
   1.444 +
   1.445 +        dstrect.x = textRect.x;
   1.446 +        dstrect.y = textRect.y + (textRect.h - 16 * UNIFONT_DRAW_SCALE) / 2;
   1.447 +        dstrect.w = 16 * UNIFONT_DRAW_SCALE;
   1.448 +        dstrect.h = 16 * UNIFONT_DRAW_SCALE;
   1.449 +        drawnTextRect.y = dstrect.y;
   1.450 +        drawnTextRect.h = dstrect.h;
   1.451 +
   1.452 +        while ((codepoint = utf8_decode(utext, len = utf8_length(*utext))))
   1.453 +        {
   1.454 +            Sint32 advance = unifont_draw_glyph(codepoint, rendererID, &dstrect) * UNIFONT_DRAW_SCALE;
   1.455 +            dstrect.x += advance;
   1.456 +            drawnTextRect.w += advance;
   1.457 +            utext += len;
   1.458 +        }
   1.459 +#endif
   1.460      }
   1.461 -#endif
   1.462  
   1.463 -    markedRect.x = textRect.x + w;
   1.464 -    markedRect.w = textRect.w - w;
   1.465 +    markedRect.x = textRect.x + drawnTextRect.w;
   1.466 +    markedRect.w = textRect.w - drawnTextRect.w;
   1.467      if (markedRect.w < 0)
   1.468      {
   1.469          /* Stop text input because we cannot hold any more characters */
   1.470 @@ -150,9 +520,13 @@
   1.471          SDL_StartTextInput();
   1.472      }
   1.473  
   1.474 -    cursorRect = markedRect;
   1.475 +    cursorRect = drawnTextRect;
   1.476 +    cursorRect.x += cursorRect.w;
   1.477      cursorRect.w = 2;
   1.478 -    cursorRect.h = h;
   1.479 +    cursorRect.h = drawnTextRect.h;
   1.480 +
   1.481 +    drawnTextRect.x += drawnTextRect.w;
   1.482 +    drawnTextRect.w = 0;
   1.483  
   1.484      SDL_SetRenderDrawColor(renderer, backColor.r, backColor.g, backColor.b, backColor.a);
   1.485      SDL_RenderFillRect(renderer,&markedRect);
   1.486 @@ -161,7 +535,6 @@
   1.487      {
   1.488  #ifdef HAVE_SDL_TTF
   1.489          SDL_Surface *textSur;
   1.490 -        SDL_Rect dest;
   1.491          SDL_Texture *texture;
   1.492          if (cursor)
   1.493          {
   1.494 @@ -172,30 +545,60 @@
   1.495  
   1.496              c = *p;
   1.497              *p = 0;
   1.498 -            TTF_SizeUTF8(font, markedText, &w, 0);
   1.499 -            cursorRect.x += w;
   1.500 +            TTF_SizeUTF8(font, markedText, &drawnTextRect.w, NULL);
   1.501 +            cursorRect.x += drawnTextRect.w;
   1.502              *p = c;
   1.503          }
   1.504          textSur = TTF_RenderUTF8_Blended(font, markedText, textColor);
   1.505 -        dest.x = markedRect.x;
   1.506 -        dest.y = markedRect.y;
   1.507 -        dest.w = textSur->w;
   1.508 -        dest.h = textSur->h;
   1.509 -        TTF_SizeUTF8(font, markedText, &w, &h);
   1.510 +        /* Vertically center text */
   1.511 +        drawnTextRect.y = textRect.y + (textRect.h - textSur->h) / 2;
   1.512 +        drawnTextRect.w = textSur->w;
   1.513 +        drawnTextRect.h = textSur->h;
   1.514 +
   1.515          texture = SDL_CreateTextureFromSurface(renderer,textSur);
   1.516          SDL_FreeSurface(textSur);
   1.517  
   1.518 -        SDL_RenderCopy(renderer,texture,NULL,&dest);
   1.519 +        SDL_RenderCopy(renderer,texture,NULL,&drawnTextRect);
   1.520          SDL_DestroyTexture(texture);
   1.521 +#else
   1.522 +        int i = 0;
   1.523 +        char *utext = markedText;
   1.524 +        Uint32 codepoint;
   1.525 +        size_t len;
   1.526 +        SDL_Rect dstrect;
   1.527 +
   1.528 +        dstrect.x = drawnTextRect.x;
   1.529 +        dstrect.y = textRect.y + (textRect.h - 16 * UNIFONT_DRAW_SCALE) / 2;
   1.530 +        dstrect.w = 16 * UNIFONT_DRAW_SCALE;
   1.531 +        dstrect.h = 16 * UNIFONT_DRAW_SCALE;
   1.532 +        drawnTextRect.y = dstrect.y;
   1.533 +        drawnTextRect.h = dstrect.h;
   1.534 +
   1.535 +        while ((codepoint = utf8_decode(utext, len = utf8_length(*utext))))
   1.536 +        {
   1.537 +            Sint32 advance = unifont_draw_glyph(codepoint, rendererID, &dstrect) * UNIFONT_DRAW_SCALE;
   1.538 +            dstrect.x += advance;
   1.539 +            drawnTextRect.w += advance;
   1.540 +            if (i < cursor)
   1.541 +                cursorRect.x += advance;
   1.542 +            i++;
   1.543 +            utext += len;
   1.544 +        }
   1.545  #endif
   1.546  
   1.547 +        if (cursor > 0)
   1.548 +        {
   1.549 +            cursorRect.y = drawnTextRect.y;
   1.550 +            cursorRect.h = drawnTextRect.h;
   1.551 +        }
   1.552 +
   1.553          underlineRect = markedRect;
   1.554 -        underlineRect.y += (h - 2);
   1.555 +        underlineRect.y = drawnTextRect.y + drawnTextRect.h - 2;
   1.556          underlineRect.h = 2;
   1.557 -        underlineRect.w = w;
   1.558 +        underlineRect.w = drawnTextRect.w;
   1.559  
   1.560          SDL_SetRenderDrawColor(renderer, lineColor.r, lineColor.g, lineColor.b, lineColor.a);
   1.561 -        SDL_RenderFillRect(renderer,&markedRect);
   1.562 +        SDL_RenderFillRect(renderer, &underlineRect);
   1.563      }
   1.564  
   1.565      SDL_SetRenderDrawColor(renderer, lineColor.r, lineColor.g, lineColor.b, lineColor.a);
   1.566 @@ -213,7 +616,8 @@
   1.567          SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
   1.568          SDL_RenderClear(renderer);
   1.569  
   1.570 -        _Redraw(renderer);
   1.571 +        /* Sending in the window id to let the font renderers know which one we're working with. */
   1.572 +        _Redraw(i);
   1.573  
   1.574          SDL_RenderPresent(renderer);
   1.575      }
   1.576 @@ -271,6 +675,8 @@
   1.577          SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to find font: %s\n", TTF_GetError());
   1.578          exit(-1);
   1.579      }
   1.580 +#else
   1.581 +    unifont_init(fontname);
   1.582  #endif
   1.583  
   1.584      SDL_Log("Using font: %s\n", fontname);
   1.585 @@ -300,6 +706,8 @@
   1.586                               Redraw();
   1.587                               break;
   1.588                          case SDLK_BACKSPACE:
   1.589 +                            /* Only delete text if not in editing mode. */
   1.590 +                             if (!markedText[0])
   1.591                               {
   1.592                                   size_t textlen = SDL_strlen(text);
   1.593  
   1.594 @@ -366,7 +774,7 @@
   1.595                      SDL_Log("text editing \"%s\", selected range (%d, %d)\n",
   1.596                              event.edit.text, event.edit.start, event.edit.length);
   1.597  
   1.598 -                    strcpy(markedText, event.edit.text);
   1.599 +                    SDL_strlcpy(markedText, event.edit.text, SDL_TEXTEDITINGEVENT_TEXT_SIZE);
   1.600                      cursor = event.edit.start;
   1.601                      Redraw();
   1.602                      break;