Skip to content

Commit 209e12b

Browse files
buginatorperim
authored andcommitted
CHANGELOG: Correctly handle unicode strings for edit boxes.
fixes ticket:2209
1 parent bf058bb commit 209e12b

File tree

1 file changed

+108
-66
lines changed

1 file changed

+108
-66
lines changed

lib/widget/editbox.c

+108-66
Original file line numberDiff line numberDiff line change
@@ -266,94 +266,119 @@ static void delCharLeft(utf_32_char *pBuffer, UDWORD *pPos)
266266
/* Calculate how much of the start of a string can fit into the edit box */
267267
static void fitStringStart(utf_32_char *pBuffer, UDWORD boxWidth, UWORD *pCount, UWORD *pCharWidth)
268268
{
269-
UDWORD len;
270-
UWORD printChars = 0, pixelWidth = 0;
271-
char *utf = NULL;
272-
char *utf2 = NULL;
269+
UDWORD size32;
270+
UWORD pixelWidth = 0;
271+
char *utf = NULL;
273272

273+
size32 = utf32len(pBuffer);
274274
utf = UTF32toUTF8(pBuffer, NULL);
275275
if (!utf)
276276
{
277277
debug(LOG_ERROR, "Couldn't convert UTF32 to UTF8?");
278278
*pCount = *pCharWidth = 0;
279279
return;
280280
}
281-
len = strlen(utf);
282281

283282
// We need to calculate the whole string's pixel size.
284283
// From QuesoGLC's notes: additional processing like kerning creates strings of text whose dimensions are not directly
285284
// related to the simple juxtaposition of individual glyph metrics. For example, the advance width of "VA" isn't the
286285
// sum of the advances of "V" and "A" taken separately.
287286
pixelWidth = iV_GetTextWidth(utf);
287+
free(utf); // release the utf buffer
288288

289289
// Find the number of characters that will fit in boxWidth
290290
if (pixelWidth < boxWidth - (WEDB_XGAP*2 + WEDB_CURSORSIZE))
291291
{
292-
*pCharWidth = pixelWidth; // the actual pixelWidth we use for the string
293-
*pCount = len; // and the length of said string.
292+
*pCharWidth = pixelWidth; // the actual pixelWidth we use for the string
293+
*pCount = size32; // and the length of said string.
294+
295+
return;
294296
}
295297
else
296298
{
297-
utf2 = utf;
299+
utf_32_char *tmp;
300+
int printChars = 0;
301+
302+
tmp = malloc( sizeof(utf_32_char) * size32 + sizeof(utf_32_char));
303+
memcpy(tmp, pBuffer, sizeof(utf_32_char) * size32);
304+
tmp[size32] = 0;
305+
306+
// we must do this, since it is possible to have invalid utf8 when you start removing just 1 byte at a time
298307
do
299308
{
300-
pixelWidth = iV_GetTextWidth(utf2);
309+
utf = UTF32toUTF8(tmp, NULL);
310+
pixelWidth = iV_GetTextWidth(utf);
301311
printChars++;
302-
utf2[(len - printChars)] = 0; // keep chopping off end until it fits
312+
free(utf);
313+
tmp[(size32 - printChars)] = 0; // keep chopping off end until it fits
303314
}
304-
while (pixelWidth > boxWidth - (WEDB_XGAP*2 + WEDB_CURSORSIZE) && printChars < len);
315+
while (pixelWidth > boxWidth - (WEDB_XGAP*2 + WEDB_CURSORSIZE) && printChars < size32);
305316

317+
size32 = utf32len(tmp); // length we ended up with
318+
free(tmp);
306319
*pCharWidth = pixelWidth; // the actual pixelWidth we use for the string
307-
*pCount = len - printChars; // and the length of the new string.
320+
*pCount = size32; // and the length of the new string.
308321
}
309-
free(utf); // release the utf buffer
310322
}
311323

312324

