From f0c407e7d468bc5acfd8d436be7f79f6e6248421 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Mon, 21 Nov 2011 12:38:18 +0800 Subject: [PATCH] Usermode/AxWin3 - Added delete support to text input - Moved UTF-8 code out from wm_render_text.c - Added max bytes to text render functions > Note: They have a Feature-Bug where it will over-read by up to 3 bytes > Due to the UTF-8 parsing code, and is useful in some cases. - Added INT_MIN and INT_MAX --- Usermode/Applications/axwin3_src/WM/Makefile | 2 +- .../Applications/axwin3_src/WM/decorator.c | 4 +- .../Applications/axwin3_src/WM/include/utf8.h | 18 +++ .../Applications/axwin3_src/WM/include/wm.h | 28 +++- Usermode/Applications/axwin3_src/WM/input.c | 10 +- .../axwin3_src/WM/renderers/menu.c | 17 +- .../axwin3_src/WM/renderers/widget/disptext.c | 4 +- .../WM/renderers/widget/textinput.c | 126 +++++++++++++-- Usermode/Applications/axwin3_src/WM/utf-8.c | 153 ++++++++++++++++++ .../Applications/axwin3_src/WM/wm_input.c | 3 + .../axwin3_src/WM/wm_render_text.c | 91 +++-------- Usermode/include/stdint.h | 3 + 12 files changed, 350 insertions(+), 109 deletions(-) create mode 100644 Usermode/Applications/axwin3_src/WM/include/utf8.h create mode 100644 Usermode/Applications/axwin3_src/WM/utf-8.c diff --git a/Usermode/Applications/axwin3_src/WM/Makefile b/Usermode/Applications/axwin3_src/WM/Makefile index a8d77cf7..f0f93216 100644 --- a/Usermode/Applications/axwin3_src/WM/Makefile +++ b/Usermode/Applications/axwin3_src/WM/Makefile @@ -6,7 +6,7 @@ CPPFLAGS += -I include/ -I ../include/ DIR := Apps/AxWin/3.0 BIN := AxWinWM -OBJ := main.o input.o video.o ipc.o image.o +OBJ := main.o input.o video.o ipc.o image.o utf-8.o OBJ += wm.o wm_input.o wm_render.o wm_render_text.o OBJ += decorator.o OBJ += renderers/passthru.o diff --git a/Usermode/Applications/axwin3_src/WM/decorator.c b/Usermode/Applications/axwin3_src/WM/decorator.c index f91c0cad..937fb18b 100644 --- a/Usermode/Applications/axwin3_src/WM/decorator.c +++ b/Usermode/Applications/axwin3_src/WM/decorator.c @@ -83,7 +83,7 @@ void Decorator_Redraw(tWindow *Window) WM_Render_GetTextDims( NULL, // TODO: Select font - Window->Title ? Window->Title : "jI", + Window->Title ? Window->Title : "jI", -1, &text_width, &text_height ); WM_Render_DrawText(Window, @@ -91,7 +91,7 @@ void Decorator_Redraw(tWindow *Window) Window->W - ciTitlebarHeight - 4, text_height, NULL, // TODO: Select font (bActive ? cColourActive_TitleText : cColourInactive_TitleText), - Window->Title ? Window->Title : "--" + Window->Title ? Window->Title : "--", -1 ); // Maximized windows don't have any other borders diff --git a/Usermode/Applications/axwin3_src/WM/include/utf8.h b/Usermode/Applications/axwin3_src/WM/include/utf8.h new file mode 100644 index 00000000..3ecaeb08 --- /dev/null +++ b/Usermode/Applications/axwin3_src/WM/include/utf8.h @@ -0,0 +1,18 @@ +/* + * Acess2 GUI (AxWin) Version 3 + * - By John Hodge (thePowersGang) + * + * utf8.h + * - UTF-8 Parsing header + */ +#ifndef _UTF8_H_ +#define _UTF8_H_ + +#include + +extern int ReadUTF8(const char *Input, uint32_t *Val); +extern int ReadUTF8Rev(const char *Base, int Offset, uint32_t *Val); +extern int WriteUTF8(char *buf, uint32_t Val); + +#endif + diff --git a/Usermode/Applications/axwin3_src/WM/include/wm.h b/Usermode/Applications/axwin3_src/WM/include/wm.h index ad67f231..7807c901 100644 --- a/Usermode/Applications/axwin3_src/WM/include/wm.h +++ b/Usermode/Applications/axwin3_src/WM/include/wm.h @@ -57,8 +57,32 @@ extern int WM_SendMessage(tWindow *Source, tWindow *Dest, int MessageID, int Len // --- Rendering extern void WM_Render_FillRect(tWindow *Window, int X, int Y, int W, int H, tColour Colour); extern void WM_Render_DrawRect(tWindow *Window, int X, int Y, int W, int H, tColour Colour); -extern int WM_Render_DrawText(tWindow *Window, int X, int Y, int W, int H, tFont *Font, tColour Colour, const char *Text); -extern void WM_Render_GetTextDims(tFont *Font, const char *Text, int *W, int *H); +/** + * \brief Draw text to a window + * \param Window Destination Window + * \param X X coordinate (Left) + * \param Y Y coordinate (Top) + * \param W Width of destination region + * \param H Height of destination region + * \param Font Font to use + * \param Colour Text foreground colour + * \param Text UTF-8 string to render + * \param MaxLen Number of bytes in \a Text to read (Note: A final multi-byte sequence can exceed this count) + * + * \note As as noted in the \a MaxLen parameter, up to 3 more bytes may be read + * if the final character is a multi-byte UTF-8 sequence. This allows 1 + * to be passed to only render a single character. + */ +extern int WM_Render_DrawText(tWindow *Window, int X, int Y, int W, int H, tFont *Font, tColour Colour, const char *Text, int MaxLen); +/** + * \brief Get the dimensions of a string if it was rendered + * \param Font Font to use + * \param Text UTF-8 string to be processed + * \param MaxLen Number of bytes in \a Text to read (same caveat as WM_Render_DrawText applies) + * \param W Pointer to an integer to store the width of the rendered text + * \param H Pointer to an integer to store the height of the rendered text + */ +extern void WM_Render_GetTextDims(tFont *Font, const char *Text, int MaxLen, int *W, int *H); extern void WM_Render_DrawImage(tWindow *Window, int X, int Y, int W, int H, tImage *Image); extern void WM_Render_SetTextCursor(tWindow *Window, int X, int Y, int W, int H, tColour Colour); // NOTE: Should really be elsewhere diff --git a/Usermode/Applications/axwin3_src/WM/input.c b/Usermode/Applications/axwin3_src/WM/input.c index 45985028..da5b0d33 100644 --- a/Usermode/Applications/axwin3_src/WM/input.c +++ b/Usermode/Applications/axwin3_src/WM/input.c @@ -74,17 +74,20 @@ void Input_HandleSelect(fd_set *set) if( read(giTerminalFD, &codepoint, sizeof(codepoint)) != sizeof(codepoint) ) { // oops, error + _SysDebug("Terminal read failed?"); } +// _SysDebug("Keypress 0x%x", codepoint); + switch(codepoint & 0xC0000000) { case 0x00000000: // Key pressed WM_Input_KeyDown(codepoint & KEY_CODEPOINT_MASK, scancode); - case 0x40000000: // Key refire + case 0x80000000: // Key release WM_Input_KeyFire(codepoint & KEY_CODEPOINT_MASK, scancode); scancode = 0; break; - case 0x80000000: // Key release + case 0x40000000: // Key refire WM_Input_KeyUp(codepoint & KEY_CODEPOINT_MASK, scancode); scancode = 0; break; @@ -92,9 +95,6 @@ void Input_HandleSelect(fd_set *set) scancode = codepoint & KEY_CODEPOINT_MASK; break; } - - // TODO: pass on to message handler - _SysDebug("Keypress 0x%x", codepoint); } if(FD_ISSET(giMouseFD, set)) diff --git a/Usermode/Applications/axwin3_src/WM/renderers/menu.c b/Usermode/Applications/axwin3_src/WM/renderers/menu.c index 7e286709..ffd1db0d 100644 --- a/Usermode/Applications/axwin3_src/WM/renderers/menu.c +++ b/Usermode/Applications/axwin3_src/WM/renderers/menu.c @@ -168,7 +168,7 @@ void Renderer_Menu_Redraw(tWindow *Window) w, ciMenu_ItemHeight, gMenu_Font, cMenu_LabelColour, - item->Label + item->Label, -1 ); // Underline if(item->UnderlineW) @@ -188,7 +188,7 @@ void Renderer_Menu_Redraw(tWindow *Window) w, ciMenu_ItemHeight, gMenu_Font, cMenu_ShortcutColour, - item->Shortcut + item->Shortcut, -1 ); } @@ -277,23 +277,20 @@ int Renderer_Menu_int_AddItem(tWindow *Window, int Length, const tMenuMsg_AddIte { char tmp = item->Label[item->KeyOffset]; // Get width of preceding substring - item->Label[item->KeyOffset] = '\0'; - WM_Render_GetTextDims(NULL, item->Label, &item->UnderlineX, NULL); + WM_Render_GetTextDims(NULL, item->Label, item->KeyOffset, &item->UnderlineX, NULL); // Get the width of the underlined character - // TODO: Fix for high UTF-8 characters item->Label[item->KeyOffset] = tmp; - tmp = item->Label[item->KeyOffset+1]; - item->Label[item->KeyOffset+1] = '\0'; + // NOTE: 1 makes only one character be parsed, even if it is >1 byte long WM_Render_GetTextDims( - NULL, item->Label+item->KeyOffset, + NULL, item->Label+item->KeyOffset, 1, &item->UnderlineW, NULL ); item->Label[item->KeyOffset+1] = tmp; } // - Labels - WM_Render_GetTextDims(NULL, item->Label, &item->LabelWidth, NULL); + WM_Render_GetTextDims(NULL, item->Label, -1, &item->LabelWidth, NULL); if(item->Shortcut) - WM_Render_GetTextDims(NULL, item->Shortcut, &item->ShortcutWidth, NULL); + WM_Render_GetTextDims(NULL, item->Shortcut, -1, &item->ShortcutWidth, NULL); else item->ShortcutWidth = 0; diff --git a/Usermode/Applications/axwin3_src/WM/renderers/widget/disptext.c b/Usermode/Applications/axwin3_src/WM/renderers/widget/disptext.c index dfdb3580..d3abdea1 100644 --- a/Usermode/Applications/axwin3_src/WM/renderers/widget/disptext.c +++ b/Usermode/Applications/axwin3_src/WM/renderers/widget/disptext.c @@ -17,7 +17,7 @@ void Widget_DispText_Render(tWindow *Window, tElement *Element) Element->CachedX+1, Element->CachedY+1, Element->CachedW-2, Element->CachedH-2, NULL, TEXT_COLOUR, - Element->Text + Element->Text, -1 ); } @@ -28,7 +28,7 @@ void Widget_DispText_UpdateText(tElement *Element, const char *Text) if(Element->Text) free(Element->Text); Element->Text = strdup(Text); - WM_Render_GetTextDims(NULL, Element->Text, &w, &h); + WM_Render_GetTextDims(NULL, Element->Text, -1, &w, &h); // Apply edge padding w += 2; h += 2; diff --git a/Usermode/Applications/axwin3_src/WM/renderers/widget/textinput.c b/Usermode/Applications/axwin3_src/WM/renderers/widget/textinput.c index 7c077003..2e21e789 100644 --- a/Usermode/Applications/axwin3_src/WM/renderers/widget/textinput.c +++ b/Usermode/Applications/axwin3_src/WM/renderers/widget/textinput.c @@ -10,18 +10,56 @@ #include #include "./common.h" #include "./colours.h" +#include +#include struct sTextInputInfo { int DrawOfs; // Byte offset for the leftmost character int CursorXOfs; // Pixel offset of the cursor + + int CursorByteOfs; + int Length; }; +// === CONSTANTS === +const int ciTextInput_MarginT = 3; +const int ciTextInput_MarginB = 3; +const int ciTextInput_MarginV = 6; // Sum of above +const int ciTextInput_MarginL = 3; +const int ciTextInput_MarginR = 3; +const int ciTextInput_MarginH = 6; + +// === GLOBALS === +tFont *gpTextInput_Font = NULL; + +// === CODE === void Widget_TextInput_Render(tWindow *Window, tElement *Element) { struct sTextInputInfo *info = (void*)Element->Data; struct sWidgetWin *wininfo = Window->RendererInfo; + // Scroll view when X offset reaches either end + while(info->CursorXOfs >= Element->CachedW - ciTextInput_MarginH) + { + int w; + uint32_t cp; + info->DrawOfs += ReadUTF8( &Element->Text[info->DrawOfs], &cp ); + WM_Render_GetTextDims( + gpTextInput_Font, + &Element->Text[info->DrawOfs], info->CursorByteOfs - info->DrawOfs, + &w, NULL + ); + info->CursorXOfs = w; + } + if(info->CursorXOfs < 0) + { + info->DrawOfs = info->CursorByteOfs; + info->CursorXOfs = 0; + } + + + // Borders WM_Render_FillRect(Window, Element->CachedX, Element->CachedY, Element->CachedW, Element->CachedH, @@ -39,21 +77,21 @@ void Widget_TextInput_Render(tWindow *Window, tElement *Element) ); // Text + // - Pre-cursor WM_Render_DrawText(Window, - Element->CachedX+2, Element->CachedY+2, - Element->CachedW-4, Element->CachedW-4, - NULL, TEXTINPUT_TEXT, - &Element->Text[info->DrawOfs] + Element->CachedX+ciTextInput_MarginL, Element->CachedY+ciTextInput_MarginT, + Element->CachedW-ciTextInput_MarginH, Element->CachedH-ciTextInput_MarginV, + gpTextInput_Font, TEXTINPUT_TEXT, + &Element->Text[info->DrawOfs], -1 ); - // TODO: Determine if this element has focus + // Cursor if( wininfo->FocusedElement == Element ) { - // TODO: Multiple Cursors WM_Render_SetTextCursor(Window, - Element->CachedX+2+info->CursorXOfs, - Element->CachedY+2, - 1, Element->CachedH-4, + Element->CachedX+ciTextInput_MarginL+info->CursorXOfs, + Element->CachedY+ciTextInput_MarginR, + 1, Element->CachedH-ciTextInput_MarginV, TEXTINPUT_TEXT ); } @@ -65,12 +103,12 @@ void Widget_TextInput_Init(tElement *Element) int h; // TODO: Select font correctly - WM_Render_GetTextDims(NULL, "jJ", NULL, &h); + WM_Render_GetTextDims(gpTextInput_Font, "jy|qJ", -1, NULL, &h); - h += 2+2; // Border padding + h += ciTextInput_MarginV; // Border padding Element->MinH = h; - Element->MinW = 4; + Element->MinW = ciTextInput_MarginH; info = Element->Data = malloc(sizeof(*info)); info->DrawOfs = 0; @@ -79,9 +117,69 @@ void Widget_TextInput_Init(tElement *Element) // No need to explicitly update parent min dims, as the AddElement routine does that } -int Widget_TextInput_KeyFire(tElement *Ele, int KeySym, int Character) +int Widget_TextInput_KeyFire(tElement *Element, int KeySym, int Character) { - _SysDebug("Key 0x%x fired ('%c')", Character, Character); + struct sTextInputInfo *info = Element->Data; + int len; + int w; + char *dest; + uint32_t cp; + +// _SysDebug("Key 0x%x fired ('%c')", Character, Character); + + if( Character == 0 ) + return 0; + + // TODO: Don't hard code + if(Character > 0x30000000) return 0; + + switch(Character) + { + case '\t': + return 0; + + case '\b': + // Check if there is anything to delete + if( info->CursorByteOfs == 0 ) return 0; + // Get character to be deleted + len = ReadUTF8Rev(Element->Text, info->CursorByteOfs, &cp); + info->CursorByteOfs -= len; + dest = &Element->Text[info->CursorByteOfs]; +// _SysDebug("\\b, len = %i, removing '%.*s'", len, len, dest); + WM_Render_GetTextDims(gpTextInput_Font, dest, len, &w, 0); + // Remove from buffer + memmove(dest, &dest[len], info->Length - info->CursorByteOfs - len); + info->Length -= len; + Element->Text[info->Length] = '\0'; + // Adjust cursor + info->CursorXOfs -= w; + break; + default: + if(Character >= 0x30000000) return 0; + if(Character < ' ') return 0; + + // Get required length + len = WriteUTF8(NULL, Character); + + // Create space (possibly in the middle) + Element->Text = realloc(Element->Text, info->Length + len + 1); + dest = &Element->Text[info->CursorByteOfs]; + memmove(&dest[len], dest, info->Length - info->CursorByteOfs); + // Add the character + WriteUTF8(dest, Character); + info->CursorByteOfs += len; + info->Length += len; + Element->Text[info->Length] = '\0'; + + // Update the cursor position + // - Scrolling is implemented in render function (CachedW/CachedH are invalid atm) + WM_Render_GetTextDims(gpTextInput_Font, dest, len, &w, NULL); + info->CursorXOfs += w; + } + + // TODO: Have a Widget_ function to do this instead + WM_Invalidate(Element->Window); + return 0; } diff --git a/Usermode/Applications/axwin3_src/WM/utf-8.c b/Usermode/Applications/axwin3_src/WM/utf-8.c new file mode 100644 index 00000000..5c088281 --- /dev/null +++ b/Usermode/Applications/axwin3_src/WM/utf-8.c @@ -0,0 +1,153 @@ +/* + * Acess2 GUI (AxWin) Version 3 + * - By John Hodge (thePowersGang) + * + * utf-8.c + * - UTF-8 Parsing code + */ +#include +#include + +/** + * \brief Read a UTF-8 character from a string + * \param Input Source UTF-8 encoded string + * \param Val Destination for read codepoint + * \return Number of bytes read/used + */ +int ReadUTF8(const char *Input, uint32_t *Val) +{ + const uint8_t *str = (const uint8_t *)Input; + *Val = 0xFFFD; // Assume invalid character + + // ASCII + if( !(*str & 0x80) ) { + *Val = *str; + return 1; + } + + // Middle of a sequence + if( (*str & 0xC0) == 0x80 ) { + return 1; + } + + // Two Byte + if( (*str & 0xE0) == 0xC0 ) { + *Val = (*str & 0x1F) << 6; // Upper 6 Bits + str ++; + if( (*str & 0xC0) != 0x80) return -1; // Validity check + *Val |= (*str & 0x3F); // Lower 6 Bits + return 2; + } + + // Three Byte + if( (*str & 0xF0) == 0xE0 ) { + *Val = (*str & 0x0F) << 12; // Upper 4 Bits + str ++; + if( (*str & 0xC0) != 0x80) return -1; // Validity check + *Val |= (*str & 0x3F) << 6; // Middle 6 Bits + str ++; + if( (*str & 0xC0) != 0x80) return -1; // Validity check + *Val |= (*str & 0x3F); // Lower 6 Bits + return 3; + } + + // Four Byte + if( (*str & 0xF1) == 0xF0 ) { + *Val = (*str & 0x07) << 18; // Upper 3 Bits + str ++; + if( (*str & 0xC0) != 0x80) return -1; // Validity check + *Val |= (*str & 0x3F) << 12; // Middle-upper 6 Bits + str ++; + if( (*str & 0xC0) != 0x80) return -1; // Validity check + *Val |= (*str & 0x3F) << 6; // Middle-lower 6 Bits + str ++; + if( (*str & 0xC0) != 0x80) return -1; // Validity check + *Val |= (*str & 0x3F); // Lower 6 Bits + return 4; + } + + // UTF-8 Doesn't support more than four bytes + return 4; +} + +/** + * \brief Get the UTF-8 character before the + * \ + */ +int ReadUTF8Rev(const char *Base, int Offset, uint32_t *Val) +{ + int len = 0; + + // Scan backwards for the beginning of the character + while( Offset > 0 && (Base[Offset--] & 0xC0) == 0x80 ) + len ++; + // Invalid string (no beginning) + if(Offset == 0 && (Base[Offset] & 0xC0) == 0x80 ) + return len; + + len ++; // First character + if( ReadUTF8(Base+Offset, Val) != len ) { + *Val = 0xFFFD; + } + return len; +} + +/** + * \brief Write a UTF-8 character sequence to a string + * \param buf Destination buffer (must have at least 4 bytes available) + * \param Val Unicode codepoint to write + * \return Number of bytes written + * \note Does not NULL terminate the string in \a buf + */ +int WriteUTF8(char *buf, uint32_t Val) +{ + uint8_t *str = (void*)buf; + + // ASCII + if( Val < 128 ) { + if(str) { + *str = Val; + } + return 1; + } + + // Two Byte + if( Val < 0x8000 ) { + if(str) { + *str = 0xC0 | (Val >> 6); + str ++; + *str = 0x80 | (Val & 0x3F); + } + return 2; + } + + // Three Byte + if( Val < 0x10000 ) { + if(str) { + *str = 0xE0 | (Val >> 12); + str ++; + *str = 0x80 | ((Val >> 6) & 0x3F); + str ++; + *str = 0x80 | (Val & 0x3F); + } + return 3; + } + + // Four Byte + if( Val < 0x110000 ) { + if(str) { + *str = 0xF0 | (Val >> 18); + str ++; + *str = 0x80 | ((Val >> 12) & 0x3F); + str ++; + *str = 0x80 | ((Val >> 6) & 0x3F); + str ++; + *str = 0x80 | (Val & 0x3F); + } + return 4; + } + + // UTF-8 Doesn't support more than four bytes + return 0; +} + diff --git a/Usermode/Applications/axwin3_src/WM/wm_input.c b/Usermode/Applications/axwin3_src/WM/wm_input.c index dc8d8acb..1fc49f8e 100644 --- a/Usermode/Applications/axwin3_src/WM/wm_input.c +++ b/Usermode/Applications/axwin3_src/WM/wm_input.c @@ -122,6 +122,9 @@ void WM_Input_KeyDown(uint32_t Character, uint32_t Scancode) void WM_Input_KeyFire(uint32_t Character, uint32_t Scancode) { struct sWndMsg_KeyAction msg; + + // TODO: Properly translate into KeySyms and Unicode + msg.KeySym = Scancode; msg.UCS32 = Character; WM_SendMessage(NULL, gpWM_FocusedWindow, WNDMSG_KEYFIRE, sizeof(msg), &msg); diff --git a/Usermode/Applications/axwin3_src/WM/wm_render_text.c b/Usermode/Applications/axwin3_src/WM/wm_render_text.c index 4ce35cb7..d189e5e0 100644 --- a/Usermode/Applications/axwin3_src/WM/wm_render_text.c +++ b/Usermode/Applications/axwin3_src/WM/wm_render_text.c @@ -8,6 +8,7 @@ #include #include #include +#include // === TYPES === typedef struct sGlyph tGlyph; @@ -51,12 +52,11 @@ struct sFont // === PROTOTYPES === - int WM_Render_DrawText(tWindow *Window, int X, int Y, int W, int H, tFont *Font, tColour Color, const char *Text); -void WM_Render_GetTextDims(tFont *Font, const char *Text, int *W, int *H); + int WM_Render_DrawText(tWindow *Window, int X, int Y, int W, int H, tFont *Font, tColour Color, const char *Text, int MaxLen); +void WM_Render_GetTextDims(tFont *Font, const char *Text, int MaxLen, int *W, int *H); tGlyph *_GetGlyph(tFont *Font, uint32_t Codepoint); void _RenderGlyph(tWindow *Window, short X, short Y, tGlyph *Glyph, uint32_t Color); tGlyph *_SystemFont_CacheGlyph(tFont *Font, uint32_t Codepoint); - int ReadUTF8(const char *Input, uint32_t *Output); // === GLOBALS === tFont gSystemFont = { @@ -67,7 +67,7 @@ tFont gSystemFont = { /** * \brief Draw text to the screen */ -int WM_Render_DrawText(tWindow *Window, int X, int Y, int W, int H, tFont *Font, tColour Colour, const char *Text) +int WM_Render_DrawText(tWindow *Window, int X, int Y, int W, int H, tFont *Font, tColour Colour, const char *Text, int MaxLen) { int xOfs = 0; tGlyph *glyph; @@ -78,6 +78,7 @@ int WM_Render_DrawText(tWindow *Window, int X, int Y, int W, int H, tFont *Font, if(!Text) return 0; + if(MaxLen < 0) MaxLen = INT_MAX; X += Window->BorderL; Y += Window->BorderT; @@ -94,10 +95,13 @@ int WM_Render_DrawText(tWindow *Window, int X, int Y, int W, int H, tFont *Font, // Handle NULL font (system default monospace) if( !Font ) Font = &gSystemFont; - while( *Text ) + while( MaxLen > 0 && *Text ) { + int len; // Read character - Text += ReadUTF8(Text, &ch); + len = ReadUTF8(Text, &ch); + Text += len; + MaxLen -= len; // Find (or load) the glyph glyph = _GetGlyph(Font, ch); @@ -114,16 +118,21 @@ int WM_Render_DrawText(tWindow *Window, int X, int Y, int W, int H, tFont *Font, return xOfs; } -void WM_Render_GetTextDims(tFont *Font, const char *Text, int *W, int *H) +void WM_Render_GetTextDims(tFont *Font, const char *Text, int MaxLen, int *W, int *H) { int w=0, h=0; uint32_t ch; tGlyph *glyph; if( !Font ) Font = &gSystemFont; - while( *Text ) + if(MaxLen < 0) MaxLen = INT_MAX; + + while( MaxLen > 0 && *Text ) { - Text += ReadUTF8(Text, &ch); + int len; + len = ReadUTF8(Text, &ch); + Text += len; + MaxLen -= len; glyph = _GetGlyph(Font, ch); if( !glyph ) continue; @@ -316,67 +325,3 @@ tGlyph *_SystemFont_CacheGlyph(tFont *Font, uint32_t Codepoint) return ret; } - -/** - * \fn int ReadUTF8(char *Input, uint32_t *Val) - * \brief Read a UTF-8 character from a string - */ -int ReadUTF8(const char *Input, uint32_t *Val) -{ - const uint8_t *str = (const uint8_t *)Input; - *Val = 0xFFFD; // Assume invalid character - - // ASCII - if( !(*str & 0x80) ) { - *Val = *str; - return 1; - } - - // Middle of a sequence - if( (*str & 0xC0) == 0x80 ) { - return 1; - } - - // Two Byte - if( (*str & 0xE0) == 0xC0 ) { - *Val = (*str & 0x1F) << 6; // Upper 6 Bits - str ++; - if( (*str & 0xC0) != 0x80) return -1; // Validity check - *Val |= (*str & 0x3F); // Lower 6 Bits - return 2; - } - - // Three Byte - if( (*str & 0xF0) == 0xE0 ) { - *Val = (*str & 0x0F) << 12; // Upper 4 Bits - str ++; - if( (*str & 0xC0) != 0x80) return -1; // Validity check - *Val |= (*str & 0x3F) << 6; // Middle 6 Bits - str ++; - if( (*str & 0xC0) != 0x80) return -1; // Validity check - *Val |= (*str & 0x3F); // Lower 6 Bits - return 3; - } - - // Four Byte - if( (*str & 0xF1) == 0xF0 ) { - *Val = (*str & 0x07) << 18; // Upper 3 Bits - str ++; - if( (*str & 0xC0) != 0x80) return -1; // Validity check - *Val |= (*str & 0x3F) << 12; // Middle-upper 6 Bits - str ++; - if( (*str & 0xC0) != 0x80) return -1; // Validity check - *Val |= (*str & 0x3F) << 6; // Middle-lower 6 Bits - str ++; - if( (*str & 0xC0) != 0x80) return -1; // Validity check - *Val |= (*str & 0x3F); // Lower 6 Bits - return 4; - } - - // UTF-8 Doesn't support more than four bytes - return 4; -} - - - - diff --git a/Usermode/include/stdint.h b/Usermode/include/stdint.h index 477f8ebd..d0f949ef 100644 --- a/Usermode/include/stdint.h +++ b/Usermode/include/stdint.h @@ -3,6 +3,9 @@ #ifndef _STDINT_H_ #define _STDINT_H_ +#define INT_MIN -0x80000000 +#define INT_MAX 0x7FFFFFFF + typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; -- 2.20.1