Decided to use character offsets instead of byte offsets for text layout attributes. This removes the shaky code from the OS X and Windows backends to compute a list of character offsets for byte offsets. The equivalent code for GTK+ to convert chars to bytes will be much more solid; it will be written next.
This commit is contained in:
parent
c2d165af94
commit
5b74b2752e
|
@ -439,78 +439,27 @@ void uiDrawTextFontGetMetrics(uiDrawTextFont *font, uiDrawTextFontMetrics *metri
|
||||||
|
|
||||||
struct uiDrawTextLayout {
|
struct uiDrawTextLayout {
|
||||||
CFMutableAttributedStringRef mas;
|
CFMutableAttributedStringRef mas;
|
||||||
intmax_t *bytesToCharacters;
|
|
||||||
double width;
|
double width;
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO this is *really* iffy, but we need to know character offsets...
|
|
||||||
// TODO clean up the local variable names and improve documentation
|
|
||||||
static intmax_t *strToCFStrOffsetList(const char *str, CFMutableStringRef *cfstr)
|
|
||||||
{
|
|
||||||
intmax_t *bytesToCharacters;
|
|
||||||
intmax_t i, len;
|
|
||||||
|
|
||||||
len = strlen(str);
|
|
||||||
bytesToCharacters = (intmax_t *) uiAlloc(len * sizeof (intmax_t), "intmax_t[]");
|
|
||||||
|
|
||||||
*cfstr = CFStringCreateMutable(NULL, 0);
|
|
||||||
if (*cfstr == NULL)
|
|
||||||
complain("error creating CFMutableStringRef for storing string in strToCFStrOffset()");
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
while (i < len) {
|
|
||||||
CFStringRef substr;
|
|
||||||
intmax_t n;
|
|
||||||
intmax_t j;
|
|
||||||
intmax_t pos;
|
|
||||||
|
|
||||||
// figure out how many characters to convert and convert them
|
|
||||||
for (n = 1; (i + n - 1) < len; n++) {
|
|
||||||
substr = CFStringCreateWithBytes(NULL, (const UInt8 *) (str + i), n, kCFStringEncodingUTF8, false);
|
|
||||||
if (substr != NULL) // found a full character
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// if this test passes we either:
|
|
||||||
// - reached the end of the string without a successful conversion (invalid string)
|
|
||||||
// - ran into allocation issues
|
|
||||||
if (substr == NULL)
|
|
||||||
complain("something bad happened when trying to prepare string in strToCFStrOffset()");
|
|
||||||
|
|
||||||
// now save the character offsets for those bytes
|
|
||||||
pos = CFStringGetLength(*cfstr);
|
|
||||||
for (j = 0; j < n; j++)
|
|
||||||
bytesToCharacters[j] = pos;
|
|
||||||
|
|
||||||
// and add the characters that we converted
|
|
||||||
CFStringAppend(*cfstr, substr);
|
|
||||||
CFRelease(substr); // TODO correct?
|
|
||||||
|
|
||||||
// and go to the next
|
|
||||||
i += n;
|
|
||||||
}
|
|
||||||
|
|
||||||
return bytesToCharacters;
|
|
||||||
}
|
|
||||||
|
|
||||||
uiDrawTextLayout *uiDrawNewTextLayout(const char *str, uiDrawTextFont *defaultFont, double width)
|
uiDrawTextLayout *uiDrawNewTextLayout(const char *str, uiDrawTextFont *defaultFont, double width)
|
||||||
{
|
{
|
||||||
uiDrawTextLayout *layout;
|
uiDrawTextLayout *layout;
|
||||||
CFMutableStringRef cfstr;
|
//TODO CFStringRef cfstr;
|
||||||
CFAttributedStringRef immutable;
|
CFAttributedStringRef immutable;
|
||||||
CFMutableDictionaryRef attr;
|
CFMutableDictionaryRef attr;
|
||||||
|
|
||||||
layout = uiNew(uiDrawTextLayout);
|
layout = uiNew(uiDrawTextLayout);
|
||||||
|
|
||||||
layout->bytesToCharacters = strToCFStrOffsetList(str, &cfstr);
|
|
||||||
|
|
||||||
attr = newAttrList();
|
attr = newAttrList();
|
||||||
// this will retain defaultFont->f; no need to worry
|
// this will retain defaultFont->f; no need to worry
|
||||||
CFDictionaryAddValue(attr, kCTFontAttributeName, defaultFont->f);
|
CFDictionaryAddValue(attr, kCTFontAttributeName, defaultFont->f);
|
||||||
|
|
||||||
immutable = CFAttributedStringCreate(NULL, cfstr, attr);
|
// TODO convert the NSString call to a CFString call
|
||||||
|
immutable = CFAttributedStringCreate(NULL, (CFStringRef) [NSString stringWithUTF8String:str], attr);
|
||||||
if (immutable == NULL)
|
if (immutable == NULL)
|
||||||
complain("error creating immutable attributed string in uiDrawNewTextLayout()");
|
complain("error creating immutable attributed string in uiDrawNewTextLayout()");
|
||||||
CFRelease(cfstr);
|
//TODO CFRelease(cfstr);
|
||||||
CFRelease(attr);
|
CFRelease(attr);
|
||||||
|
|
||||||
layout->mas = CFAttributedStringCreateMutableCopy(NULL, 0, immutable);
|
layout->mas = CFAttributedStringCreateMutableCopy(NULL, 0, immutable);
|
||||||
|
@ -526,7 +475,6 @@ uiDrawTextLayout *uiDrawNewTextLayout(const char *str, uiDrawTextFont *defaultFo
|
||||||
void uiDrawFreeTextLayout(uiDrawTextLayout *layout)
|
void uiDrawFreeTextLayout(uiDrawTextLayout *layout)
|
||||||
{
|
{
|
||||||
CFRelease(layout->mas);
|
CFRelease(layout->mas);
|
||||||
uiFree(layout->bytesToCharacters);
|
|
||||||
uiFree(layout);
|
uiFree(layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -318,69 +318,12 @@ void uiDrawTextFontGetMetrics(uiDrawTextFont *font, uiDrawTextFontMetrics *metri
|
||||||
struct uiDrawTextLayout {
|
struct uiDrawTextLayout {
|
||||||
IDWriteTextFormat *format;
|
IDWriteTextFormat *format;
|
||||||
IDWriteTextLayout *layout;
|
IDWriteTextLayout *layout;
|
||||||
intmax_t *bytesToCharacters;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MBTWC(str, n, wstr, bufsiz) MultiByteToWideChar(CP_UTF8, 0, str, n, wstr, bufsiz)
|
|
||||||
#define MBTWCErr(str, n, wstr, bufsiz) MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str, n, wstr, bufsiz)
|
|
||||||
|
|
||||||
// TODO figure out how ranges are specified in DirectWrite
|
|
||||||
// TODO clean up the local variable names and improve documentation
|
|
||||||
static intmax_t *toUTF16Offsets(const char *str, WCHAR **wstr, intmax_t *wlenout)
|
|
||||||
{
|
|
||||||
intmax_t *bytesToCharacters;
|
|
||||||
intmax_t i, len;
|
|
||||||
int wlen;
|
|
||||||
intmax_t outpos;
|
|
||||||
|
|
||||||
len = strlen(str);
|
|
||||||
bytesToCharacters = (intmax_t *) uiAlloc(len * sizeof (intmax_t), "intmax_t[]");
|
|
||||||
|
|
||||||
wlen = MBTWC(str, -1, NULL, 0);
|
|
||||||
if (wlen == 0)
|
|
||||||
logLastError("error figuring out number of characters to convert to in toUTF16Offsets()");
|
|
||||||
*wstr = (WCHAR *) uiAlloc(wlen * sizeof (WCHAR), "WCHAR[]");
|
|
||||||
*wlenout = wlen;
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
outpos = 0;
|
|
||||||
while (i < len) {
|
|
||||||
intmax_t n;
|
|
||||||
intmax_t j;
|
|
||||||
BOOL found;
|
|
||||||
int m;
|
|
||||||
|
|
||||||
// figure out how many characters to convert and convert them
|
|
||||||
found = FALSE;
|
|
||||||
for (n = 1; (i + n - 1) < len; n++) {
|
|
||||||
// we need MB_ERR_INVALID_CHARS here for this to work properly
|
|
||||||
m = MBTWCErr(str + i, n, *wstr + outpos, wlen - outpos);
|
|
||||||
if (m != 0) { // found a full character
|
|
||||||
found = TRUE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// if this test passes we reached the end of the string without a successful conversion (invalid string)
|
|
||||||
if (!found)
|
|
||||||
logLastError("something bad happened when trying to prepare string in uiDrawNewTextLayout()");
|
|
||||||
|
|
||||||
// now save the character offsets for those bytes
|
|
||||||
for (j = 0; j < m; j++)
|
|
||||||
bytesToCharacters[j] = outpos;
|
|
||||||
|
|
||||||
// and go to the next
|
|
||||||
i += n;
|
|
||||||
outpos += m;
|
|
||||||
}
|
|
||||||
|
|
||||||
return bytesToCharacters;
|
|
||||||
}
|
|
||||||
|
|
||||||
uiDrawTextLayout *uiDrawNewTextLayout(const char *text, uiDrawTextFont *defaultFont, double width)
|
uiDrawTextLayout *uiDrawNewTextLayout(const char *text, uiDrawTextFont *defaultFont, double width)
|
||||||
{
|
{
|
||||||
uiDrawTextLayout *layout;
|
uiDrawTextLayout *layout;
|
||||||
WCHAR *wtext;
|
WCHAR *wtext;
|
||||||
intmax_t wlen;
|
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
layout = uiNew(uiDrawTextLayout);
|
layout = uiNew(uiDrawTextLayout);
|
||||||
|
@ -400,8 +343,8 @@ uiDrawTextLayout *uiDrawNewTextLayout(const char *text, uiDrawTextFont *defaultF
|
||||||
if (hr != S_OK)
|
if (hr != S_OK)
|
||||||
logHRESULT("error creating IDWriteTextFormat in uiDrawNewTextLayout()", hr);
|
logHRESULT("error creating IDWriteTextFormat in uiDrawNewTextLayout()", hr);
|
||||||
|
|
||||||
layout->bytesToCharacters = toUTF16Offsets(text, &wtext, &wlen);
|
wtext = toUTF16(text);
|
||||||
hr = dwfactory->CreateTextLayout(wtext, wlen,
|
hr = dwfactory->CreateTextLayout(wtext, wcslen(wtext),
|
||||||
layout->format,
|
layout->format,
|
||||||
// FLOAT is float, not double, so this should work... TODO
|
// FLOAT is float, not double, so this should work... TODO
|
||||||
FLT_MAX, FLT_MAX,
|
FLT_MAX, FLT_MAX,
|
||||||
|
|
Loading…
Reference in New Issue