From 188d9f736fe9ae43a3169bbd638b0e0816f8efeb Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Sat, 6 Jun 2020 22:29:06 -0400 Subject: [PATCH] Reintegrated UTF-16 stuff we need immediately and prepared the test suite for it. --- test/test.h | 10 +++++ test/utf8.c | 59 +++++++++++++++++++++++++++++ windows/meson.build | 2 + windows/uipriv_windows.hpp | 4 ++ {zOLD_windows => windows}/utf16.cpp | 11 ++++-- windows/window.cpp | 21 ++++------ windows/winhresult.cpp | 8 ++++ windows/winhresult.hpp | 1 + 8 files changed, 100 insertions(+), 16 deletions(-) rename {zOLD_windows => windows}/utf16.cpp (93%) diff --git a/test/test.h b/test/test.h index 085a663d..8e54daae 100644 --- a/test/test.h +++ b/test/test.h @@ -96,9 +96,19 @@ extern const char testUTF8WithFourByte[]; extern const char testUTF8Combined[]; extern const char testUTF8InvalidInput[]; extern const char testUTF8InvalidOutput[]; +extern const uint16_t testUTF16Empty[]; +extern const uint16_t testUTF16ASCIIOnly[]; +extern const uint16_t testUTF16WithTwoByte[]; +extern const uint16_t testUTF16WithThreeByte[]; +extern const uint16_t testUTF16WithFourByte[]; +extern const uint16_t testUTF16Combined[]; +extern const uint16_t testUTF16InvalidOutput[]; extern bool utf8equal(const char *s, const char *t); extern void utf8diffErrorFull(const char *file, long line, const char *msg, const char *got, const char *want); #define utf8diffError(msg, got, want) utf8diffErrorFull(__FILE__, __LINE__, msg, got, want) +extern bool utf16equal(const uint16_t *s, const uint16_t *t); +extern void utf16diffErrorFull(const char *file, long line, const char *msg, const uint16_t *got, const uint16_t *want); +#define utf16diffError(msg, got, want) utf16diffErrorFull(__FILE__, __LINE__, msg, got, want) #ifdef __cplusplus } diff --git a/test/utf8.c b/test/utf8.c index 8a073e80..7b3e8b37 100644 --- a/test/utf8.c +++ b/test/utf8.c @@ -43,6 +43,16 @@ const char testUTF8WithFourByte[] = { 0x74, 0xF0, 0x9D, 0x90, 0x9E, 0x73, 0x74, const char testUTF8Combined[] = { 0x74, 0x65, 0xCC, 0x81, 0x73, 0x74, 0 }; const char testUTF8InvalidInput[] = { 0x74, 0xC3, 0x29, 0x73, 0x74, 0 }; const char testUTF8InvalidOutput[] = { 0x74, 0xEF, 0xBF, 0xBD, 0x29, 0x73, 0x74, 0 }; +// TODO multiline versions + +const uint16_t testUTF16Empty[] = { 0 }; +const uint16_t testUTF16ASCIIOnly[] = { 0x0074, 0x0065, 0x0073, 0x0074, 0 }; +const uint16_t testUTF16WithTwoByte[] = { 0x0074, 0x00E9, 0x0073, 0x0074, 0 }; +const uint16_t testUTF16WithThreeByte[] = { 0x0074, 0x24D4, 0x0073, 0x0074, 0 }; +const uint16_t testUTF16WithFourByte[] = { 0x0074, 0xD835, 0xDC1E, 0x0073, 0x0074, 0 }; +const uint16_t testUTF16Combined[] = { 0x0074, 0x0065, 0x0301, 0x0073, 0x0074, 0 }; +// no UTF-16 invalid input since we don't input UTF-16 +const uint16_t testUTF16InvalidOutput[] = { 0x0074, 0xFFFD, 0x0029, 0x0073, 0x0074, 0 }; // TODO figure out if strcmp() is adequate for this bool utf8equal(const char *s, const char *t) @@ -91,3 +101,52 @@ void utf8diffErrorFull(const char *file, long line, const char *msg, const char utf8hexdump(b, want); TestErrorfFull(file, line, "%s:" diff("%s"), msg, a, b); } + +bool utf16equal(const uint16_t *s, const uint16_t *t) +{ + for (;;) { + if (*s == 0 && *t == 0) + return true; + if (*s == 0 || *t == 0) + return false; + if (*s != *t) + return false; + s++; + t++; + } +} + +static void utf16hexdump(char buf[64], const uint16_t *s) +{ + int i; + uint16_t x; + + for (i = 0; i < 60; i += 5) { + x = (uint16_t) (*s); + s++; + buf[i + 0] = "0123456789ABCDEF"[(x & 0xF000) >> 12]; + buf[i + 1] = "0123456789ABCDEF"[(x & 0x0F00) >> 8]; + buf[i + 2] = "0123456789ABCDEF"[(x & 0x00F0) >> 4]; + buf[i + 3] = "0123456789ABCDEF"[x & 0x000F]; + if (x == 0) { + buf[i + 4] = '\0'; + break; + } + buf[i + 4] = ' '; + } + if (i >= 60) { + buf[60] = '.'; + buf[61] = '.'; + buf[62] = '.'; + buf[63] = '\0'; + } +} + +void utf16diffErrorFull(const char *file, long line, const char *msg, const uint16_t *got, const uint16_t *want) +{ + char a[64], b[64]; + + utf16hexdump(a, got); + utf16hexdump(b, want); + TestErrorfFull(file, line, "%s:" diff("%s"), msg, a, b); +} diff --git a/windows/meson.build b/windows/meson.build index 2528f009..d480a5d9 100644 --- a/windows/meson.build +++ b/windows/meson.build @@ -5,7 +5,9 @@ windows = import('windows') libui_sources += [ 'windows/controls.cpp', 'windows/main.cpp', + 'windows/utf16.cpp', 'windows/utilwin.cpp', + 'windows/window.cpp', 'windows/winhresult.cpp', ] diff --git a/windows/uipriv_windows.hpp b/windows/uipriv_windows.hpp index bc82a27c..05b86c09 100644 --- a/windows/uipriv_windows.hpp +++ b/windows/uipriv_windows.hpp @@ -19,3 +19,7 @@ extern HRESULT uiprivInitUtilWindow(HICON hDefaultIcon, HCURSOR hDefaultCursor); // window.cpp extern HRESULT uiprivRegisterWindowClass(HICON hDefaultIcon, HCURSOR hDefaultCursor); + +// utf16.cpp +extern WCHAR *uiprivToUTF16(const char *str); +extern char *uiprivToUTF8(const WCHAR *wstr); diff --git a/zOLD_windows/utf16.cpp b/windows/utf16.cpp similarity index 93% rename from zOLD_windows/utf16.cpp rename to windows/utf16.cpp index 131759e9..3319b617 100644 --- a/zOLD_windows/utf16.cpp +++ b/windows/utf16.cpp @@ -1,9 +1,10 @@ // 21 april 2016 #include "uipriv_windows.hpp" -// see http://stackoverflow.com/a/29556509/3408572 +// TODO clean this up +#define emptyUTF16() ((WCHAR *) uiprivAlloc(1 * sizeof (WCHAR), "WCHAR[]")) -WCHAR *toUTF16(const char *str) +WCHAR *uiprivToUTF16(const char *str) { WCHAR *wstr; WCHAR *wp; @@ -23,7 +24,7 @@ WCHAR *toUTF16(const char *str) return wstr; } -char *toUTF8(const WCHAR *wstr) +char *uiprivToUTF8(const WCHAR *wstr) { char *str; char *sp; @@ -43,6 +44,8 @@ char *toUTF8(const WCHAR *wstr) return str; } +#if 0 + WCHAR *utf16dup(const WCHAR *orig) { WCHAR *out; @@ -147,3 +150,5 @@ WCHAR *itoutf16(int i) s = ss.str(); // to be safe return utf16dup(s.c_str()); } + +#endif diff --git a/windows/window.cpp b/windows/window.cpp index 14546b83..e1068b9c 100644 --- a/windows/window.cpp +++ b/windows/window.cpp @@ -261,17 +261,6 @@ static void uiWindowChildVisibilityChanged(uiWindowsControl *c) uiWindowsControlMinimumSizeChanged(c); } -char *uiWindowTitle(uiWindow *w) -{ - return uiWindowsWindowText(w->hwnd); -} - -void uiWindowSetTitle(uiWindow *w, const char *title) -{ - uiWindowsSetWindowText(w->hwnd, title); - // don't queue resize; the caption isn't part of what affects layout and sizing of the client area (it'll be ellipsized if too long) -} - // this is used for both fullscreening and centering // see also https://blogs.msdn.microsoft.com/oldnewthing/20100412-00/?p=14353 and https://blogs.msdn.microsoft.com/oldnewthing/20050505-04/?p=35703 static void windowMonitorRect(HWND hwnd, RECT *r) @@ -606,14 +595,20 @@ const char *uiprivSysWindowTitle(uiWindow *w) void uiprivSysWindowSetTitle(uiWindow *w, const char *title) { struct windowImplData *wi = (struct windowImplData *) uiControlImplData(uiControl(w)); + WCHAR *wtitle; if (wi->title != NULL) uiprivFreeUTF8(wi->title); wi->title = uiprivSanitizeUTF8(title); - // TODO + wtitle = uiprivToUTF16(wi->title); + hr = uiprivHrSetWindowTextW(wi->hwnd, wtitle); + uiprivFree(wtitle); + if (hr != S_OK) { + // TODO + } + // don't queue resize; the caption isn't part of what affects layout and sizing of the client area (it'll be ellipsized if too long) } - #if 0 // this cannot queue a resize because it's called by the resize handler diff --git a/windows/winhresult.cpp b/windows/winhresult.cpp index 0b7ea0fc..43209254 100644 --- a/windows/winhresult.cpp +++ b/windows/winhresult.cpp @@ -82,3 +82,11 @@ HRESULT WINAPI uiprivHrLoadCursorW(HINSTANCE hInstance, LPCWSTR name, HCURSOR *h return lastErrorToHRESULT(); return S_OK; } + +HRESULT WINAPI uiprivHrSetWindowTextW(HWND hwnd, LPCWSTR text) +{ + SetLastError(0); + if (SetWindowTextW(hwnd, text) == 0) + return lastErrorToHRESULT(); + return S_OK; +} diff --git a/windows/winhresult.hpp b/windows/winhresult.hpp index a2126ce2..6973b1c0 100644 --- a/windows/winhresult.hpp +++ b/windows/winhresult.hpp @@ -7,3 +7,4 @@ extern HRESULT WINAPI uiprivHrGetMessageW(LPMSG msg, HWND hwnd, UINT filterMin, extern HRESULT WINAPI uiprivHrPostMessageW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); extern HRESULT WINAPI uiprivHrLoadIconW(HINSTANCE hInstance, LPCWSTR name, HICON *hIcon); extern HRESULT WINAPI uiprivHrLoadCursorW(HINSTANCE hInstance, LPCWSTR name, HCURSOR *hCursor); +extern HRESULT WINAPI uiprivHrSetWindowTextW(HWND hwnd, LPCWSTR text);