313325
/* Calculate how much of the end of a string can fit into the edit box */
314326
static void fitStringEnd(utf_32_char *pBuffer, UDWORD boxWidth, UWORD *pStart, UWORD *pCount, UWORD *pCharWidth)
315327
{
316-
UDWORD len;
317-
UWORD printChars = 0, pixelWidth = 0;
328+
UDWORD olen32, nlen32;
329+
UWORD pixelWidth = 0;
318330
char *utf = NULL;
319-
char *utf2 = NULL;
320331

332+
olen32 = utf32len(pBuffer); // original length
321333
utf = UTF32toUTF8(pBuffer, NULL);
322334
if (!utf)
323335
{
324336
debug(LOG_ERROR, "Couldn't convert UTF32 to UTF8?");
325337
*pCount = *pStart = *pCharWidth = 0;
326338
return;
327339
}
328-
len = strlen(utf);
329340

330341
// We need to calculate the whole string's pixel size.
331342
// From QuesoGLC's notes: additional processing like kerning creates strings of text whose dimensions are not directly
332343
// related to the simple juxtaposition of individual glyph metrics. For example, the advance width of "VA" isn't the
333344
// sum of the advances of "V" and "A" taken separately.
334345
pixelWidth = iV_GetTextWidth(utf);
346+
free(utf); // release the utf buffer
335347

336348
// Find the number of characters that will fit in boxWidth
337349
if (pixelWidth < boxWidth - (WEDB_XGAP*2 + WEDB_CURSORSIZE))
338350
{
339-
*pStart = 0 ; // nothing to trim
340-
*pCharWidth = pixelWidth; // the actual pixelWidth we use for the string
341-
*pCount = len; // and the length of said string.
351+
*pStart = 0 ; // nothing to trim
352+
*pCharWidth = pixelWidth; // the actual pixelWidth we use for the string
353+
*pCount = olen32; // and the length of said string.
354+
355+
return;
342356
}
343357
else
344358
{
345-
utf2 = utf;
346-
while (pixelWidth > boxWidth - (WEDB_XGAP*2 + WEDB_CURSORSIZE) && printChars < len)
359+
utf_32_char *tmp = NULL, *utf32buf = NULL;
360+
int printChars = 0;
361+
362+
utf32buf = malloc( sizeof(utf_32_char) * olen32 + sizeof(utf_32_char));
363+
memcpy(utf32buf, pBuffer, sizeof(utf_32_char) * olen32);
364+
utf32buf[olen32] = 0;
365+
tmp = utf32buf;
366+
367+
while (pixelWidth > boxWidth - (WEDB_XGAP*2 + WEDB_CURSORSIZE) && printChars < olen32)
347368
{
348-
utf2++; // new string is 1 char shorter [abc] is now [bc]
349-
pixelWidth = iV_GetTextWidth(utf2);
369+
tmp++; // new string is 1 char shorter [abc] is now [bc]
370+
utf = UTF32toUTF8(tmp, NULL);
371+
pixelWidth = iV_GetTextWidth(utf);
350372
printChars++;
373+
free(utf);
351374
}
352-
*pStart = len - (len - printChars); // the starting position of the string to display
375+
376+
nlen32 = utf32len(tmp); // new size of string
377+
*pStart = printChars; // the starting position of the string to display
353378
*pCharWidth = pixelWidth; // the actual pixelWidth we use for the string
354-
*pCount = len - printChars; // and the length of the new string.
379+
*pCount = nlen32; // and the length of the new string.
380+
free(utf32buf);
355381
}
356-
free(utf); // release the utf buffer
357382
}
358383

359384

@@ -497,8 +522,7 @@ void editBoxRun(W_EDITBOX *psWidget, W_CONTEXT *psContext)
497522
delCharRight(pBuffer, &pos);
498523

