And finished implementing attributes on Windows.
This commit is contained in:
parent
b42250e3a9
commit
f2b158b529
|
@ -100,7 +100,15 @@ static void setupAttributedString(void)
|
||||||
spec.Type = uiAttributeVerticalForms;
|
spec.Type = uiAttributeVerticalForms;
|
||||||
spec.Value = 1;
|
spec.Value = 1;
|
||||||
uiAttributedStringSetAttribute(attrstr, &spec, start, end);
|
uiAttributedStringSetAttribute(attrstr, &spec, start, end);
|
||||||
uiAttributedStringAppendUnattributed(attrstr, " (which you can draw rotated for proper vertical text)");
|
uiAttributedStringAppendUnattributed(attrstr, " (which you can draw rotated for proper vertical text; for instance, ");
|
||||||
|
next = "\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86\xE3\x81\x88\xE3\x81\x8A";
|
||||||
|
start = uiAttributedStringLen(attrstr);
|
||||||
|
end = start + strlen(next);
|
||||||
|
uiAttributedStringAppendUnattributed(attrstr, next);
|
||||||
|
spec.Type = uiAttributeVerticalForms;
|
||||||
|
spec.Value = 1;
|
||||||
|
uiAttributedStringSetAttribute(attrstr, &spec, start, end);
|
||||||
|
uiAttributedStringAppendUnattributed(attrstr, ")");
|
||||||
|
|
||||||
uiAttributedStringAppendUnattributed(attrstr, ", ");
|
uiAttributedStringAppendUnattributed(attrstr, ", ");
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ struct foreachParams {
|
||||||
IDWriteTextLayout *layout;
|
IDWriteTextLayout *layout;
|
||||||
std::map<size_t, textDrawingEffect *> *effects;
|
std::map<size_t, textDrawingEffect *> *effects;
|
||||||
std::map<size_t, IDWriteTypography *> *features;
|
std::map<size_t, IDWriteTypography *> *features;
|
||||||
//TODO GPtrArray *backgroundClosures;
|
std::vector<backgroundFunc> *backgroundFuncs;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define isCodepointStart(w) ((((uint16_t) (w)) < 0xDC00) || (((uint16_t) (w)) >= 0xE000))
|
#define isCodepointStart(w) ((((uint16_t) (w)) < 0xDC00) || (((uint16_t) (w)) >= 0xE000))
|
||||||
|
@ -59,54 +59,20 @@ static void ensureFeaturesInRange(struct foreachParams *p, size_t start, size_t
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0 /* TODO */
|
static backgroundFunc mkBackgroundFunc(size_t start, size_t end, double r, double g, double b, double a)
|
||||||
struct closureParams {
|
|
||||||
size_t start;
|
|
||||||
size_t end;
|
|
||||||
double r;
|
|
||||||
double g;
|
|
||||||
double b;
|
|
||||||
double a;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void backgroundClosure(uiDrawContext *c, uiDrawTextLayout *layout, double x, double y, gpointer data)
|
|
||||||
{
|
{
|
||||||
struct closureParams *p = (struct closureParams *) data;
|
return [=](uiDrawContext *c, uiDrawTextLayout *layout, double x, double y) {
|
||||||
uiDrawBrush brush;
|
uiDrawBrush brush;
|
||||||
|
|
||||||
brush.Type = uiDrawBrushTypeSolid;
|
brush.Type = uiDrawBrushTypeSolid;
|
||||||
brush.R = p->r;
|
brush.R = r;
|
||||||
brush.G = p->g;
|
brush.G = g;
|
||||||
brush.B = p->b;
|
brush.B = b;
|
||||||
brush.A = p->a;
|
brush.A = a;
|
||||||
drawTextBackground(c, x, y, layout, p->start, p->end, &brush, 0);
|
drawTextBackground(c, x, y, layout, start, end, &brush, 0);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static void freeClosureParams(gpointer data, GClosure *closure)
|
|
||||||
{
|
|
||||||
uiFree((struct closureParams *) data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static GClosure *mkBackgroundClosure(size_t start, size_t end, double r, double g, double b, double a)
|
|
||||||
{
|
|
||||||
struct closureParams *p;
|
|
||||||
GClosure *closure;
|
|
||||||
|
|
||||||
p = uiNew(struct closureParams);
|
|
||||||
p->start = start;
|
|
||||||
p->end = end;
|
|
||||||
p->r = r;
|
|
||||||
p->g = g;
|
|
||||||
p->b = b;
|
|
||||||
p->a = a;
|
|
||||||
closure = (GClosure *) g_cclosure_new(G_CALLBACK(backgroundClosure), p, freeClosureParams);
|
|
||||||
// TODO write a specific marshaler
|
|
||||||
// TODO or drop the closure stuff entirely
|
|
||||||
g_closure_set_marshal(closure, g_cclosure_marshal_generic);
|
|
||||||
return closure;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct otParam {
|
struct otParam {
|
||||||
struct foreachParams *p;
|
struct foreachParams *p;
|
||||||
size_t start;
|
size_t start;
|
||||||
|
@ -144,10 +110,8 @@ static int processAttribute(uiAttributedString *s, uiAttributeSpec *spec, size_t
|
||||||
struct foreachParams *p = (struct foreachParams *) data;
|
struct foreachParams *p = (struct foreachParams *) data;
|
||||||
DWRITE_TEXT_RANGE range;
|
DWRITE_TEXT_RANGE range;
|
||||||
WCHAR *wfamily;
|
WCHAR *wfamily;
|
||||||
#if 0 /* TODO */
|
BOOL hasUnderline;
|
||||||
GClosure *closure;
|
uint32_t vertval;
|
||||||
PangoGravity gravity;
|
|
||||||
#endif
|
|
||||||
WCHAR *localeName;
|
WCHAR *localeName;
|
||||||
struct otParam op;
|
struct otParam op;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
@ -204,64 +168,79 @@ static int processAttribute(uiAttributedString *s, uiAttributeSpec *spec, size_t
|
||||||
t->a = spec->A;
|
t->a = spec->A;
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
#if 0
|
|
||||||
case uiAttributeBackground:
|
case uiAttributeBackground:
|
||||||
closure = mkBackgroundClosure(start, end,
|
p->backgroundFuncs->push_back(
|
||||||
spec->R, spec->G, spec->B, spec->A);
|
mkBackgroundFunc(start, end,
|
||||||
g_ptr_array_add(p->backgroundClosures, closure);
|
spec->R, spec->G, spec->B, spec->A));
|
||||||
break;
|
break;
|
||||||
case uiAttributeVerticalForms:
|
case uiAttributeVerticalForms:
|
||||||
gravity = PANGO_GRAVITY_SOUTH;
|
// LONGTERM 8 and/or 8.1 add other methods for vertical text
|
||||||
|
op.p = p;
|
||||||
|
op.start = start;
|
||||||
|
op.end = end;
|
||||||
|
vertval = 0;
|
||||||
if (spec->Value != 0)
|
if (spec->Value != 0)
|
||||||
gravity = PANGO_GRAVITY_EAST;
|
vertval = 1;
|
||||||
addattr(p, start, end,
|
doOpenType("vert", vertval, &op);
|
||||||
pango_attr_gravity_new(gravity));
|
doOpenType("vrt2", vertval, &op);
|
||||||
|
doOpenType("vkrn", vertval, &op);
|
||||||
|
doOpenType("vrtr", vertval, &op);
|
||||||
break;
|
break;
|
||||||
case uiAttributeUnderline:
|
case uiAttributeUnderline:
|
||||||
switch (spec->Value) {
|
ensureEffectsInRange(p, start, end, [=](textDrawingEffect *t) {
|
||||||
case uiDrawUnderlineStyleNone:
|
t->hasUnderline = true;
|
||||||
underline = PANGO_UNDERLINE_NONE;
|
t->u = (uiDrawUnderlineStyle) (spec->Value);
|
||||||
break;
|
});
|
||||||
case uiDrawUnderlineStyleSingle:
|
// mark that we have an underline; otherwise, DirectWrite will never call our custom renderer's DrawUnderline() method
|
||||||
underline = PANGO_UNDERLINE_SINGLE;
|
hasUnderline = FALSE;
|
||||||
break;
|
if ((uiDrawUnderlineStyle) (spec->Value) != uiDrawUnderlineStyleNone)
|
||||||
case uiDrawUnderlineStyleDouble:
|
hasUnderline = TRUE;
|
||||||
underline = PANGO_UNDERLINE_DOUBLE;
|
hr = p->layout->SetUnderline(hasUnderline, range);
|
||||||
break;
|
if (hr != S_OK)
|
||||||
case uiDrawUnderlineStyleSuggestion:
|
logHRESULT(L"error applying underline attribute", hr);
|
||||||
underline = PANGO_UNDERLINE_ERROR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
addattr(p, start, end,
|
|
||||||
pango_attr_underline_new(underline));
|
|
||||||
break;
|
break;
|
||||||
case uiAttributeUnderlineColor:
|
case uiAttributeUnderlineColor:
|
||||||
switch (spec->Value) {
|
switch (spec->Value) {
|
||||||
case uiDrawUnderlineColorCustom:
|
case uiDrawUnderlineColorCustom:
|
||||||
addattr(p, start, end,
|
ensureEffectsInRange(p, start, end, [=](textDrawingEffect *t) {
|
||||||
pango_attr_underline_color_new(
|
t->hasUnderlineColor = true;
|
||||||
(guint16) (spec->R * 65535.0),
|
t->ur = spec->R;
|
||||||
(guint16) (spec->G * 65535.0),
|
t->ug = spec->G;
|
||||||
(guint16) (spec->B * 65535.0)));
|
t->ub = spec->B;
|
||||||
|
t->ua = spec->A;
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
|
// TODO see if Microsoft has any standard colors for this
|
||||||
case uiDrawUnderlineColorSpelling:
|
case uiDrawUnderlineColorSpelling:
|
||||||
// TODO GtkTextView style property error-underline-color
|
// TODO GtkTextView style property error-underline-color
|
||||||
addattr(p, start, end,
|
ensureEffectsInRange(p, start, end, [=](textDrawingEffect *t) {
|
||||||
pango_attr_underline_color_new(65535, 0, 0));
|
t->hasUnderlineColor = true;
|
||||||
|
t->ur = 1.0;
|
||||||
|
t->ug = 0.0;
|
||||||
|
t->ub = 0.0;
|
||||||
|
t->ua = 1.0;
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
case uiDrawUnderlineColorGrammar:
|
case uiDrawUnderlineColorGrammar:
|
||||||
// TODO find a more appropriate color
|
ensureEffectsInRange(p, start, end, [=](textDrawingEffect *t) {
|
||||||
addattr(p, start, end,
|
t->hasUnderlineColor = true;
|
||||||
pango_attr_underline_color_new(0, 65535, 0));
|
t->ur = 0.0;
|
||||||
|
t->ug = 1.0;
|
||||||
|
t->ub = 0.0;
|
||||||
|
t->ua = 1.0;
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
case uiDrawUnderlineColorAuxiliary:
|
case uiDrawUnderlineColorAuxiliary:
|
||||||
// TODO find a more appropriate color
|
ensureEffectsInRange(p, start, end, [=](textDrawingEffect *t) {
|
||||||
addattr(p, start, end,
|
t->hasUnderlineColor = true;
|
||||||
pango_attr_underline_color_new(0, 0, 65535));
|
t->ur = 0.0;
|
||||||
|
t->ug = 0.0;
|
||||||
|
t->ub = 1.0;
|
||||||
|
t->ua = 1.0;
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#endif
|
|
||||||
// locale names are specified as BCP 47: https://msdn.microsoft.com/en-us/library/windows/desktop/dd373814(v=vs.85).aspx https://www.ietf.org/rfc/rfc4646.txt
|
// locale names are specified as BCP 47: https://msdn.microsoft.com/en-us/library/windows/desktop/dd373814(v=vs.85).aspx https://www.ietf.org/rfc/rfc4646.txt
|
||||||
case uiAttributeLanguage:
|
case uiAttributeLanguage:
|
||||||
localeName = toUTF16((char *) (spec->Value));
|
localeName = toUTF16((char *) (spec->Value));
|
||||||
|
@ -321,14 +300,7 @@ static void applyAndFreeFeatureAttributes(struct foreachParams *p)
|
||||||
delete p->features;
|
delete p->features;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0 /* TODO */
|
void attrstrToIDWriteTextLayoutAttrs(uiDrawTextLayoutParams *p, IDWriteTextLayout *layout, std::vector<backgroundFunc> **backgroundFuncs)
|
||||||
static void unrefClosure(gpointer data)
|
|
||||||
{
|
|
||||||
g_closure_unref((GClosure *) data);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void attrstrToIDWriteTextLayoutAttrs(uiDrawTextLayoutParams *p, IDWriteTextLayout *layout/*TODO, GPtrArray **backgroundClosures*/)
|
|
||||||
{
|
{
|
||||||
struct foreachParams fep;
|
struct foreachParams fep;
|
||||||
|
|
||||||
|
@ -336,35 +308,9 @@ void attrstrToIDWriteTextLayoutAttrs(uiDrawTextLayoutParams *p, IDWriteTextLayou
|
||||||
fep.layout = layout;
|
fep.layout = layout;
|
||||||
fep.effects = new std::map<size_t, textDrawingEffect *>;
|
fep.effects = new std::map<size_t, textDrawingEffect *>;
|
||||||
fep.features = new std::map<size_t, IDWriteTypography *>;
|
fep.features = new std::map<size_t, IDWriteTypography *>;
|
||||||
//TODO fep.backgroundClosures = g_ptr_array_new_with_free_func(unrefClosure);
|
fep.backgroundFuncs = new std::vector<backgroundFunc>;
|
||||||
uiAttributedStringForEachAttribute(p->String, processAttribute, &fep);
|
uiAttributedStringForEachAttribute(p->String, processAttribute, &fep);
|
||||||
applyAndFreeEffectsAttributes(&fep);
|
applyAndFreeEffectsAttributes(&fep);
|
||||||
applyAndFreeFeatureAttributes(&fep);
|
applyAndFreeFeatureAttributes(&fep);
|
||||||
//TODO *backgroundClosures = fep.backgroundClosures;
|
*backgroundFuncs = fep.backgroundFuncs;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
void invokeBackgroundClosure(GClosure *closure, uiDrawContext *c, uiDrawTextLayout *layout, double x, double y)
|
|
||||||
{
|
|
||||||
GValue values[4] = {
|
|
||||||
// the zero-initialization is needed for g_value_init() to work
|
|
||||||
G_VALUE_INIT,
|
|
||||||
G_VALUE_INIT,
|
|
||||||
G_VALUE_INIT,
|
|
||||||
G_VALUE_INIT,
|
|
||||||
};
|
|
||||||
|
|
||||||
g_value_init(values + 0, G_TYPE_POINTER);
|
|
||||||
g_value_set_pointer(values + 0, c);
|
|
||||||
g_value_init(values + 1, G_TYPE_POINTER);
|
|
||||||
g_value_set_pointer(values + 1, layout);
|
|
||||||
g_value_init(values + 2, G_TYPE_DOUBLE);
|
|
||||||
g_value_set_double(values + 2, x);
|
|
||||||
g_value_init(values + 3, G_TYPE_DOUBLE);
|
|
||||||
g_value_set_double(values + 3, y);
|
|
||||||
g_closure_invoke(closure,
|
|
||||||
NULL,
|
|
||||||
4, values,
|
|
||||||
NULL);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -16,7 +16,8 @@ extern ID2D1PathGeometry *pathGeometry(uiDrawPath *p);
|
||||||
extern void m2d(uiDrawMatrix *m, D2D1_MATRIX_3X2_F *d);
|
extern void m2d(uiDrawMatrix *m, D2D1_MATRIX_3X2_F *d);
|
||||||
|
|
||||||
// attrstr.cpp
|
// attrstr.cpp
|
||||||
extern void attrstrToIDWriteTextLayoutAttrs(uiDrawTextLayoutParams *p, IDWriteTextLayout *layout/*TODO, GPtrArray **backgroundClosures*/);
|
typedef std::function<void(uiDrawContext *c, uiDrawTextLayout *layout, double x, double y)> backgroundFunc;
|
||||||
|
extern void attrstrToIDWriteTextLayoutAttrs(uiDrawTextLayoutParams *p, IDWriteTextLayout *layout, std::vector<backgroundFunc> **backgroundFuncs);
|
||||||
|
|
||||||
// drawtext.cpp
|
// drawtext.cpp
|
||||||
class textDrawingEffect : public IUnknown {
|
class textDrawingEffect : public IUnknown {
|
||||||
|
|
|
@ -6,12 +6,14 @@
|
||||||
// - consider the warnings about antialiasing in the PadWrite sample
|
// - consider the warnings about antialiasing in the PadWrite sample
|
||||||
// - if that's not a problem, do we have overlapping rects in the hittest sample? I can't tell...
|
// - if that's not a problem, do we have overlapping rects in the hittest sample? I can't tell...
|
||||||
// - what happens if any nLines == 0?
|
// - what happens if any nLines == 0?
|
||||||
|
// - paragraph alignment is subject to RTL mirroring; see if it is on other platforms
|
||||||
|
|
||||||
// TODO verify our renderer is correct, especially with regards to snapping
|
// TODO verify our renderer is correct, especially with regards to snapping
|
||||||
|
|
||||||
struct uiDrawTextLayout {
|
struct uiDrawTextLayout {
|
||||||
IDWriteTextFormat *format;
|
IDWriteTextFormat *format;
|
||||||
IDWriteTextLayout *layout;
|
IDWriteTextLayout *layout;
|
||||||
|
std::vector<backgroundFunc> *backgroundFuncs;
|
||||||
UINT32 nLines;
|
UINT32 nLines;
|
||||||
struct lineInfo *lineInfo;
|
struct lineInfo *lineInfo;
|
||||||
// for converting DirectWrite indices from/to byte offsets
|
// for converting DirectWrite indices from/to byte offsets
|
||||||
|
@ -196,7 +198,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);
|
attrstrToIDWriteTextLayoutAttrs(p, tl->layout, &(tl->backgroundFuncs));
|
||||||
|
|
||||||
computeLineInfo(tl);
|
computeLineInfo(tl);
|
||||||
|
|
||||||
|
@ -214,6 +216,7 @@ void uiDrawFreeTextLayout(uiDrawTextLayout *tl)
|
||||||
uiFree(tl->u16tou8);
|
uiFree(tl->u16tou8);
|
||||||
uiFree(tl->u8tou16);
|
uiFree(tl->u8tou16);
|
||||||
uiFree(tl->lineInfo);
|
uiFree(tl->lineInfo);
|
||||||
|
delete tl->backgroundFuncs;
|
||||||
tl->layout->Release();
|
tl->layout->Release();
|
||||||
tl->format->Release();
|
tl->format->Release();
|
||||||
uiFree(tl);
|
uiFree(tl);
|
||||||
|
@ -373,17 +376,118 @@ public:
|
||||||
|
|
||||||
virtual HRESULT STDMETHODCALLTYPE DrawStrikethrough(void *clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, const DWRITE_STRIKETHROUGH *strikethrough, IUnknown *clientDrawingEffect)
|
virtual HRESULT STDMETHODCALLTYPE DrawStrikethrough(void *clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, const DWRITE_STRIKETHROUGH *strikethrough, IUnknown *clientDrawingEffect)
|
||||||
{
|
{
|
||||||
textDrawingEffect *t = (textDrawingEffect *) clientDrawingEffect;
|
// we don't support strikethrough
|
||||||
|
return E_UNEXPECTED;
|
||||||
// TODO
|
|
||||||
return S_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual HRESULT DrawUnderline(void *clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, const DWRITE_UNDERLINE *underline, IUnknown *clientDrawingEffect)
|
virtual HRESULT DrawUnderline(void *clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, const DWRITE_UNDERLINE *underline, IUnknown *clientDrawingEffect)
|
||||||
{
|
{
|
||||||
textDrawingEffect *t = (textDrawingEffect *) clientDrawingEffect;
|
textDrawingEffect *t = (textDrawingEffect *) clientDrawingEffect;
|
||||||
|
ID2D1SolidColorBrush *brush;
|
||||||
|
D2D1_RECT_F rect;
|
||||||
|
D2D1::Matrix3x2F pixeltf;
|
||||||
|
FLOAT dpix, dpiy;
|
||||||
|
D2D1_POINT_2F pt;
|
||||||
|
|
||||||
// TODO
|
if (underline == NULL)
|
||||||
|
return E_POINTER;
|
||||||
|
if (t == NULL) // we can only get here through an underline
|
||||||
|
return E_UNEXPECTED;
|
||||||
|
brush = this->black;
|
||||||
|
if (t->hasUnderlineColor) {
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
hr = mkSolidBrush(this->rt, t->ur, t->ug, t->ub, t->ua, &brush);
|
||||||
|
if (hr != S_OK)
|
||||||
|
return hr;
|
||||||
|
} else if (t->hasColor) {
|
||||||
|
// TODO formalize this rule
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
hr = mkSolidBrush(this->rt, t->r, t->g, t->b, t->a, &brush);
|
||||||
|
if (hr != S_OK)
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
rect.left = baselineOriginX;
|
||||||
|
rect.top = baselineOriginY + underline->offset;
|
||||||
|
rect.right = rect.left + underline->width;
|
||||||
|
rect.bottom = rect.top + underline->thickness;
|
||||||
|
switch (t->u) {
|
||||||
|
case uiDrawUnderlineStyleSingle:
|
||||||
|
this->rt->FillRectangle(&rect, brush);
|
||||||
|
break;
|
||||||
|
case uiDrawUnderlineStyleDouble:
|
||||||
|
// TODO do any of the matrix methods return errors?
|
||||||
|
// TODO standardize double-underline shape across platforms? wavy underline shape?
|
||||||
|
this->rt->GetTransform(&pixeltf);
|
||||||
|
this->rt->GetDpi(&dpix, &dpiy);
|
||||||
|
pixeltf = pixeltf * D2D1::Matrix3x2F::Scale(dpix / 96, dpiy / 96);
|
||||||
|
pt.x = 0;
|
||||||
|
pt.y = rect.top;
|
||||||
|
pt = pixeltf.TransformPoint(pt);
|
||||||
|
rect.top = (FLOAT) ((int) (pt.y + 0.5));
|
||||||
|
pixeltf.Invert();
|
||||||
|
pt = pixeltf.TransformPoint(pt);
|
||||||
|
rect.top = pt.y;
|
||||||
|
// first line
|
||||||
|
rect.top -= underline->thickness;
|
||||||
|
// and it seems we need to recompute this
|
||||||
|
rect.bottom = rect.top + underline->thickness;
|
||||||
|
this->rt->FillRectangle(&rect, brush);
|
||||||
|
// second line
|
||||||
|
rect.top += 2 * underline->thickness;
|
||||||
|
rect.bottom = rect.top + underline->thickness;
|
||||||
|
this->rt->FillRectangle(&rect, brush);
|
||||||
|
break;
|
||||||
|
case uiDrawUnderlineStyleSuggestion:
|
||||||
|
{ // TODO get rid of the extra block
|
||||||
|
// TODO properly clean resources on failure
|
||||||
|
// TODO use fully qualified C overloads for all methods
|
||||||
|
// TODO ensure all methods properly have errors handled
|
||||||
|
ID2D1PathGeometry *path;
|
||||||
|
ID2D1GeometrySink *sink;
|
||||||
|
double amplitude, period, xOffset, yOffset;
|
||||||
|
double t;
|
||||||
|
bool first = true;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
hr = d2dfactory->CreatePathGeometry(&path);
|
||||||
|
if (hr != S_OK)
|
||||||
|
return hr;
|
||||||
|
hr = path->Open(&sink);
|
||||||
|
if (hr != S_OK)
|
||||||
|
return hr;
|
||||||
|
amplitude = underline->thickness;
|
||||||
|
period = 5 * underline->thickness;
|
||||||
|
xOffset = baselineOriginX;
|
||||||
|
yOffset = baselineOriginY + underline->offset;
|
||||||
|
for (t = 0; t < underline->width; t++) {
|
||||||
|
double x, angle, y;
|
||||||
|
D2D1_POINT_2F pt;
|
||||||
|
|
||||||
|
x = t + xOffset;
|
||||||
|
angle = 2 * uiPi * fmod(x, period) / period;
|
||||||
|
y = amplitude * sin(angle) + yOffset;
|
||||||
|
pt.x = x;
|
||||||
|
pt.y = y;
|
||||||
|
if (first) {
|
||||||
|
sink->BeginFigure(pt, D2D1_FIGURE_BEGIN_HOLLOW);
|
||||||
|
first = false;
|
||||||
|
} else
|
||||||
|
sink->AddLine(pt);
|
||||||
|
}
|
||||||
|
sink->EndFigure(D2D1_FIGURE_END_OPEN);
|
||||||
|
hr = sink->Close();
|
||||||
|
if (hr != S_OK)
|
||||||
|
return hr;
|
||||||
|
sink->Release();
|
||||||
|
this->rt->DrawGeometry(path, brush, underline->thickness);
|
||||||
|
path->Release();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (t->hasUnderlineColor || t->hasColor)
|
||||||
|
brush->Release();
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -396,6 +500,10 @@ void uiDrawText(uiDrawContext *c, uiDrawTextLayout *tl, double x, double y)
|
||||||
textRenderer *renderer;
|
textRenderer *renderer;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
|
// TODO the "any combination of the above" one isn't drawn in the right place but the "multiple backgrounds" one is (at least for when there's a line break; TODO)
|
||||||
|
for (const auto &f : *(tl->backgroundFuncs))
|
||||||
|
f(c, tl, x, y);
|
||||||
|
|
||||||
// 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
|
||||||
black = mustMakeSolidBrush(c->rt, 0.0, 0.0, 0.0, 1.0);
|
black = mustMakeSolidBrush(c->rt, 0.0, 0.0, 0.0, 1.0);
|
||||||
|
|
Loading…
Reference in New Issue