Switched text layout attributes to grapheme-based indices on Windows, just like on OS X.
This commit is contained in:
parent
278227a3d7
commit
47632fe560
|
@ -28,6 +28,7 @@ CXXFILES += \
|
|||
windows/events.cpp \
|
||||
windows/fontbutton.cpp \
|
||||
windows/fontdialog.cpp \
|
||||
windows/grapheme.cpp \
|
||||
windows/group.cpp \
|
||||
windows/init.cpp \
|
||||
windows/label.cpp \
|
||||
|
@ -66,9 +67,10 @@ RCFILES += \
|
|||
# LONGTERM split into a separate file or put in GNUmakefile.libui somehow?
|
||||
|
||||
# flags for the Windows API
|
||||
# notice that usp10.lib comes before gdi32.lib
|
||||
# TODO prune this list
|
||||
LDFLAGS += \
|
||||
user32.lib kernel32.lib gdi32.lib comctl32.lib uxtheme.lib msimg32.lib comdlg32.lib d2d1.lib dwrite.lib ole32.lib oleaut32.lib oleacc.lib uuid.lib
|
||||
user32.lib kernel32.lib usp10.lib gdi32.lib comctl32.lib uxtheme.lib msimg32.lib comdlg32.lib d2d1.lib dwrite.lib ole32.lib oleaut32.lib oleacc.lib uuid.lib
|
||||
|
||||
# flags for building a shared library
|
||||
LDFLAGS += \
|
||||
|
|
|
@ -337,6 +337,7 @@ struct layoutAttr {
|
|||
struct uiDrawTextLayout {
|
||||
WCHAR *text;
|
||||
size_t textlen;
|
||||
size_t *graphemes;
|
||||
double width;
|
||||
IDWriteTextFormat *format;
|
||||
std::vector<struct layoutAttr> *attrs;
|
||||
|
@ -366,6 +367,7 @@ uiDrawTextLayout *uiDrawNewTextLayout(const char *text, uiDrawTextFont *defaultF
|
|||
|
||||
layout->text = toUTF16(text);
|
||||
layout->textlen = wcslen(layout->text);
|
||||
layout->graphemes = graphemes(layout->text);
|
||||
|
||||
uiDrawTextLayoutSetWidth(layout, width);
|
||||
|
||||
|
@ -425,8 +427,8 @@ IDWriteTextLayout *prepareLayout(uiDrawTextLayout *layout, ID2D1RenderTarget *rt
|
|||
logHRESULT(L"error creating IDWriteTextLayout", hr);
|
||||
|
||||
for (const struct layoutAttr &attr : *(layout->attrs)) {
|
||||
range.startPosition = attr.start;
|
||||
range.length = attr.end - attr.start;
|
||||
range.startPosition = layout->graphemes[attr.start];
|
||||
range.length = layout->graphemes[attr.end] - layout->graphemes[attr.start];
|
||||
switch (attr.type) {
|
||||
case layoutAttrColor:
|
||||
if (rt == NULL) // determining extents, not drawing
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
// 25 may 2016
|
||||
#include "uipriv_windows.hpp"
|
||||
|
||||
// We could use CharNext() to generate grapheme cluster boundaries, but it doesn't handle surrogate pairs properly (see http://archives.miloush.net/michkap/archive/2008/12/16/9223301.html).
|
||||
// So let's use Uniscribe (see http://archives.miloush.net/michkap/archive/2005/01/14/352802.html)
|
||||
// See also http://www.catch22.net/tuts/uniscribe-mysteries and http://www.catch22.net/tuts/keyboard-navigation for more details.
|
||||
|
||||
static HRESULT itemize(WCHAR *msg, size_t len, SCRIPT_ITEM **out, int *outn)
|
||||
{
|
||||
SCRIPT_CONTROL sc;
|
||||
SCRIPT_STATE ss;
|
||||
SCRIPT_ITEM *items;
|
||||
size_t maxItems;
|
||||
int n;
|
||||
HRESULT hr;
|
||||
|
||||
// make sure these are zero-initialized to avoid mangling the text
|
||||
ZeroMemory(&sc, sizeof (SCRIPT_CONTROL));
|
||||
ZeroMemory(&ss, sizeof (SCRIPT_STATE));
|
||||
|
||||
maxItems = len + 2;
|
||||
for (;;) {
|
||||
items = new SCRIPT_ITEM[maxItems];
|
||||
hr = ScriptItemize(msg, len,
|
||||
maxItems,
|
||||
&sc, &ss,
|
||||
items, &n);
|
||||
if (hr == S_OK)
|
||||
break;
|
||||
// otherwise either an error or not enough room
|
||||
delete[] items;
|
||||
if (hr != E_OUTOFMEMORY)
|
||||
return hr;
|
||||
maxItems *= 2; // add some more and try again
|
||||
}
|
||||
|
||||
*out = items;
|
||||
*outn = n;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
size_t *graphemes(WCHAR *msg)
|
||||
{
|
||||
size_t len;
|
||||
SCRIPT_ITEM *items;
|
||||
int i, n;
|
||||
size_t *out;
|
||||
size_t *op;
|
||||
SCRIPT_LOGATTR *logattr;
|
||||
int j, nn;
|
||||
HRESULT hr;
|
||||
|
||||
len = wcslen(msg);
|
||||
hr = itemize(msg, len, &items, &n);
|
||||
if (hr != S_OK)
|
||||
logHRESULT(L"error itemizing string for finding grapheme cluster boundaries", hr);
|
||||
|
||||
// should be enough; 2 more just to be safe
|
||||
out = (size_t *) uiAlloc((len + 2) * sizeof (size_t), "size_t[]");
|
||||
op = out;
|
||||
|
||||
// note that there are actually n + 1 elements in items
|
||||
for (i = 0; i < n; i++) {
|
||||
nn = items[i + 1].iCharPos - items[i].iCharPos;
|
||||
logattr = new SCRIPT_LOGATTR[nn];
|
||||
hr = ScriptBreak(msg + items[i].iCharPos, nn,
|
||||
&(items[i].a), logattr);
|
||||
if (hr != S_OK)
|
||||
logHRESULT(L"error breaking string for finding grapheme cluster boundaries", hr);
|
||||
for (j = 0; j < nn; j++)
|
||||
if (logattr[j].fCharStop != 0)
|
||||
*op++ = items[i].iCharPos + j;
|
||||
delete[] logattr;
|
||||
}
|
||||
// and handle the last item for the end of the string
|
||||
*op++ = items[i].iCharPos;
|
||||
|
||||
delete[] items;
|
||||
return out;
|
||||
}
|
|
@ -140,6 +140,10 @@ extern BOOL showColorDialog(HWND parent, struct colorDialogRGBA *c);
|
|||
// sizing.cpp
|
||||
extern void getSizing(HWND hwnd, uiWindowsSizing *sizing, HFONT font);
|
||||
|
||||
// grapheme.cpp
|
||||
extern size_t *graphemes(WCHAR *msg);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include <d2d1.h>
|
||||
#include <d2d1helper.h>
|
||||
#include <dwrite.h>
|
||||
#include <usp10.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
|
Loading…
Reference in New Issue