Fixed text rendering on Windows. Woo, it all works so far!

This commit is contained in:
Pietro Gagliardi 2016-01-09 02:23:01 -05:00
parent a826fd7516
commit ef54b99b93
2 changed files with 99 additions and 36 deletions

View File

@ -875,7 +875,7 @@ void uiDrawRestore(uiDrawContext *c)
} }
// TODO document that fully opaque black is the default text color; figure out whether this is upheld in various scenarios on other platforms // TODO document that fully opaque black is the default text color; figure out whether this is upheld in various scenarios on other platforms
void uiDrawText(uiDrawContext *c, doule x, double y, uiDrawTextLayout *layout) void uiDrawText(uiDrawContext *c, double x, double y, uiDrawTextLayout *layout)
{ {
uiDrawBrush brush; uiDrawBrush brush;
ID2D1Brush *black; ID2D1Brush *black;

View File

@ -152,66 +152,89 @@ static intmax_t *toUTF16Offsets(const char *str, WCHAR **wstr, intmax_t *wlenout
intmax_t n; intmax_t n;
intmax_t j; intmax_t j;
BOOL found; BOOL found;
int m;
// figure out how many characters to convert and convert them // figure out how many characters to convert and convert them
found = FALSE; found = FALSE;
for (n = 1; (i + n - 1) < len; n++) for (n = 1; (i + n - 1) < len; n++) {
if (MBTWC(str + i, n, *wstr + outpos, wlen - outpos) == n) { // TODO do we need MB_ERR_INVALID_CHARS here for this to work properly?
// found a full character m = MBTWC(str + i, n, *wstr + outpos, wlen - outpos);
if (m != 0) { // found a full character
found = TRUE; found = TRUE;
break; break;
} }
}
// if this test passes we reached the end of the string without a successful conversion (invalid string) // if this test passes we reached the end of the string without a successful conversion (invalid string)
if (!found) if (!found)
logLastError("something bad happened when trying to prepare string in uiDrawNewTextLayout()"); logLastError("something bad happened when trying to prepare string in uiDrawNewTextLayout()");
// now save the character offsets for those bytes // now save the character offsets for those bytes
for (j = 0; j < n; j++) for (j = 0; j < m; j++)
bytesToCharacters[j] = outpos; bytesToCharacters[j] = outpos;
// and go to the next // and go to the next
outpos += n; i += n;
outpos += m;
} }
return bytesToCharacters; return bytesToCharacters;
} }
// Not only does C++11 NOT include C99 designated initializers, but the C++ standards committee has REPEATEDLY REJECTING THEM, covering their ears and yelling "CONSTRUCTORS!!!111 PRIVATE DATA!1111 ENCAPSULATION!11one" at the top of their lungs.
// So what could have been a simple array lookup is now a loop. Thanks guys.
static const DWRITE_FONT_WEIGHT dwriteWeights[] = { static const struct {
[uiDrawTextWeightThin] = DWRITE_FONT_WEIGHT_THIN, bool lastOne;
[uiDrawTextWeightUltraLight] = DWRITE_FONT_WEIGHT_ULTRA_LIGHT, uiDrawTextWeight uival;
[uiDrawTextWeightLight] = DWRITE_FONT_WEIGHT_LIGHT, DWRITE_FONT_WEIGHT dwval;
[uiDrawTextWeightBook] = DWRITE_FONT_WEIGHT_SEMI_LIGHT, } dwriteWeights[] = {
[uiDrawTextWeightNormal] = DWRITE_FONT_WEIGHT_NORMAL, { false, uiDrawTextWeightThin, DWRITE_FONT_WEIGHT_THIN },
[uiDrawTextWeightMedium] = DWRITE_FONT_WEIGHT_MEDIUM, { false, uiDrawTextWeightUltraLight, DWRITE_FONT_WEIGHT_ULTRA_LIGHT },
[uiDrawTextWeightSemiBold] = DWRITE_FONT_WEIGHT_SEMI_BOLD, { false, uiDrawTextWeightLight, DWRITE_FONT_WEIGHT_LIGHT },
[uiDrawTextWeightBold] = DWRITE_FONT_WEIGHT_BOLD, { false, uiDrawTextWeightBook, DWRITE_FONT_WEIGHT_SEMI_LIGHT },
[uiDrawTextWeightUtraBold] = DWRITE_FONT_WEIGHT_ULTRA_BOLD, { false, uiDrawTextWeightNormal, DWRITE_FONT_WEIGHT_NORMAL },
[uiDrawTextWeightHeavy] = DWRITE_FONT_WEIGHT_HEAVY, { false, uiDrawTextWeightMedium, DWRITE_FONT_WEIGHT_MEDIUM },
[uiDrawTextWeightUltraHeavy] = DWRITE_FONT_WEIGHT_ULTRA_BLACK, { false, uiDrawTextWeightSemiBold, DWRITE_FONT_WEIGHT_SEMI_BOLD },
{ false, uiDrawTextWeightBold, DWRITE_FONT_WEIGHT_BOLD },
{ false, uiDrawTextWeightUtraBold, DWRITE_FONT_WEIGHT_ULTRA_BOLD },
{ false, uiDrawTextWeightHeavy, DWRITE_FONT_WEIGHT_HEAVY },
{ true, uiDrawTextWeightUltraHeavy, DWRITE_FONT_WEIGHT_ULTRA_BLACK, },
}; };
static const DWRITE_FONT_STYLE dwriteItalics[] = { static const struct {
[uiDrawTextItalicNormal] = DWRITE_FONT_STYLE_NORMAL, bool lastOne;
[uiDrawTextItalicOblique] = DWRITE_FONT_STYLE_OBLIQUE, uiDrawTextItalic uival;
[uiDrawTextItalicItalic] = DWRITE_FONT_STYLE_ITALIC, DWRITE_FONT_STYLE dwval;
} dwriteItalics[] = {
{ false, uiDrawTextItalicNormal, DWRITE_FONT_STYLE_NORMAL },
{ false, uiDrawTextItalicOblique, DWRITE_FONT_STYLE_OBLIQUE },
{ true, uiDrawTextItalicItalic, DWRITE_FONT_STYLE_ITALIC },
}; };
static const DWRITE_FONT_STRETCH dwriteStretches[] = { static const struct {
[uiDrawTextStretchUltraCondensed] = DWRITE_FONT_STRETCH_ULTRA_CONDENSED, bool lastOne;
[uiDrawTextStretchExtraCondensed] = DWRITE_FONT_STRETCH_EXTRA_CONDENSED, uiDrawTextStretch uival;
[uiDrawTextStretchCondensed] = DWRITE_FONT_STRETCH_CONDENSED, DWRITE_FONT_STRETCH dwval;
[uiDrawTextStretchSemiCondensed] = DWRITE_FONT_STRETCH_SEMI_CONDENSED, } dwriteStretches[] = {
[uiDrawTextStretchNormal] = DWRITE_FONT_STRETCH_NORMAL, { false, uiDrawTextStretchUltraCondensed, DWRITE_FONT_STRETCH_ULTRA_CONDENSED },
[uiDrawTextStretchSemiExpanded] = DWRITE_FONT_STRETCH_SEMI_EXPANDED, { false, uiDrawTextStretchExtraCondensed, DWRITE_FONT_STRETCH_EXTRA_CONDENSED },
[uiDrawTextStretchExpanded] = DWRITE_FONT_STRETCH_EXPANDED, { false, uiDrawTextStretchCondensed, DWRITE_FONT_STRETCH_CONDENSED },
[uiDrawTextStretchExtraExpanded] = DWRITE_FONT_STRETCH_EXTRA_EXPANDED, { false, uiDrawTextStretchSemiCondensed, DWRITE_FONT_STRETCH_SEMI_CONDENSED },
[uiDrawTextStretchUltraExpanded] = DWRITE_FONT_STRETCH_ULTRA_EXPANDED, { false, uiDrawTextStretchNormal, DWRITE_FONT_STRETCH_NORMAL },
{ false, uiDrawTextStretchSemiExpanded, DWRITE_FONT_STRETCH_SEMI_EXPANDED },
{ false, uiDrawTextStretchExpanded, DWRITE_FONT_STRETCH_EXPANDED },
{ false, uiDrawTextStretchExtraExpanded, DWRITE_FONT_STRETCH_EXTRA_EXPANDED },
{ true, uiDrawTextStretchUltraExpanded, DWRITE_FONT_STRETCH_ULTRA_EXPANDED },
}; };
uiDrawTextLayout *uiDrawNewTextLayout(const char *text, const uiDrawInitialTextStyle *initialStyle) uiDrawTextLayout *uiDrawNewTextLayout(const char *text, const uiDrawInitialTextStyle *initialStyle)
{ {
uiDrawTextLayout *layout; uiDrawTextLayout *layout;
DWRITE_FONT_WEIGHT weight;
DWRITE_FONT_STYLE italic;
DWRITE_FONT_STRETCH stretch;
bool found;
int i;
WCHAR *family; WCHAR *family;
WCHAR *wtext; WCHAR *wtext;
intmax_t wlen; intmax_t wlen;
@ -219,12 +242,51 @@ uiDrawTextLayout *uiDrawNewTextLayout(const char *text, const uiDrawInitialTextS
layout = uiNew(uiDrawTextLayout); layout = uiNew(uiDrawTextLayout);
found = false;
for (i = 0; ; i++) {
if (dwriteWeights[i].uival == initialStyle->Weight) {
weight = dwriteWeights[i].dwval;
found = true;
break;
}
if (dwriteWeights[i].lastOne)
break;
}
if (!found)
complain("invalid initial weight %d passed to uiDrawNewTextLayout()", initialStyle->Weight);
found = false;
for (i = 0; ; i++) {
if (dwriteItalics[i].uival == initialStyle->Italic) {
italic = dwriteItalics[i].dwval;
found = true;
break;
}
if (dwriteItalics[i].lastOne)
break;
}
if (!found)
complain("invalid initial italic %d passed to uiDrawNewTextLayout()", initialStyle->Italic);
found = false;
for (i = 0; ; i++) {
if (dwriteStretches[i].uival == initialStyle->Stretch) {
stretch = dwriteStretches[i].dwval;
found = true;
break;
}
if (dwriteStretches[i].lastOne)
break;
}
if (!found)
complain("invalid initial stretch %d passed to uiDrawNewTextLayout()", initialStyle->Stretch);
family = toUTF16(initialStyle->Family); family = toUTF16(initialStyle->Family);
hr = dwfactory->CreateTextFormat(family, hr = dwfactory->CreateTextFormat(family,
NULL, NULL,
dwriteWeights[initialStyle->Weight], weight,
dwriteItalics[initialStyle->Italic], italic,
dwriteStretches[initialStyle->Stretch], stretch,
// typographic points are 1/72 inch; this parameter is 1/96 inch // typographic points are 1/72 inch; this parameter is 1/96 inch
// fortunately Microsoft does this too, in https://msdn.microsoft.com/en-us/library/windows/desktop/dd371554%28v=vs.85%29.aspx // fortunately Microsoft does this too, in https://msdn.microsoft.com/en-us/library/windows/desktop/dd371554%28v=vs.85%29.aspx
initialStyle->Size * (96.0 / 72.0), initialStyle->Size * (96.0 / 72.0),
@ -235,10 +297,11 @@ uiDrawTextLayout *uiDrawNewTextLayout(const char *text, const uiDrawInitialTextS
if (hr != S_OK) if (hr != S_OK)
logHRESULT("error creating IDWriteTextFormat in uiDrawNewTextLayout()", hr); logHRESULT("error creating IDWriteTextFormat in uiDrawNewTextLayout()", hr);
uiFree(family); uiFree(family);
// TODO small caps
// TODO gravity // TODO gravity
layout->bytesToCharacters = toUTF16Offsets(text, &wtext, &wlen); layout->bytesToCharacters = toUTF16Offsets(text, &wtext, &wlen);
hr = dwfactory->CreateTextLayout(wstr, wlen, hr = dwfactory->CreateTextLayout(wtext, wlen,
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,