More migrations of attrstr.cpp and drawtext.cpp. My this is a mess :D
This commit is contained in:
parent
5314295e4c
commit
1b1d609c88
|
@ -23,7 +23,3 @@ extern BOOL showFontDialog(HWND parent, struct fontDialogParams *params);
|
||||||
extern void loadInitialFontDialogParams(struct fontDialogParams *params);
|
extern void loadInitialFontDialogParams(struct fontDialogParams *params);
|
||||||
extern void destroyFontDialogParams(struct fontDialogParams *params);
|
extern void destroyFontDialogParams(struct fontDialogParams *params);
|
||||||
extern WCHAR *fontDialogParamsToString(struct fontDialogParams *params);
|
extern WCHAR *fontDialogParamsToString(struct fontDialogParams *params);
|
||||||
|
|
||||||
// attrstr.cpp
|
|
||||||
typedef std::function<void(uiDrawContext *c, uiDrawTextLayout *layout, double x, double y)> backgroundFunc;
|
|
||||||
extern void attrstrToIDWriteTextLayoutAttrs(uiDrawTextLayoutParams *p, IDWriteTextLayout *layout, std::vector<backgroundFunc> **backgroundFuncs);
|
|
||||||
|
|
|
@ -4,14 +4,15 @@
|
||||||
|
|
||||||
// TODO this whole file needs cleanup
|
// TODO this whole file needs cleanup
|
||||||
|
|
||||||
// we need to collect all the background blocks and add them all at once
|
// we need to collect all the background parameters and add them all at once
|
||||||
|
// TODO consider having background parameters in the drawing effects
|
||||||
// TODO contextual alternates override ligatures?
|
// TODO contextual alternates override ligatures?
|
||||||
// TODO rename this struct to something that isn't exclusively foreach-ing?
|
// TODO rename this struct to something that isn't exclusively foreach-ing?
|
||||||
struct foreachParams {
|
struct foreachParams {
|
||||||
const uint16_t *s;
|
const uint16_t *s;
|
||||||
size_t len;
|
size_t len;
|
||||||
IDWriteTextLayout *layout;
|
IDWriteTextLayout *layout;
|
||||||
std::vector<backgroundFunc> *backgroundFuncs;
|
std::vector<struct drawTextBackgroundParams *> *backgroundParams;
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::hash<double> doubleHash;
|
static std::hash<double> doubleHash;
|
||||||
|
@ -255,18 +256,15 @@ static HRESULT addEffectAttributeToRange(struct foreachParams *p, size_t start,
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static backgroundFunc mkBackgroundFunc(size_t start, size_t end, double r, double g, double b, double a)
|
static void addBackgroundParams(struct foreachParams *p, size_t start, size_t end, const uiAttribute *attr)
|
||||||
{
|
{
|
||||||
return [=](uiDrawContext *c, uiDrawTextLayout *layout, double x, double y) {
|
struct drawTextBackgroundParams *params;
|
||||||
uiDrawBrush brush;
|
|
||||||
|
|
||||||
brush.Type = uiDrawBrushTypeSolid;
|
params = uiprivNew(struct drawTextBackgroundParams);
|
||||||
brush.R = r;
|
params->start = start;
|
||||||
brush.G = g;
|
params->end = end;
|
||||||
brush.B = b;
|
uiAttributeColor(attr, &(params->r), &(params->g), &(params->b), &(params->a));
|
||||||
brush.A = a;
|
p->backgroundParams->push_back(params);
|
||||||
drawTextBackground(c, x, y, layout, start, end, &brush, 0);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uiForEach processAttribute(const uiAttributedString *s, const uiAttribute *attr, size_t start, size_t end, void *data)
|
static uiForEach processAttribute(const uiAttributedString *s, const uiAttribute *attr, size_t start, size_t end, void *data)
|
||||||
|
@ -274,16 +272,12 @@ static uiForEach processAttribute(const uiAttributedString *s, const uiAttribute
|
||||||
struct foreachParams *p = (struct foreachParams *) data;
|
struct foreachParams *p = (struct foreachParams *) data;
|
||||||
DWRITE_TEXT_RANGE range;
|
DWRITE_TEXT_RANGE range;
|
||||||
WCHAR *wfamily;
|
WCHAR *wfamily;
|
||||||
size_t ostart, oend;
|
|
||||||
BOOL hasUnderline;
|
BOOL hasUnderline;
|
||||||
IDWriteTypography *dt;
|
IDWriteTypography *dt;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
ostart = start;
|
start = uiprivAttributedStringUTF8ToUTF16(s, start);
|
||||||
oend = end;
|
end = uiprivAttributedStringUTF8ToUTF16(s, end);
|
||||||
// TODO fix const correctness
|
|
||||||
start = attrstrUTF8ToUTF16((uiAttributedString *) s, start);
|
|
||||||
end = attrstrUTF8ToUTF16((uiAttributedString *) s, end);
|
|
||||||
range.startPosition = start;
|
range.startPosition = start;
|
||||||
range.length = end - start;
|
range.length = end - start;
|
||||||
switch (uiAttributeGetType(attr)) {
|
switch (uiAttributeGetType(attr)) {
|
||||||
|
@ -340,9 +334,7 @@ static uiForEach processAttribute(const uiAttributedString *s, const uiAttribute
|
||||||
logHRESULT(L"error applying effect (color, underline, or underline color) attribute", hr);
|
logHRESULT(L"error applying effect (color, underline, or underline color) attribute", hr);
|
||||||
break;
|
break;
|
||||||
case uiAttributeBackground:
|
case uiAttributeBackground:
|
||||||
p->backgroundFuncs->push_back(
|
addBackgroundParams(p, start, end, attr);
|
||||||
mkBackgroundFunc(ostart, oend,
|
|
||||||
spec->R, spec->G, spec->B, spec->A));
|
|
||||||
break;
|
break;
|
||||||
case uiAttributeTypeFeatures:
|
case uiAttributeTypeFeatures:
|
||||||
// only generate an attribute if not NULL
|
// only generate an attribute if not NULL
|
||||||
|
@ -407,7 +399,7 @@ TODO
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void uiprivAttributedStringApplyAttributesToDWriteTextLayout(uiDrawTextLayoutParams *p, IDWriteTextLayout *layout, std::vector<backgroundFunc> **backgroundFuncs)
|
void uiprivAttributedStringApplyAttributesToDWriteTextLayout(uiDrawTextLayoutParams *p, IDWriteTextLayout *layout, std::vector<struct drawTextBackgroundParams *> **backgroundParams)
|
||||||
{
|
{
|
||||||
struct foreachParams fep;
|
struct foreachParams fep;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
@ -415,10 +407,10 @@ void uiprivAttributedStringApplyAttributesToDWriteTextLayout(uiDrawTextLayoutPar
|
||||||
fep.s = attrstrUTF16(p->String);
|
fep.s = attrstrUTF16(p->String);
|
||||||
fep.len = attrstrUTF16Len(p->String);
|
fep.len = attrstrUTF16Len(p->String);
|
||||||
fep.layout = layout;
|
fep.layout = layout;
|
||||||
fep.backgroundFuncs = new std::vector<backgroundFunc>;
|
fep.backgroundParams = new std::vector<struct drawTextBackgroundParams *>;
|
||||||
uiAttributedStringForEachAttribute(p->String, processAttribute, &fep);
|
uiAttributedStringForEachAttribute(p->String, processAttribute, &fep);
|
||||||
hr = applyEffectsAttributes(&fep);
|
hr = applyEffectsAttributes(&fep);
|
||||||
if (hr != S_OK)
|
if (hr != S_OK)
|
||||||
logHRESULT(L"error applying effects attributes", hr);
|
logHRESULT(L"error applying effects attributes", hr);
|
||||||
*backgroundFuncs = fep.backgroundFuncs;
|
*backgroundParams = fep.backgroundParams;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,9 @@ extern DWRITE_FONT_STRETCH uiprivStretchToDWriteStretch(uiTextStretch s);
|
||||||
extern void uiprivFontDescriptorFromIDWriteFont(IDWriteFont *font, uiFontDescriptor *uidesc);
|
extern void uiprivFontDescriptorFromIDWriteFont(IDWriteFont *font, uiFontDescriptor *uidesc);
|
||||||
|
|
||||||
// attrstr.cpp
|
// attrstr.cpp
|
||||||
extern void uiprivAttributedStringApplyAttributesToDWriteTextLayout(uiDrawTextLayoutParams *p, IDWriteTextLayout *layout, std::vector<backgroundFunc> **backgroundFuncs);
|
// TODO
|
||||||
|
struct drawTextBackgroundParams;
|
||||||
|
extern void uiprivAttributedStringApplyAttributesToDWriteTextLayout(uiDrawTextLayoutParams *p, IDWriteTextLayout *layout, std::vector<struct drawTextBackgroundParams *> **backgroundFuncs);
|
||||||
|
|
||||||
// drawtext.cpp
|
// drawtext.cpp
|
||||||
class drawingEffectsAttr : public IUnknown {
|
class drawingEffectsAttr : public IUnknown {
|
||||||
|
@ -48,3 +50,12 @@ public:
|
||||||
HRESULT underline(uiUnderline *u);
|
HRESULT underline(uiUnderline *u);
|
||||||
HRESULT mkUnderlineBrush(ID2D1RenderTarget *rt, ID2D1SolidColorBrush **b);
|
HRESULT mkUnderlineBrush(ID2D1RenderTarget *rt, ID2D1SolidColorBrush **b);
|
||||||
};
|
};
|
||||||
|
// TODO figure out where this type should *really* go in all the headers...
|
||||||
|
struct drawTextBackgroundParams {
|
||||||
|
size_t start;
|
||||||
|
size_t end;
|
||||||
|
double r;
|
||||||
|
double g;
|
||||||
|
double b;
|
||||||
|
double a;
|
||||||
|
};
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
struct uiDrawTextLayout {
|
struct uiDrawTextLayout {
|
||||||
IDWriteTextFormat *format;
|
IDWriteTextFormat *format;
|
||||||
IDWriteTextLayout *layout;
|
IDWriteTextLayout *layout;
|
||||||
std::vector<backgroundFunc> *backgroundFuncs;
|
std::vector<struct drawTextBackgroundParams *> *backgroundParams;
|
||||||
// for converting DirectWrite indices from/to byte offsets
|
// for converting DirectWrite indices from/to byte offsets
|
||||||
size_t *u8tou16;
|
size_t *u8tou16;
|
||||||
size_t nUTF8;
|
size_t nUTF8;
|
||||||
|
@ -84,7 +84,7 @@ uiDrawTextLayout *uiDrawNewTextLayout(uiDrawTextLayoutParams *p)
|
||||||
if (hr != S_OK)
|
if (hr != S_OK)
|
||||||
logHRESULT(L"error setting IDWriteTextLayout max layout width", hr);
|
logHRESULT(L"error setting IDWriteTextLayout max layout width", hr);
|
||||||
|
|
||||||
attrstrToIDWriteTextLayoutAttrs(p, tl->layout, &(tl->backgroundFuncs));
|
attrstrToIDWriteTextLayoutAttrs(p, tl->layout, &(tl->backgroundParams));
|
||||||
|
|
||||||
// and finally copy the UTF-8/UTF-16 index conversion tables
|
// and finally copy the UTF-8/UTF-16 index conversion tables
|
||||||
tl->u8tou16 = attrstrCopyUTF8ToUTF16(p->String, &(tl->nUTF8));
|
tl->u8tou16 = attrstrCopyUTF8ToUTF16(p->String, &(tl->nUTF8));
|
||||||
|
@ -97,12 +97,15 @@ void uiDrawFreeTextLayout(uiDrawTextLayout *tl)
|
||||||
{
|
{
|
||||||
uiFree(tl->u16tou8);
|
uiFree(tl->u16tou8);
|
||||||
uiFree(tl->u8tou16);
|
uiFree(tl->u8tou16);
|
||||||
delete tl->backgroundFuncs;
|
for (auto p in *(tl->backgroundParams))
|
||||||
|
uiprivFree(p);
|
||||||
|
delete tl->backgroundParams;
|
||||||
tl->layout->Release();
|
tl->layout->Release();
|
||||||
tl->format->Release();
|
tl->format->Release();
|
||||||
uiFree(tl);
|
uiFree(tl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO make this shared code somehow
|
||||||
static HRESULT mkSolidBrush(ID2D1RenderTarget *rt, double r, double g, double b, double a, ID2D1SolidColorBrush **brush)
|
static HRESULT mkSolidBrush(ID2D1RenderTarget *rt, double r, double g, double b, double a, ID2D1SolidColorBrush **brush)
|
||||||
{
|
{
|
||||||
D2D1_BRUSH_PROPERTIES props;
|
D2D1_BRUSH_PROPERTIES props;
|
||||||
|
@ -354,6 +357,7 @@ public:
|
||||||
return E_UNEXPECTED;
|
return E_UNEXPECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO clean this function up
|
||||||
virtual HRESULT STDMETHODCALLTYPE DrawUnderline(void *clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, const DWRITE_UNDERLINE *underline, IUnknown *clientDrawingEffect)
|
virtual HRESULT STDMETHODCALLTYPE DrawUnderline(void *clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, const DWRITE_UNDERLINE *underline, IUnknown *clientDrawingEffect)
|
||||||
{
|
{
|
||||||
drawingEffectsAttr *dea = (drawingEffectsAttr *) clientDrawingEffect;
|
drawingEffectsAttr *dea = (drawingEffectsAttr *) clientDrawingEffect;
|
||||||
|
@ -468,8 +472,6 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
$$$$ TODO continue here
|
|
||||||
|
|
||||||
// TODO this ignores clipping?
|
// TODO this ignores clipping?
|
||||||
void uiDrawText(uiDrawContext *c, uiDrawTextLayout *tl, double x, double y)
|
void uiDrawText(uiDrawContext *c, uiDrawTextLayout *tl, double x, double y)
|
||||||
{
|
{
|
||||||
|
@ -478,8 +480,9 @@ void uiDrawText(uiDrawContext *c, uiDrawTextLayout *tl, double x, double y)
|
||||||
textRenderer *renderer;
|
textRenderer *renderer;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
for (const auto &f : *(tl->backgroundFuncs))
|
for (auto p : *(tl->backgroundParams)) {
|
||||||
f(c, tl, x, y);
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
// 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
|
||||||
// TODO figure out if this needs to be cleaned out
|
// TODO figure out if this needs to be cleaned out
|
||||||
|
@ -534,136 +537,22 @@ void uiDrawTextLayoutExtents(uiDrawTextLayout *tl, double *width, double *height
|
||||||
|
|
||||||
int uiDrawTextLayoutNumLines(uiDrawTextLayout *tl)
|
int uiDrawTextLayoutNumLines(uiDrawTextLayout *tl)
|
||||||
{
|
{
|
||||||
|
return 0;
|
||||||
|
#if 0
|
||||||
|
TODO
|
||||||
return tl->nLines;
|
return tl->nLines;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// DirectWrite doesn't provide a direct way to do this, so we have to do this manually
|
// DirectWrite doesn't provide a direct way to do this, so we have to do this manually
|
||||||
// TODO does that comment still apply here or to the code at the top of this file?
|
// TODO does that comment still apply here or to the code at the top of this file?
|
||||||
void uiDrawTextLayoutLineByteRange(uiDrawTextLayout *tl, int line, size_t *start, size_t *end)
|
void uiDrawTextLayoutLineByteRange(uiDrawTextLayout *tl, int line, size_t *start, size_t *end)
|
||||||
{
|
{
|
||||||
|
#if 0
|
||||||
|
TODO
|
||||||
*start = tl->lineInfo[line].startPos;
|
*start = tl->lineInfo[line].startPos;
|
||||||
*start = tl->u16tou8[*start];
|
*start = tl->u16tou8[*start];
|
||||||
*end = tl->lineInfo[line].endPos - tl->lineInfo[line].newlineCount;
|
*end = tl->lineInfo[line].endPos - tl->lineInfo[line].newlineCount;
|
||||||
*end = tl->u16tou8[*end];
|
*end = tl->u16tou8[*end];
|
||||||
}
|
#endif
|
||||||
|
|
||||||
void uiDrawTextLayoutLineGetMetrics(uiDrawTextLayout *tl, int line, uiDrawTextLayoutLineMetrics *m)
|
|
||||||
{
|
|
||||||
m->X = tl->lineInfo[line].x;
|
|
||||||
m->Y = tl->lineInfo[line].y;
|
|
||||||
m->Width = tl->lineInfo[line].width;
|
|
||||||
m->Height = tl->lineInfo[line].height;
|
|
||||||
|
|
||||||
// TODO rename tl->lineInfo[line].baseline to .baselineOffset or something of the sort to make its meaning more clear
|
|
||||||
m->BaselineY = tl->lineInfo[line].y + tl->lineInfo[line].baseline;
|
|
||||||
m->Ascent = tl->lineInfo[line].baseline;
|
|
||||||
m->Descent = tl->lineInfo[line].height - tl->lineInfo[line].baseline;
|
|
||||||
m->Leading = 0; // TODO
|
|
||||||
|
|
||||||
m->ParagraphSpacingBefore = 0; // TODO
|
|
||||||
m->LineHeightSpace = 0; // TODO
|
|
||||||
m->LineSpacing = 0; // TODO
|
|
||||||
m->ParagraphSpacing = 0; // TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
// this algorithm comes from Microsoft's PadWrite sample, following TextEditor::SetSelectionFromPoint()
|
|
||||||
// TODO go back through all of these and make sure we convert coordinates properly
|
|
||||||
// TODO same for OS X
|
|
||||||
void uiDrawTextLayoutHitTest(uiDrawTextLayout *tl, double x, double y, size_t *pos, int *line)
|
|
||||||
{
|
|
||||||
DWRITE_HIT_TEST_METRICS m;
|
|
||||||
BOOL trailing, inside;
|
|
||||||
size_t p;
|
|
||||||
UINT32 i;
|
|
||||||
HRESULT hr;
|
|
||||||
|
|
||||||
hr = tl->layout->HitTestPoint(x, y,
|
|
||||||
&trailing, &inside,
|
|
||||||
&m);
|
|
||||||
if (hr != S_OK)
|
|
||||||
logHRESULT(L"error hit-testing IDWriteTextLayout", hr);
|
|
||||||
p = m.textPosition;
|
|
||||||
// on a trailing hit, align to the nearest cluster
|
|
||||||
if (trailing) {
|
|
||||||
DWRITE_HIT_TEST_METRICS m2;
|
|
||||||
FLOAT x, y; // crashes if I skip these :/
|
|
||||||
|
|
||||||
hr = tl->layout->HitTestTextPosition(m.textPosition, trailing,
|
|
||||||
&x, &y, &m2);
|
|
||||||
if (hr != S_OK)
|
|
||||||
logHRESULT(L"error aligning trailing hit to nearest cluster", hr);
|
|
||||||
p = m2.textPosition + m2.length;
|
|
||||||
}
|
|
||||||
*pos = tl->u16tou8[p];
|
|
||||||
|
|
||||||
for (i = 0; i < tl->nLines; i++) {
|
|
||||||
double ltop, lbottom;
|
|
||||||
|
|
||||||
ltop = tl->lineInfo[i].y;
|
|
||||||
lbottom = ltop + tl->lineInfo[i].height;
|
|
||||||
// y will already >= ltop at this point since the past lbottom should == ltop
|
|
||||||
if (y < lbottom)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (i == tl->nLines)
|
|
||||||
i--;
|
|
||||||
*line = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
double uiDrawTextLayoutByteLocationInLine(uiDrawTextLayout *tl, size_t pos, int line)
|
|
||||||
{
|
|
||||||
BOOL trailing;
|
|
||||||
DWRITE_HIT_TEST_METRICS m;
|
|
||||||
FLOAT x, y;
|
|
||||||
HRESULT hr;
|
|
||||||
|
|
||||||
if (line < 0 || line >= tl->nLines)
|
|
||||||
return -1;
|
|
||||||
pos = tl->u8tou16[pos];
|
|
||||||
// note: >, not >=, because the position at endPos is valid!
|
|
||||||
if (pos < tl->lineInfo[line].startPos || pos > tl->lineInfo[line].endPos)
|
|
||||||
return -1;
|
|
||||||
// this behavior seems correct
|
|
||||||
// there's also PadWrite's TextEditor::GetCaretRect() but that requires state...
|
|
||||||
// TODO where does this fail?
|
|
||||||
trailing = FALSE;
|
|
||||||
if (pos != 0 && pos != tl->nUTF16 && pos == tl->lineInfo[line].endPos) {
|
|
||||||
pos--;
|
|
||||||
trailing = TRUE;
|
|
||||||
}
|
|
||||||
hr = tl->layout->HitTestTextPosition(pos, trailing,
|
|
||||||
&x, &y, &m);
|
|
||||||
if (hr != S_OK)
|
|
||||||
logHRESULT(L"error calling IDWriteTextLayout::HitTestTextPosition()", hr);
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
void caretDrawParams(uiDrawContext *c, double height, struct caretDrawParams *p)
|
|
||||||
{
|
|
||||||
DWORD caretWidth;
|
|
||||||
|
|
||||||
// there seems to be no defined caret color
|
|
||||||
// the best I can come up with is "inverts colors underneath" (according to https://msdn.microsoft.com/en-us/library/windows/desktop/ms648397(v=vs.85).aspx) which I have no idea how to do (TODO)
|
|
||||||
// just return black for now
|
|
||||||
p->r = 0.0;
|
|
||||||
p->g = 0.0;
|
|
||||||
p->b = 0.0;
|
|
||||||
p->a = 1.0;
|
|
||||||
|
|
||||||
if (SystemParametersInfoW(SPI_GETCARETWIDTH, 0, &caretWidth, 0) == 0)
|
|
||||||
// don't log the failure, fall back gracefully
|
|
||||||
// the instruction to use this comes from https://msdn.microsoft.com/en-us/library/windows/desktop/ms648399(v=vs.85).aspx
|
|
||||||
// and we have to assume GetSystemMetrics() always succeeds, so
|
|
||||||
caretWidth = GetSystemMetrics(SM_CXBORDER);
|
|
||||||
// TODO make this a function and split it out of areautil.cpp
|
|
||||||
{
|
|
||||||
FLOAT dpix, dpiy;
|
|
||||||
|
|
||||||
// TODO can we pass NULL for dpiy?
|
|
||||||
c->rt->GetDpi(&dpix, &dpiy);
|
|
||||||
// see https://msdn.microsoft.com/en-us/library/windows/desktop/dd756649%28v=vs.85%29.aspx (and others; search "direct2d mouse")
|
|
||||||
p->width = ((double) (caretWidth * 96)) / dpix;
|
|
||||||
}
|
|
||||||
// and there doesn't seem to be this either... (TODO check what PadWrite does?)
|
|
||||||
p->xoff = 0;
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue