diff --git a/common/attribute.c b/common/attribute.c index 4a8f0160..1289528a 100644 --- a/common/attribute.c +++ b/common/attribute.c @@ -183,6 +183,11 @@ uiAttribute *uiNewBackgroundAttribute(double r, double g, double b, double a) return at; } +void uiAttributeBackground(const uiAttribute *a, double *r, double *g, double *b, double *alpha) +{ + uiAttributeColor(a, r, g, b, alpha); +} + uiAttribute *uiNewUnderlineAttribute(uiUnderline u) { uiAttribute *a; diff --git a/ui.h b/ui.h index 40aea949..0a76bf52 100644 --- a/ui.h +++ b/ui.h @@ -668,6 +668,10 @@ _UI_EXTERN void uiAttributeColor(const uiAttribute *a, double *r, double *g, dou // error to specify an invalid color. _UI_EXTERN uiAttribute *uiNewBackgroundAttribute(double r, double g, double b, double a); +// uiAttributeBackground() returns the background color stored in a. It is an +// error to call this on a uiAttribute that does not hold a background color. +_UI_EXTERN void uiAttributeBackground(const uiAttribute *a, double *r, double *g, double *b, double *alpha); + // TODO reuse uiAttributeColor() for background colors, or make a new function... // uiUnderline specifies a type of underline to use on text. diff --git a/windows/attrstr.cpp b/windows/attrstr.cpp index 740ac43e..ef512783 100644 --- a/windows/attrstr.cpp +++ b/windows/attrstr.cpp @@ -33,6 +33,7 @@ static std::hash doubleHash; class combinedEffectsAttr : public IUnknown { ULONG refcount; uiAttribute *colorAttr; + uiAttribute *backgroundAttr; uiAttribute *underlineAttr; uiAttribute *underlineColorAttr; @@ -46,6 +47,11 @@ class combinedEffectsAttr : public IUnknown { uiprivAttributeRelease(this->colorAttr); this->colorAttr = uiprivAttributeRetain(a); break; + case uiAttributeTypeBackground: + if (this->backgroundAttr != NULL) + uiprivAttributeRelease(this->backgroundAttr); + this->backgroundAttr = uiprivAttributeRetain(a); + break; case uiAttributeTypeUnderline: if (this->underlineAttr != NULL) uiprivAttributeRelease(this->underlineAttr); @@ -74,6 +80,7 @@ public: { this->refcount = 1; this->colorAttr = NULL; + this->backgroundAttr = NULL; this->underlineAttr = NULL; this->underlineColorAttr = NULL; this->setAttribute(a); @@ -83,6 +90,8 @@ public: { if (this->colorAttr != NULL) uiprivAttributeRelease(this->colorAttr); + if (this->backgroundAttr != NULL) + uiprivAttributeRelease(this->backgroundAttr); if (this->underlineAttr != NULL) uiprivAttributeRelease(this->underlineAttr); if (this->underlineColorAttr != NULL) @@ -124,6 +133,7 @@ public: combinedEffectsAttr *b; b = new combinedEffectsAttr(this->colorAttr); + b->setAttribute(this->backgroundAttr); b->setAttribute(this->underlineAttr); b->setAttribute(this->underlineColorAttr); b->setAttribute(a); @@ -144,6 +154,13 @@ public: ret ^= doubleHash(b); ret ^= doubleHash(a); } + if (this->backgroundAttr != NULL) { + uiAttributeBackground(this->backgroundAttr, &r, &g, &b, &a); + ret ^= doubleHash(r); + ret ^= doubleHash(g); + ret ^= doubleHash(b); + ret ^= doubleHash(a); + } if (this->underlineAttr != NULL) ret ^= (size_t) uiAttributeUnderline(this->underlineAttr); if (this->underlineColorAttr != NULL) { @@ -162,6 +179,7 @@ public: if (b == NULL) return false; return combinedEffectsAttr::attrEqual(this->colorAttr, b->colorAttr) && + combinedEffectsAttr::attrEqual(this->backgroundAttr, b->backgroundAttr) && combinedEffectsAttr::attrEqual(this->underlineAttr, b->underlineAttr) && combinedEffectsAttr::attrEqual(this->underlineColorAttr, b->underlineColorAttr); } @@ -177,6 +195,10 @@ public: uiAttributeColor(this->colorAttr, &r, &g, &b, &a); dea->setColor(r, g, b, a); } + if (this->backgroundAttr != NULL) { + uiAttributeBackground(this->backgroundAttr, &r, &g, &b, &a); + dea->setBackground(r, g, b, a); + } if (this->underlineAttr != NULL) dea->setUnderline(uiAttributeUnderline(this->underlineAttr)); if (this->underlineColorAttr != NULL) { @@ -338,14 +360,15 @@ static uiForEach processAttribute(const uiAttributedString *s, const uiAttribute // and fall through to set the underline style through the drawing effect case uiAttributeTypeColor: case uiAttributeTypeUnderlineColor: + case uiAttributeTypeBackground: // TODO const-correct this properly hr = addEffectAttributeToRange(p, start, end, (uiAttribute *) attr); if (hr != S_OK) logHRESULT(L"error applying effect (color, underline, or underline color) attribute", hr); break; - case uiAttributeTypeBackground: - addBackgroundParams(p, start, end, attr); - break; + // case uiAttributeTypeBackground: + // addBackgroundParams(p, start, end, attr); + // break; case uiAttributeTypeFeatures: // only generate an attribute if not NULL // TODO do we still need to do this or not... diff --git a/windows/attrstr.hpp b/windows/attrstr.hpp index bd522ca1..15f65d2b 100644 --- a/windows/attrstr.hpp +++ b/windows/attrstr.hpp @@ -39,6 +39,12 @@ class drawingEffectsAttr : public IUnknown { double b; double a; + bool hasBackground; + double br; + double bg; + double bb; + double ba; + bool hasUnderline; uiUnderline u; @@ -56,9 +62,11 @@ public: virtual ULONG STDMETHODCALLTYPE Release(void); void setColor(double r, double g, double b, double a); + void setBackground(double r, double g, double b, double a); void setUnderline(uiUnderline u); void setUnderlineColor(double r, double g, double b, double a); HRESULT mkColorBrush(ID2D1RenderTarget *rt, ID2D1SolidColorBrush **b); + HRESULT mkBackgroundBrush(ID2D1RenderTarget *rt, ID2D1SolidColorBrush **b); HRESULT underline(uiUnderline *u); HRESULT mkUnderlineBrush(ID2D1RenderTarget *rt, ID2D1SolidColorBrush **b); }; diff --git a/windows/drawtext.cpp b/windows/drawtext.cpp index ec2ae152..cdcfd0b1 100644 --- a/windows/drawtext.cpp +++ b/windows/drawtext.cpp @@ -143,6 +143,7 @@ drawingEffectsAttr::drawingEffectsAttr(void) { this->refcount = 1; this->hasColor = false; + this->hasBackground = false; this->hasUnderline = false; this->hasUnderlineColor = false; } @@ -185,6 +186,15 @@ void drawingEffectsAttr::setColor(double r, double g, double b, double a) this->a = a; } +void drawingEffectsAttr::setBackground(double r, double g, double b, double a) +{ + this->hasBackground = true; + this->br = r; + this->bg = g; + this->bb = b; + this->ba = a; +} + void drawingEffectsAttr::setUnderline(uiUnderline u) { this->hasUnderline = true; @@ -209,6 +219,15 @@ HRESULT drawingEffectsAttr::mkColorBrush(ID2D1RenderTarget *rt, ID2D1SolidColorB return mkSolidBrush(rt, this->r, this->g, this->b, this->a, b); } +HRESULT drawingEffectsAttr::mkBackgroundBrush(ID2D1RenderTarget *rt, ID2D1SolidColorBrush **b) +{ + if (!this->hasBackground) { + *b = NULL; + return S_OK; + } + return mkSolidBrush(rt, this->br, this->bg, this->bb, this->ba, b); +} + HRESULT drawingEffectsAttr::underline(uiUnderline *u) { if (u == NULL) @@ -316,28 +335,54 @@ public: { D2D1_POINT_2F baseline; drawingEffectsAttr *dea = (drawingEffectsAttr *) clientDrawingEffect; - ID2D1SolidColorBrush *brush; + ID2D1SolidColorBrush *foregroundBrush; + ID2D1SolidColorBrush *backgroundBrush; baseline.x = baselineOriginX; baseline.y = baselineOriginY; - brush = NULL; + foregroundBrush = NULL; + backgroundBrush = NULL; if (dea != NULL) { HRESULT hr; - hr = dea->mkColorBrush(this->rt, &brush); + hr = dea->mkColorBrush(this->rt, &foregroundBrush); + if (hr != S_OK) + return hr; + + hr = dea->mkBackgroundBrush(this->rt, &backgroundBrush); if (hr != S_OK) return hr; } - if (brush == NULL) { - brush = this->black; - brush->AddRef(); + if (foregroundBrush == NULL) { + foregroundBrush = this->black; + foregroundBrush->AddRef(); + } + if (backgroundBrush != nullptr) { + // Get width of text + float totalWidth = 0; + for (UINT32 index = 0; index < glyphRun->glyphCount; index++) { + totalWidth += glyphRun->glyphAdvances[index]; + } + + // Get height of text + DWRITE_FONT_METRICS fontMetrics; + glyphRun->fontFace->GetMetrics(&fontMetrics); + float adjust = glyphRun->fontEmSize / fontMetrics.designUnitsPerEm; + float ascent = adjust * fontMetrics.ascent; + float descent = adjust * fontMetrics.descent; + D2D1_RECT_F rect = D2D1::RectF(baselineOriginX, + baselineOriginY - ascent, + baselineOriginX + totalWidth, + baselineOriginY + descent); + + this->rt->FillRectangle(rect, backgroundBrush); } this->rt->DrawGlyphRun( baseline, glyphRun, - brush, + foregroundBrush, measuringMode); - brush->Release(); + foregroundBrush->Release(); return S_OK; }