Fixed text rendering on Windows. Woo, it all works so far!
This commit is contained in:
parent
a826fd7516
commit
ef54b99b93
|
@ -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;
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in New Issue