499524
/* Update the printable text */
500-
fitStringStart(pBuffer + printStart, psWidget->width,
501-
&printChars, &printWidth);
525+
fitStringStart(pBuffer + printStart, psWidget->width, &printChars, &printWidth);
502526
debug(LOG_INPUT, "EditBox cursor delete");
503527
break;
504528
case INPBUF_PGUP :
@@ -523,14 +547,12 @@ void editBoxRun(W_EDITBOX *psWidget, W_CONTEXT *psContext)
523547
else
524548
{
525549
printStart -= WEDB_CHARJUMP;
526-
fitStringStart(pBuffer + printStart, psWidget->width,
527-
&printChars, &printWidth);
550+
fitStringStart(pBuffer + printStart, psWidget->width, &printChars, &printWidth);
528551
}
529552
}
530553
else
531554
{
532-
fitStringStart(pBuffer + printStart, psWidget->width,
533-
&printChars, &printWidth);
555+
fitStringStart(pBuffer + printStart, psWidget->width, &printChars, &printWidth);
534556
}
535557
debug(LOG_INPUT, "EditBox cursor backspace");
536558
break;
@@ -563,9 +585,9 @@ void editBoxRun(W_EDITBOX *psWidget, W_CONTEXT *psContext)
563585
{
564586
overwriteChar(&pBuffer, &pBufferAllocated, &pos, unicode, psWidget);
565587
}
566-
588+
len = utf32len(pBuffer);
567589
/* Update the printable chars */
568-
if (pos == utf32len(pBuffer))
590+
if (pos == len)
569591
{
570592
fitStringEnd(pBuffer, psWidget->width, &printStart, &printChars, &printWidth);
571593
}
@@ -578,8 +600,7 @@ void editBoxRun(W_EDITBOX *psWidget, W_CONTEXT *psContext)
578600
if (printStart >= len)
579601
{
580602
printStart = (UWORD)(len - 1);
581-
fitStringStart(pBuffer + printStart, psWidget->width,
582-
&printChars, &printWidth);
603+
fitStringStart(pBuffer + printStart, psWidget->width, &printChars, &printWidth);
583604
}
584605
}
585606
}
@@ -666,8 +687,7 @@ void editBoxFocusLost(W_SCREEN* psScreen, W_EDITBOX *psWidget)
666687
/* Stop editing the widget */
667688
psWidget->state = WEDBS_FIXED;
668689
psWidget->printStart = 0;
669-
fitStringStart(psWidget->aText,psWidget->width,
670-
&psWidget->printChars, &psWidget->printWidth);
690+
fitStringStart(psWidget->aText,psWidget->width, &psWidget->printChars, &psWidget->printWidth);
671691

672692
widgSetReturn(psScreen, (WIDGET *)psWidget);
673693

@@ -689,7 +709,8 @@ void editBoxHiLite(W_EDITBOX *psWidget)
689709
return;
690710
}
691711

692-
if(psWidget->AudioCallback) {
712+
if(psWidget->AudioCallback)
713+
{
693714
psWidget->AudioCallback(psWidget->HilightAudioID);
694715
}
695716

@@ -715,11 +736,13 @@ void editBoxDisplay(WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset, PIELIGHT *
715736
W_EDITBOX *psEdBox;
716737
SDWORD x0,y0,x1,y1, fx,fy, cx,cy;
717738
enum iV_fonts CurrFontID;
718-
utf_32_char ch, *pInsPoint, *pPrint;
739+
719740
#if CURSOR_BLINK
720741
BOOL blink;
721742
#endif
722743
char *utf;
744+
utf_32_char *pInsPoint, *UTF32string;
745+
int size=0;
723746

724747
psEdBox = (W_EDITBOX *)psWidget;
725748
CurrFontID = psEdBox->FontID;
@@ -729,9 +752,12 @@ void editBoxDisplay(WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset, PIELIGHT *
729752
x1=x0 + psEdBox->width;
730753
y1=y0 + psEdBox->height;
731754

732-
if(psEdBox->pBoxDisplay) {
755+
if(psEdBox->pBoxDisplay)
756+
{
733757
psEdBox->pBoxDisplay((WIDGET *)psEdBox, xOffset, yOffset, pColours);
734-
} else {
758+
}
759+
else
760+
{
735761
pie_BoxFill(x0, y0, x1, y1, pColours[WCOL_BKGRND]);
736762

737763
iV_Line(x0,y0, x1,y0, pColours[WCOL_DARK]);
@@ -745,41 +771,50 @@ void editBoxDisplay(WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset, PIELIGHT *
745771
iV_SetFont(CurrFontID);
746772
iV_SetTextColour(pColours[WCOL_TEXT]);
747773

748-
fy = y0 + (psEdBox->height - iV_GetTextLineSize())/2 - iV_GetTextAboveBase();
774+
fy = y0 + (psEdBox->height - iV_GetTextLineSize())/2 - iV_GetTextAboveBase();
749775

776+
/* If there is more text than will fit into the box, display the bit with the cursor in it */
777+
size = utf32len(psEdBox->aText);
778+
UTF32string = malloc( sizeof(utf_32_char) * size + sizeof(utf_32_char));
779+
memcpy(UTF32string, psEdBox->aText, sizeof(utf_32_char) * size);
750780

751-
/* If there is more text than will fit into the box,
752-
display the bit with the cursor in it */
753-
pPrint = psEdBox->aText + psEdBox->printStart;
754-
pInsPoint = pPrint + psEdBox->printChars;
755-
ch = *pInsPoint;
781+
pInsPoint = UTF32string + psEdBox->printStart; // deal with position
782+
pInsPoint[psEdBox->printChars] = 0;
783+
784+
utf = UTF32toUTF8(pInsPoint, NULL);
756785

757-
*pInsPoint = '\0';
758-
utf = UTF32toUTF8(pPrint, NULL);
759786
#ifdef WZ_OS_MAC
760787
iV_DrawText(utf, fx, fy+2);
761788
#else
762789
iV_DrawText(utf, fx, fy);
763790
#endif
764791
free(utf);
765-
*pInsPoint = ch;
792+
free(UTF32string);
766793

767-
/* Display the cursor if editing */
794+
// Display the cursor if editing
768795
#if CURSOR_BLINK
769796
blink = !(((SDL_GetTicks() - psEdBox->blinkOffset)/WEDB_BLINKRATE) % 2);
770797
if ((psEdBox->state & WEDBS_MASK) == WEDBS_INSERT && blink)
771798
#else
772799
if ((psEdBox->state & WEDBS_MASK) == WEDBS_INSERT)
773800
#endif
774801
{
775-
pInsPoint = psEdBox->aText + psEdBox->insPos;
776-
ch = *pInsPoint;
777-
*pInsPoint = '\0';
778-
utf = UTF32toUTF8(psEdBox->aText + psEdBox->printStart, NULL);
802+
// insert mode
803+
804+
utf_32_char *pInsPoint, *UTF32string;
805+
int size=0;
806+
807+
size = utf32len(psEdBox->aText);
808+
UTF32string = malloc( sizeof(utf_32_char) * size + sizeof(utf_32_char));
809+
memcpy(UTF32string, psEdBox->aText, sizeof(utf_32_char) * size);
810+
811+
pInsPoint = UTF32string + psEdBox->insPos; // deal with position
812+
*pInsPoint = 0;
813+
utf = UTF32toUTF8(UTF32string + psEdBox->printStart, NULL);
779814
cx = x0 + WEDB_XGAP + iV_GetTextWidth(utf);
780815
cx += iV_GetTextWidth("-");
781816
free(utf);
782-
*pInsPoint = ch;
817+
free(UTF32string);
783818
cy = fy;
784819
iV_Line(cx, cy + iV_GetTextAboveBase(), cx, cy - iV_GetTextBelowBase(), pColours[WCOL_CURSOR]);
785820
}
@@ -789,19 +824,26 @@ void editBoxDisplay(WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset, PIELIGHT *
789824
else if ((psEdBox->state & WEDBS_MASK) == WEDBS_OVER)
790825
#endif
791826
{
792-
pInsPoint = psEdBox->aText + psEdBox->insPos;
793-
ch = *pInsPoint;
794-
*pInsPoint = '\0';
795-
utf = UTF32toUTF8(psEdBox->aText + psEdBox->printStart, NULL);
827+
// overwrite mode
828+
utf_32_char *pInsPoint, *UTF32string;
829+
int size=0;
830+
831+
size = utf32len(psEdBox->aText);
832+
UTF32string = malloc( sizeof(utf_32_char) * size + sizeof(utf_32_char));
833+
memcpy(UTF32string, psEdBox->aText, sizeof(utf_32_char) * size);
834+
835+
pInsPoint = UTF32string + psEdBox->insPos; // deal with position
836+
*pInsPoint = 0;
837+
utf = UTF32toUTF8(UTF32string + psEdBox->printStart, NULL);
796838
cx = x0 + WEDB_XGAP + iV_GetTextWidth(utf);
797839
free(utf);
798-
*pInsPoint = ch;
799-
cy = fy;
840+
free(UTF32string);
841+
cy = fy;
800842
iV_Line(cx, cy, cx + WEDB_CURSORSIZE, cy, pColours[WCOL_CURSOR]);
801843
}
802844

803-
804-
if(psEdBox->pBoxDisplay == NULL) {
845+
if(psEdBox->pBoxDisplay == NULL)
846+
{
805847
if (psEdBox->state & WEDBS_HILITE)
806848
{
807849
/* Display the button hilite */

0 commit comments

Comments
 (0)