Wrote the text drawing code on Windows. Now to build and test.
This commit is contained in:
parent
69e5dd42cf
commit
a826fd7516
|
@ -509,6 +509,7 @@ struct uiDrawTextLayout {
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO this is *really* iffy, but we need to know character offsets...
|
// 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)
|
static intmax_t *strToCFStrOffsetList(const char *str, CFMutableStringRef *cfstr)
|
||||||
{
|
{
|
||||||
intmax_t *bytesToCharacters;
|
intmax_t *bytesToCharacters;
|
||||||
|
@ -768,6 +769,7 @@ void uiDrawFreeTextLayout(uiDrawTextLayout *layout)
|
||||||
|
|
||||||
// Core Text doesn't draw onto a flipped view correctly; we have to do this
|
// Core Text doesn't draw onto a flipped view correctly; we have to do this
|
||||||
// see the iOS bits of the first example at https://developer.apple.com/library/mac/documentation/StringsTextFonts/Conceptual/CoreText_Programming/LayoutOperations/LayoutOperations.html#//apple_ref/doc/uid/TP40005533-CH12-SW1 (iOS is naturally flipped)
|
// see the iOS bits of the first example at https://developer.apple.com/library/mac/documentation/StringsTextFonts/Conceptual/CoreText_Programming/LayoutOperations/LayoutOperations.html#//apple_ref/doc/uid/TP40005533-CH12-SW1 (iOS is naturally flipped)
|
||||||
|
// TODO how is this affected by the CTM?
|
||||||
static void prepareContextForText(uiDrawContext *c, double *y)
|
static void prepareContextForText(uiDrawContext *c, double *y)
|
||||||
{
|
{
|
||||||
CGContextSaveGState(c->c);
|
CGContextSaveGState(c->c);
|
||||||
|
|
|
@ -873,3 +873,20 @@ void uiDrawRestore(uiDrawContext *c)
|
||||||
uiFree(state);
|
uiFree(state);
|
||||||
ptrArrayDelete(c->states, c->states->len - 1);
|
ptrArrayDelete(c->states, c->states->len - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
uiDrawBrush brush;
|
||||||
|
ID2D1Brush *black;
|
||||||
|
|
||||||
|
ZeroMemory(&brush, sizeof (uiDrawBrush));
|
||||||
|
brush.Type = uiDrawBrushTypeSolid;
|
||||||
|
brush.R = 0.0;
|
||||||
|
brush.G = 0.0;
|
||||||
|
brush.B = 0.0;
|
||||||
|
brush.A = 1.0;
|
||||||
|
black = makeBrush(&brush, c->rt);
|
||||||
|
doDrawText(c->rt, black, x, y, layout);
|
||||||
|
ID2D1Brush_Release(black);
|
||||||
|
}
|
||||||
|
|
|
@ -120,7 +120,152 @@ double uiDrawPointsToTextSize(double points)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void uiDrawText(uiDrawContext *c, double x, double y, const char *text, uiDrawTextStyle *style)
|
struct uiDrawTextLayout {
|
||||||
|
IDWriteTextFormat *format;
|
||||||
|
IDWriteTextLayout *layout;
|
||||||
|
intmax_t *bytesToCharacters;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MBTWC(str, n, wstr, bufsiz) MultiByteToWideChar(CP_UTF8, 0, 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)
|
||||||
{
|
{
|
||||||
// TODO
|
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;
|
||||||
|
|
||||||
|
// figure out how many characters to convert and convert them
|
||||||
|
found = FALSE;
|
||||||
|
for (n = 1; (i + n - 1) < len; n++)
|
||||||
|
if (MBTWC(str + i, n, *wstr + outpos, wlen - outpos) == n) {
|
||||||
|
// 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 < n; j++)
|
||||||
|
bytesToCharacters[j] = outpos;
|
||||||
|
|
||||||
|
// and go to the next
|
||||||
|
outpos += n;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytesToCharacters;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const DWRITE_FONT_WEIGHT dwriteWeights[] = {
|
||||||
|
[uiDrawTextWeightThin] = DWRITE_FONT_WEIGHT_THIN,
|
||||||
|
[uiDrawTextWeightUltraLight] = DWRITE_FONT_WEIGHT_ULTRA_LIGHT,
|
||||||
|
[uiDrawTextWeightLight] = DWRITE_FONT_WEIGHT_LIGHT,
|
||||||
|
[uiDrawTextWeightBook] = DWRITE_FONT_WEIGHT_SEMI_LIGHT,
|
||||||
|
[uiDrawTextWeightNormal] = DWRITE_FONT_WEIGHT_NORMAL,
|
||||||
|
[uiDrawTextWeightMedium] = DWRITE_FONT_WEIGHT_MEDIUM,
|
||||||
|
[uiDrawTextWeightSemiBold] = DWRITE_FONT_WEIGHT_SEMI_BOLD,
|
||||||
|
[uiDrawTextWeightBold] = DWRITE_FONT_WEIGHT_BOLD,
|
||||||
|
[uiDrawTextWeightUtraBold] = DWRITE_FONT_WEIGHT_ULTRA_BOLD,
|
||||||
|
[uiDrawTextWeightHeavy] = DWRITE_FONT_WEIGHT_HEAVY,
|
||||||
|
[uiDrawTextWeightUltraHeavy] = DWRITE_FONT_WEIGHT_ULTRA_BLACK,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const DWRITE_FONT_STYLE dwriteItalics[] = {
|
||||||
|
[uiDrawTextItalicNormal] = DWRITE_FONT_STYLE_NORMAL,
|
||||||
|
[uiDrawTextItalicOblique] = DWRITE_FONT_STYLE_OBLIQUE,
|
||||||
|
[uiDrawTextItalicItalic] = DWRITE_FONT_STYLE_ITALIC,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const DWRITE_FONT_STRETCH dwriteStretches[] = {
|
||||||
|
[uiDrawTextStretchUltraCondensed] = DWRITE_FONT_STRETCH_ULTRA_CONDENSED,
|
||||||
|
[uiDrawTextStretchExtraCondensed] = DWRITE_FONT_STRETCH_EXTRA_CONDENSED,
|
||||||
|
[uiDrawTextStretchCondensed] = DWRITE_FONT_STRETCH_CONDENSED,
|
||||||
|
[uiDrawTextStretchSemiCondensed] = DWRITE_FONT_STRETCH_SEMI_CONDENSED,
|
||||||
|
[uiDrawTextStretchNormal] = DWRITE_FONT_STRETCH_NORMAL,
|
||||||
|
[uiDrawTextStretchSemiExpanded] = DWRITE_FONT_STRETCH_SEMI_EXPANDED,
|
||||||
|
[uiDrawTextStretchExpanded] = DWRITE_FONT_STRETCH_EXPANDED,
|
||||||
|
[uiDrawTextStretchExtraExpanded] = DWRITE_FONT_STRETCH_EXTRA_EXPANDED,
|
||||||
|
[uiDrawTextStretchUltraExpanded] = DWRITE_FONT_STRETCH_ULTRA_EXPANDED,
|
||||||
|
};
|
||||||
|
|
||||||
|
uiDrawTextLayout *uiDrawNewTextLayout(const char *text, const uiDrawInitialTextStyle *initialStyle)
|
||||||
|
{
|
||||||
|
uiDrawTextLayout *layout;
|
||||||
|
WCHAR *family;
|
||||||
|
WCHAR *wtext;
|
||||||
|
intmax_t wlen;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
layout = uiNew(uiDrawTextLayout);
|
||||||
|
|
||||||
|
family = toUTF16(initialStyle->Family);
|
||||||
|
hr = dwfactory->CreateTextFormat(family,
|
||||||
|
NULL,
|
||||||
|
dwriteWeights[initialStyle->Weight],
|
||||||
|
dwriteItalics[initialStyle->Italic],
|
||||||
|
dwriteStretches[initialStyle->Stretch],
|
||||||
|
// 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
|
||||||
|
initialStyle->Size * (96.0 / 72.0),
|
||||||
|
// see http://stackoverflow.com/questions/28397971/idwritefactorycreatetextformat-failing and https://msdn.microsoft.com/en-us/library/windows/desktop/dd368203.aspx
|
||||||
|
// TODO use the current locale again?
|
||||||
|
L"",
|
||||||
|
&(layout->format));
|
||||||
|
if (hr != S_OK)
|
||||||
|
logHRESULT("error creating IDWriteTextFormat in uiDrawNewTextLayout()", hr);
|
||||||
|
uiFree(family);
|
||||||
|
// TODO gravity
|
||||||
|
|
||||||
|
layout->bytesToCharacters = toUTF16Offsets(text, &wtext, &wlen);
|
||||||
|
hr = dwfactory->CreateTextLayout(wstr, wlen,
|
||||||
|
layout->format,
|
||||||
|
// FLOAT is float, not double, so this should work... TODO
|
||||||
|
FLT_MAX, FLT_MAX,
|
||||||
|
&(layout->layout));
|
||||||
|
if (hr != S_OK)
|
||||||
|
logHRESULT("error creating IDWriteTextLayout in uiDrawNewTextLayout()", hr);
|
||||||
|
uiFree(wtext);
|
||||||
|
|
||||||
|
return layout;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uiDrawFreeTextLayout(uiDrawTextLayout *layout)
|
||||||
|
{
|
||||||
|
layout->layout->Release();
|
||||||
|
layout->format->Release();
|
||||||
|
uiFree(layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void doDrawText(ID2D1RenderTarget *rt, ID2D1Brush *black, double x, double y, uiDrawTextLayout *layout)
|
||||||
|
{
|
||||||
|
D2D1_POINT_2F pt;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
pt.x = x;
|
||||||
|
pt.y = y;
|
||||||
|
// TODO D2D1_DRAW_TEXT_OPTIONS_NO_SNAP?
|
||||||
|
// TODO D2D1_DRAW_TEXT_OPTIONS_CLIP?
|
||||||
|
// TODO when setting 8.1 as minimum, D2D1_DRAW_TEXT_OPTIONS_ENABLE_COLOR_FONT?
|
||||||
|
rt->DrawTextLayout(pt, layout->layout, black, D2D1_DRAW_TEXT_OPTIONS_NONE);
|
||||||
}
|
}
|
||||||
|
|
|
@ -138,6 +138,7 @@ extern void freeContext(uiDrawContext *);
|
||||||
// drawtext.cpp
|
// drawtext.cpp
|
||||||
extern HRESULT initDrawText(void);
|
extern HRESULT initDrawText(void);
|
||||||
extern void uninitDrawText(void);
|
extern void uninitDrawText(void);
|
||||||
|
extern void doDrawText(ID2D1RenderTarget *rt, ID2D1Brush *black, double x, double y, uiDrawTextLayout *layout);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue