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:
Pietro Gagliardi 2016-04-19 14:39:33 -04:00
parent c2d165af94
commit 5b74b2752e
2 changed files with 6 additions and 115 deletions

View File

@ -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);
} }

View File

@ -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,