Started migrating attrstr.cpp, using the same techniques as attrstr.m.
This commit is contained in:
parent
abc6fd2825
commit
12e97a1b29
|
@ -257,7 +257,7 @@ static void addFontAttributeToRange(struct foreachParams *p, size_t start, size_
|
||||||
else
|
else
|
||||||
cfa = [cfa copy];
|
cfa = [cfa copy];
|
||||||
[cfa addAttribute:attr];
|
[cfa addAttribute:attr];
|
||||||
// clamp effectiveRange within [start, end)
|
// clamp range within [start, end)
|
||||||
if (range.location < start) {
|
if (range.location < start) {
|
||||||
diff = start - range.location;
|
diff = start - range.location;
|
||||||
range.location = start;
|
range.location = start;
|
||||||
|
|
|
@ -1,38 +1,147 @@
|
||||||
// 12 february 2017
|
// 12 february 2017
|
||||||
#include "uipriv_windows.hpp"
|
#include "uipriv_windows.hpp"
|
||||||
#include "draw.hpp"
|
#include "attrstr.hpp"
|
||||||
|
|
||||||
// TODO this whole file needs cleanup
|
// TODO this whole file needs cleanup
|
||||||
|
|
||||||
// we need to combine color and underline style into one unit for IDWriteLayout::SetDrawingEffect()
|
// we need to collect all the background blocks and add them all at once
|
||||||
// we also need to collect all the background blocks and add them all at once
|
|
||||||
// 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::map<size_t, textDrawingEffect *> *effects;
|
|
||||||
std::vector<backgroundFunc> *backgroundFuncs;
|
std::vector<backgroundFunc> *backgroundFuncs;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void ensureEffectsInRange(struct foreachParams *p, size_t start, size_t end, std::function<void(textDrawingEffect *)> f)
|
// we need to combine color and underline style into one unit for IDWriteLayout::SetDrawingEffect()
|
||||||
{
|
// we also want to combine identical effects, which DirectWrite doesn't seem to provide a way to do
|
||||||
size_t i;
|
// we can at least try to goad it into doing so if we can deduplicate effects once they're all computed
|
||||||
size_t *key;
|
// so what we do is use this class to store in-progress effects, much like uiprivCombinedFontAttr on the OS X code
|
||||||
textDrawingEffect *t;
|
// we then deduplicate them later while converting them into a form suitable for drawing with; see applyEffectsAttributes() below
|
||||||
|
class combinedEffectsAttr : public IUnknown {
|
||||||
|
ULONG refcount;
|
||||||
|
uiAttribute *colorAttr;
|
||||||
|
uiAttribute *underlineAttr;
|
||||||
|
uiAttribute *underlineColorAttr;
|
||||||
|
|
||||||
// TODO explain why we make one for every character
|
void setAttribute(uiAttribute *a)
|
||||||
for (i = start; i < end; i++) {
|
{
|
||||||
t = (*(p->effects))[i];
|
if (a == NULL)
|
||||||
if (t != NULL) {
|
return;
|
||||||
f(t);
|
switch (uiAttributeGetType(a)) {
|
||||||
continue;
|
case uiAttributeTypeColor:
|
||||||
|
if (this->colorAttr != NULL)
|
||||||
|
uiprivAttributeRelease(this->colorAttr);
|
||||||
|
this->colorAttr = uiprivAttributeRetain(a);
|
||||||
|
break;
|
||||||
|
case uiAttributeTypeUnderline:
|
||||||
|
if (this->underlineAttr != NULL)
|
||||||
|
uiprivAttributeRelease(this->underlineAttr);
|
||||||
|
this->underlineAttr = uiprivAttributeRetain(a);
|
||||||
|
break;
|
||||||
|
case uiAttributeTypeUnderlineColor:
|
||||||
|
if (this->underlineAttr != NULL)
|
||||||
|
uiprivAttributeRelease(this->underlineAttr);
|
||||||
|
this->underlineColorAttr = uiprivAttributeRetain(a);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
t = new textDrawingEffect;
|
|
||||||
f(t);
|
|
||||||
(*(p->effects))[i] = t;
|
|
||||||
}
|
}
|
||||||
|
public:
|
||||||
|
combinedEffectsAttr(uiAttribute *a)
|
||||||
|
{
|
||||||
|
this->refcount = 1;
|
||||||
|
this->colorAttr = NULL;
|
||||||
|
this->underlineAttr = NULL;
|
||||||
|
this->underlineColorAttr = NULL;
|
||||||
|
this->setAttribute(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
~combinedEffectsAttr()
|
||||||
|
{
|
||||||
|
if (this->colorAttr != NULL)
|
||||||
|
uiprivAttributeRelease(this->colorAttr);
|
||||||
|
if (this->underlineAttr != NULL)
|
||||||
|
uiprivAttributeRelease(this->underlineAttr);
|
||||||
|
if (this->underlineColorAttr != NULL)
|
||||||
|
uiprivAttributeRelease(this->underlineColorAttr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// IUnknown
|
||||||
|
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject)
|
||||||
|
{
|
||||||
|
if (ppvObject == NULL)
|
||||||
|
return E_POINTER;
|
||||||
|
if (riid == IID_IUnknown) {
|
||||||
|
this->AddRef();
|
||||||
|
*ppvObject = this;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
*ppvObject = NULL;
|
||||||
|
return E_NOINTERFACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ULONG STDMETHODCALLTYPE AddRef(void)
|
||||||
|
{
|
||||||
|
this->refcount++;
|
||||||
|
return this->refcount;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ULONG STDMETHODCALLTYPE Release(void)
|
||||||
|
{
|
||||||
|
this->refcount--;
|
||||||
|
if (this->refcount == 0) {
|
||||||
|
delete this;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return this->refcount;
|
||||||
|
}
|
||||||
|
|
||||||
|
combinedEffectsAttr *cloneWith(uiAttribute *a)
|
||||||
|
{
|
||||||
|
combinedEffectsAttr *b;
|
||||||
|
|
||||||
|
b = new combinedEffectsAttr(this->colorAttr);
|
||||||
|
b->setAttribute(this->underlineAttr);
|
||||||
|
b->setAttribute(this->underlineColorAttr);
|
||||||
|
b->setAttribute(a);
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static HRESULT addEffectAttributeToRange(struct foreachParams *p, size_t start, size_t end, uiAttribute *attr)
|
||||||
|
{
|
||||||
|
IUnknown *u;
|
||||||
|
combinedEffectsAttr *cea;
|
||||||
|
DWRITE_TEXT_RANGE range;
|
||||||
|
size_t diff;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
while (start < end) {
|
||||||
|
hr = p->layout->GetDrawingEffect(start, &u, &range);
|
||||||
|
if (hr != S_OK)
|
||||||
|
{logHRESULT(L"HELP", hr);
|
||||||
|
return hr;
|
||||||
|
} cea = (combinedEffectsAttr *) u;
|
||||||
|
if (cea == NULL)
|
||||||
|
cea = new combinedEffectsAttr(attr);
|
||||||
|
else
|
||||||
|
cea = cea->cloneWith(attr);
|
||||||
|
// clamp range within [start, end)
|
||||||
|
if (range.startPosition < start) {
|
||||||
|
diff = start - range.startPosition;
|
||||||
|
range.startPosition = start;
|
||||||
|
range.length -= diff;
|
||||||
|
}
|
||||||
|
if ((range.startPosition + range.length) > end)
|
||||||
|
range.length = end - range.startPosition;
|
||||||
|
hr = p->layout->SetDrawingEffect(cea, range);
|
||||||
|
if (hr != S_OK)
|
||||||
|
return hr;
|
||||||
|
// TODO figure out what and when needs to be released
|
||||||
|
start += range.length;
|
||||||
|
}
|
||||||
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static backgroundFunc mkBackgroundFunc(size_t start, size_t end, double r, double g, double b, double a)
|
static backgroundFunc mkBackgroundFunc(size_t start, size_t end, double r, double g, double b, double a)
|
||||||
|
@ -49,7 +158,7 @@ static backgroundFunc mkBackgroundFunc(size_t start, size_t end, double r, doubl
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static uiForEach processAttribute(const uiAttributedString *s, const uiAttributeSpec *spec, 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)
|
||||||
{
|
{
|
||||||
struct foreachParams *p = (struct foreachParams *) data;
|
struct foreachParams *p = (struct foreachParams *) data;
|
||||||
DWRITE_TEXT_RANGE range;
|
DWRITE_TEXT_RANGE range;
|
||||||
|
@ -66,76 +175,69 @@ static uiForEach processAttribute(const uiAttributedString *s, const uiAttribute
|
||||||
end = attrstrUTF8ToUTF16((uiAttributedString *) s, end);
|
end = attrstrUTF8ToUTF16((uiAttributedString *) s, end);
|
||||||
range.startPosition = start;
|
range.startPosition = start;
|
||||||
range.length = end - start;
|
range.length = end - start;
|
||||||
switch (spec->Type) {
|
switch (uiAttributeGetType(attr)) {
|
||||||
case uiAttributeFamily:
|
case uiAttributeTypeFamily:
|
||||||
wfamily = toUTF16(spec->Family);
|
wfamily = toUTF16(uiAttributeFamily(attr));
|
||||||
hr = p->layout->SetFontFamilyName(wfamily, range);
|
hr = p->layout->SetFontFamilyName(wfamily, range);
|
||||||
if (hr != S_OK)
|
if (hr != S_OK)
|
||||||
logHRESULT(L"error applying family name attribute", hr);
|
logHRESULT(L"error applying family name attribute", hr);
|
||||||
uiFree(wfamily);
|
uiFree(wfamily);
|
||||||
break;
|
break;
|
||||||
case uiAttributeSize:
|
case uiAttributeTypeSize:
|
||||||
hr = p->layout->SetFontSize(
|
hr = p->layout->SetFontSize(
|
||||||
// TODO unify with drawtext.cpp
|
// TODO unify with fontmatch.cpp and/or attrstr.hpp
|
||||||
#define pointSizeToDWriteSize(size) (size * (96.0 / 72.0))
|
#define pointSizeToDWriteSize(size) (size * (96.0 / 72.0))
|
||||||
pointSizeToDWriteSize(spec->Double),
|
pointSizeToDWriteSize(uiAttributeSize(attr)),
|
||||||
range);
|
range);
|
||||||
if (hr != S_OK)
|
if (hr != S_OK)
|
||||||
logHRESULT(L"error applying size attribute", hr);
|
logHRESULT(L"error applying size attribute", hr);
|
||||||
break;
|
break;
|
||||||
case uiAttributeWeight:
|
case uiAttributeTypeWeight:
|
||||||
// TODO reverse the misalignment from drawtext.cpp if it is corrected
|
|
||||||
hr = p->layout->SetFontWeight(
|
hr = p->layout->SetFontWeight(
|
||||||
(DWRITE_FONT_WEIGHT) (spec->Value),
|
uiprivWeightToDWriteWeight(uiAttributeWeight(attr)),
|
||||||
range);
|
range);
|
||||||
if (hr != S_OK)
|
if (hr != S_OK)
|
||||||
logHRESULT(L"error applying weight attribute", hr);
|
logHRESULT(L"error applying weight attribute", hr);
|
||||||
break;
|
break;
|
||||||
case uiAttributeItalic:
|
case uiAttributeTypeItalic:
|
||||||
hr = p->layout->SetFontStyle(
|
hr = p->layout->SetFontStyle(
|
||||||
dwriteItalics[(uiDrawTextItalic) (spec->Value)],
|
uiprivItalicToDWriteStyle(uiAttributeItalic(attr)),
|
||||||
range);
|
range);
|
||||||
if (hr != S_OK)
|
if (hr != S_OK)
|
||||||
logHRESULT(L"error applying italic attribute", hr);
|
logHRESULT(L"error applying italic attribute", hr);
|
||||||
break;
|
break;
|
||||||
case uiAttributeStretch:
|
case uiAttributeTypeStretch:
|
||||||
hr = p->layout->SetFontStretch(
|
hr = p->layout->SetFontStretch(
|
||||||
dwriteStretches[(uiDrawTextStretch) (spec->Value)],
|
uiprivStretchToDWriteStretch(uiAttributeStretch(attr)),
|
||||||
range);
|
range);
|
||||||
if (hr != S_OK)
|
if (hr != S_OK)
|
||||||
logHRESULT(L"error applying stretch attribute", hr);
|
logHRESULT(L"error applying stretch attribute", hr);
|
||||||
break;
|
break;
|
||||||
case uiAttributeColor:
|
case uiAttributeTypeUnderline:
|
||||||
ensureEffectsInRange(p, start, end, [=](textDrawingEffect *t) {
|
// mark that we have an underline; otherwise, DirectWrite will never call our custom renderer's DrawUnderline() method
|
||||||
t->hasColor = true;
|
hasUnderline = FALSE;
|
||||||
t->r = spec->R;
|
if (uiAttributeUnderline(attr) != uiUnderlineNone)
|
||||||
t->g = spec->G;
|
hasUnderline = TRUE;
|
||||||
t->b = spec->B;
|
hr = p->layout->SetUnderline(hasUnderline, range);
|
||||||
t->a = spec->A;
|
if (hr != S_OK)
|
||||||
});
|
logHRESULT(L"error applying underline attribute", hr);
|
||||||
|
// and fall through to set the underline style through the drawing effect
|
||||||
|
case uiAttributeTypeColor:
|
||||||
|
case uiAttributeTypeUnderlineColor:
|
||||||
|
hr = addEffectAttributeToRange(p, start, end, attr);
|
||||||
|
if (hr != S_OK)
|
||||||
|
logHRESULT(L"error applying effect (color, underline, or underline color) attribute", hr);
|
||||||
break;
|
break;
|
||||||
case uiAttributeBackground:
|
case uiAttributeBackground:
|
||||||
p->backgroundFuncs->push_back(
|
p->backgroundFuncs->push_back(
|
||||||
mkBackgroundFunc(ostart, oend,
|
mkBackgroundFunc(ostart, oend,
|
||||||
spec->R, spec->G, spec->B, spec->A));
|
spec->R, spec->G, spec->B, spec->A));
|
||||||
break;
|
break;
|
||||||
case uiAttributeUnderline:
|
#if 0
|
||||||
ensureEffectsInRange(p, start, end, [=](textDrawingEffect *t) {
|
TODO
|
||||||
t->hasUnderline = true;
|
|
||||||
t->u = (uiDrawUnderlineStyle) (spec->Value);
|
|
||||||
});
|
|
||||||
// mark that we have an underline; otherwise, DirectWrite will never call our custom renderer's DrawUnderline() method
|
|
||||||
hasUnderline = FALSE;
|
|
||||||
if ((uiDrawUnderlineStyle) (spec->Value) != uiDrawUnderlineStyleNone)
|
|
||||||
hasUnderline = TRUE;
|
|
||||||
hr = p->layout->SetUnderline(hasUnderline, range);
|
|
||||||
if (hr != S_OK)
|
|
||||||
logHRESULT(L"error applying underline attribute", hr);
|
|
||||||
break;
|
|
||||||
case uiAttributeUnderlineColor:
|
|
||||||
switch (spec->Value) {
|
switch (spec->Value) {
|
||||||
case uiDrawUnderlineColorCustom:
|
case uiDrawUnderlineColorCustom:
|
||||||
ensureEffectsInRange(p, start, end, [=](textDrawingEffect *t) {
|
x(p, start, end, [=](textDrawingEffect *t) {
|
||||||
t->hasUnderlineColor = true;
|
t->hasUnderlineColor = true;
|
||||||
t->ur = spec->R;
|
t->ur = spec->R;
|
||||||
t->ug = spec->G;
|
t->ug = spec->G;
|
||||||
|
@ -146,7 +248,7 @@ static uiForEach processAttribute(const uiAttributedString *s, const uiAttribute
|
||||||
// TODO see if Microsoft has any standard colors for this
|
// 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
|
||||||
ensureEffectsInRange(p, start, end, [=](textDrawingEffect *t) {
|
x(p, start, end, [=](textDrawingEffect *t) {
|
||||||
t->hasUnderlineColor = true;
|
t->hasUnderlineColor = true;
|
||||||
t->ur = 1.0;
|
t->ur = 1.0;
|
||||||
t->ug = 0.0;
|
t->ug = 0.0;
|
||||||
|
@ -155,7 +257,7 @@ static uiForEach processAttribute(const uiAttributedString *s, const uiAttribute
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case uiDrawUnderlineColorGrammar:
|
case uiDrawUnderlineColorGrammar:
|
||||||
ensureEffectsInRange(p, start, end, [=](textDrawingEffect *t) {
|
x(p, start, end, [=](textDrawingEffect *t) {
|
||||||
t->hasUnderlineColor = true;
|
t->hasUnderlineColor = true;
|
||||||
t->ur = 0.0;
|
t->ur = 0.0;
|
||||||
t->ug = 1.0;
|
t->ug = 1.0;
|
||||||
|
@ -164,7 +266,7 @@ static uiForEach processAttribute(const uiAttributedString *s, const uiAttribute
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case uiDrawUnderlineColorAuxiliary:
|
case uiDrawUnderlineColorAuxiliary:
|
||||||
ensureEffectsInRange(p, start, end, [=](textDrawingEffect *t) {
|
x(p, start, end, [=](textDrawingEffect *t) {
|
||||||
t->hasUnderlineColor = true;
|
t->hasUnderlineColor = true;
|
||||||
t->ur = 0.0;
|
t->ur = 0.0;
|
||||||
t->ug = 0.0;
|
t->ug = 0.0;
|
||||||
|
@ -174,24 +276,25 @@ static uiForEach processAttribute(const uiAttributedString *s, const uiAttribute
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case uiAttributeFeatures:
|
#endif
|
||||||
// only generate an attribute if spec->Features is not NULL
|
case uiAttributeTypeFeatures:
|
||||||
if (spec->Features == NULL)
|
// only generate an attribute if not NULL
|
||||||
|
// TODO do we still need to do this or not...
|
||||||
|
if (uiAttributeFeatures(attr) == NULL)
|
||||||
break;
|
break;
|
||||||
dt = otfToDirectWrite(spec->Features);
|
dt = uiprivOpenTypeFeaturesToIDWriteTypography(uiAttributeFeatures(attr));
|
||||||
hr = p->layout->SetTypography(dt, range);
|
hr = p->layout->SetTypography(dt, range);
|
||||||
if (hr != S_OK)
|
if (hr != S_OK)
|
||||||
logHRESULT(L"error applying features attribute", hr);
|
logHRESULT(L"error applying features attribute", hr);
|
||||||
dt->Release();
|
dt->Release();
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
// TODO complain
|
|
||||||
;
|
|
||||||
}
|
}
|
||||||
return uiForEachContinue;
|
return uiForEachContinue;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void applyAndFreeEffectsAttributes(struct foreachParams *p)
|
$$$$TODO CONTINUE HERE
|
||||||
|
|
||||||
|
static void applyEffectsAttributes(struct foreachParams *p)
|
||||||
{
|
{
|
||||||
size_t i, n;
|
size_t i, n;
|
||||||
textDrawingEffect *effect, *effectb;
|
textDrawingEffect *effect, *effectb;
|
Loading…
Reference in New Issue